I am using a method as found here with chartJS to input dates that are missing from a JSON response.
jsonObj["result"]["data"] is output from the initial JSON response:
{
"action": "data_link_day",
"result": {
"url_ending": "0",
"data": [{
"x": "2018-03-12",
"y": 3
}, {
"x": "2018-03-16",
"y": 5
}]
}
}
Inside the drawChart function, I need to separate the x/y values as graphData = y (number) and labels = x (date) by targeting them individually. I tried to do jsonObj["result"]["data"].x but obviously not correct.
function drawChart(jsonObj) {
var graphData = jsonObj["result"]["data"],
labels = jsonObj["result"]["data"];
for (var i = 0; i < labels.length; i++) {
//make sure we are not checking the last date in the labels array
if (i + 1 < labels.length) {
var date1 = moment(labels[i], "YYYY-MM-DD");
var date2 = moment(labels[i + 1], "YYYY-MM-DD");
//if the current date +1 is not the same as it's next neighbor we have to add in a new one
if (!date1.add(1, "days").isSame(date2)) {
//add the label
labels.splice(i + 1, 0, date1.format("YYYY-MM-DD"));
//add the data
graphData.splice(i + 1, 0, 0);
}
}
}
...
}
You can use the following code to separate your data into X and Y arrays:
let data = jsonObj.result.data;
let dataX = data.map(data => data.x);
let dataY = data.map(data => data.y);
Demo:
const json = `
{
"action": "data_link_day",
"result": {
"url_ending": "0",
"data": [{
"x": "2018-03-12",
"y": 3
}, {
"x": "2018-03-16",
"y": 5
}]
}
}`;
const input = JSON.parse(json);
let data = input.result.data;
let dataX = data.map(data => data.x);
let dataY = data.map(data => data.y);
console.log(dataX);
console.log(dataY);
Related
I'm struggling with creating correct data template for my chart. I want it to create template for last 12 months with actual month. For example if I want to have last 12 months i should have data template looking like this:
[{id: BAD,
data: [
{
x: "11",
y: 0
},
{
x: "12",
y: 0
},
{
x: "1",
y: 0
},
...
]},
{id: GOOD,
data: [
{
x: "11",
y: 0
},
{
x: "12",
y: 0
},
{
x: "1",
y: 0
},
...
]},
...
]
It is not that simple because I don't know what to do when month increases to 12 because then its just keeps increasing value of "x" which stands for month and thus I don't know how should I implement that.
What i tried to do was just this. I have no other clues how to get this any hints how I can get that?
const NUMBER_OF_MONTHS = 12;
const getFirstMonth = (date, numOfMonths) => {
date.setMonth(date.getMonth() - numOfMonths);
return date.getMonth();
}
const createDataTemplate = () => {
const template = [];
const firstMonth = getFirstMonth(new Date(), NUMBER_OF_MONTHS)
for (let i = 0; i < RATINGS.length; i++) {
template.push({
'id': RATINGS[i],
'data': []
})
for (let j = 1; j <= NUMBER_OF_MONTHS; j++) {
template[i].data.push({
'x': `${firstMonth + j}`,
'y': 0
})
}
}
return template;
}
I solved it like this, generating an array of the next 12 months/year. Which you can then use to loop over and add to you data
const NUMBER_OF_MONTHS = 12;
const getNextTwelveMonths = () => {
const currentMonth = new Date().getMonth();
// create array with the months until the currentMonth
const months = new Array(currentMonth).fill(null).map((_, i) => i + 1);
// add the last x months to the begin of the array
for (let i = NUMBER_OF_MONTHS; i > currentMonth; i--) {
months.unshift(i);
}
return months;
};
const createDataTemplate = () => {
const template = [];
for (let i = 0; i < RATINGS.length; i++) {
template.push({
id: RATINGS[i],
data: [],
});
const nextMonths = getNextTwelveMonths();
for (let j = 0; j < nextMonths.length; j++) {
template[i].data.push({
x: `${nextMonths[j]}`,
y: 0,
});
}
}
return template;
};
In my project, I need to classify an array and convert it to another type of array.
The difficulty I encountered was that there was no way to use concise and efficient execution. The following are my input and output:
const input = [{
"type": 1,
"color": "Red(268)"
},
{
"type": 1,
"color": "Blue(583)"
},
{
"type": 2,
"color": "Blue(185)"
},
{
"type": 4,
"color": "Red(326)"
},
{
"type": 4,
"color": "Blue(967)"
},
{
"type": 5,
"color": "Red(863)"
}
]
const output = [
"Type 1: Red(268), Blue(583)",
"Type 2: Blue(185)",
"Type 4: Red(326), Blue(967)",
"Type 5: Red(863)"
]
The following is my method. I use the set() to find out the number of types, and then use for loop to convert it into a string and push into the array, but it cannot be executed continuously, so my function cannot get the correct result, and it is not efficient.
this.ty = 1;
this.result = [];
const set = new Set();
const length = input.filter(item => !set.has(item.type) ? set.add(item.type) : false).length + 1;
for (let i = 1; i < length; i++) {
const temp = input.filter(x => {
return x.type === ty;
})
if (temp.length < 2) {
this.result.push(`Type ${ty}: ${temp[0].color}`);
} else {
this.result.push(`Type ${ty}: ${temp[0].color}, ${temp[1].color}`);
}
this.ty = i + 1;
}
This problem has troubled me for a long time. Can someone provide an easier way to convert this array? Thank you for your help.
const input = [{
"type": 1,
"color": "Red(268)"
},
{
"type": 1,
"color": "Blue(583)"
},
{
"type": 2,
"color": "Blue(185)"
},
{
"type": 4,
"color": "Red(326)"
},
{
"type": 4,
"color": "Blue(967)"
},
{
"type": 5,
"color": "Red(863)"
}
]
console.log('input', input);
this.ty = 1;
this.result = [];
const set = new Set();
const length = input.filter(item => !set.has(item.type) ? set.add(item.type) : false).length + 1;
for (let i = 1; i < length; i++) {
const temp = input.filter(x => {
return x.type === ty;
})
if (temp.length < 2) {
this.result.push(`Type ${ty}: ${temp[0].color}`);
} else {
this.result.push(`Type ${ty}: ${temp[0].color}, ${temp[1].color}`);
}
this.ty = i + 1;
}
console.log('result', this.result);
// output
/* const output = [
"Type 1: Red(268), Blue(583)",
"Type 2: Blue(185)",
"Type 4: Red(326), Blue(967)",
"Type 5: Red(863)"
] */
You can use the Array.reduce() function to iterate your array and construct a new object.
const input = [{
"type": 1,
"color": "Red(268)"
},
{
"type": 1,
"color": "Blue(583)"
},
{
"type": 2,
"color": "Blue(185)"
},
{
"type": 4,
"color": "Red(326)"
},
{
"type": 4,
"color": "Blue(967)"
},
{
"type": 5,
"color": "Red(863)"
}
];
const mappedInput = input.reduce((grouped, {
type,
color
}) => {
if (!grouped.hasOwnProperty(type)) {
grouped[type] = `Type ${type}: ${color}`;
} else {
grouped[type] += `, ${color}`;
}
return grouped;
}, {});
console.log(Object.values(mappedInput));
We use an object to provide efficient key lookup and at the end, retrieve just the array of strings that we need.
You could reduce over the array to create an object that uses the type as a key and an array as a value, pushing new instances into the array with each iteration.
Then map over the Object.entries to produce a new array of strings.
const input = [{"type":1,"color":"Red(268)"},{"type":1,"color":"Blue(583)"},{"type":2,"color":"Blue(185)"},{"type":4,"color":"Red(326)"},{"type":4,"color":"Blue(967)"},{"type":5,"color":"Red(863)"}];
const out = input.reduce((acc, c) => {
const [ key, value ] = Object.values(c);
acc[key] = acc[key] || [];
acc[key].push(value);
return acc;
}, {});
const result = Object.entries(out).map(([key, value]) => {
return `Type ${key}: ${value.join(', ')}`
});
console.log(result);
Here's a simple, functional solution:
// Get list of unique input types
const types = Array.from(new Set(input.map(x => x.type)));
// Map over unique types, filter for matching inputs, yield all colors
const output = types.map(type => `Type ${type}: ${input.filter(x => x.type == type).map(x => x.color).join(', ')}`);
This is the Dynamic Solution for your problem.
let output = input.map(d => {
let k = Object.keys(d);
let v = Object.values(d)
let text = '';
for (var i in k) {
text += `${k[i]}: ${v[i]}, `
}
text = text.substring(0, text.length - 1);
return text })
I'm using http://d3pie.org/ to generate a pie chart for my web application. Now, I want to manipulate the value appearing on my chart. Currently, the values appearing have more than 4 decimals. For example, 10.35234234234 . I just want 10.3523 to appear.
Here's my current code:
function drawPie(id,from,to,C,formula){
var subArray = getSubArray(C.table,from,to);
if(Object.keys(subArray).length){
var partials = createPartials(subArray, C.attributes);
//console.log("partials -> ",partials);
formula = formula.slice(1,-1);
//console.log("formula ->" , formula);
formula = formula.split(",");
//console.log("formula ->" , formula);
var cloneFormula = formula.slice();
for( var i in partials){
if(i.substr(0,1) == "$"){
for(var j = 0; j< formula.length; j++){
formula[j] = replaceFunction(i,formula[j],partials[i]);
}
}
}
//console.log("replaced formula ->" , formula);
var data = [];
var isEmpty = true;
for(var j = 0; j< formula.length; j++){
var label = cloneFormula[j].split(/(?=[-+*\/])/)[0].split(".")[1];
var temp = {};
try{
temp.value = eval(formula[j]);
}catch(err){
temp.value = 0;
}
temp.label = partials[label + ".name"];
temp.color = partials[label + ".color"];
data.push(temp);
if(temp.value != 0){
isEmpty = false;
}
}
if(isEmpty){
return true;
}
//console.log("data ->" , data);
var pie = new d3pie(id, {
"size": {
"canvasHeight": 400,
"canvasWidth": 800, //see defect 1418
"pieOuterRadius": "88%"
},
"data": {
"content": data
},
"labels": {
"outer": {
"pieDistance": 100
},
"inner": {
"format": "value"
},
"mainLabel": {
"font": "verdana"
},
"percentage": {
"color": "#e1e1e1",
"font": "verdana",
"decimalPlaces": 0
},
"value": {
"color": "#e1e1e1",
"font": "verdana"
},
"lines": {
"enabled": true,
"color": "#cccccc"
},
"truncation": {
"enabled": true
}
},
"effects": {
"pullOutSegmentOnClick": {
"effect": "linear",
"speed": 400,
"size": 8
}
}
});
return false;
}
return true;
}
Can you help me try to modify the texts appearing inside my pie chart?
use the following to strip the number and then round it.
function strip(number) {
return (parseFloat(number).toPrecision(4));
}
example
var number = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679
function strip(number) {
return (parseFloat(number).toPrecision(6));
}
window.alert(strip(number));
For the generator you are using, go to the labels section, and under the label styles / Settings you will find the option for decimal places for percentage values. Enter the number of decimal places you would like to limit the labels to.
This is the JSON I'm trying to create programmatically:
{
"sensors": [{
"x": 342,
"y": 213,
"id": 4
}, {
"x": 642,
"y": 913,
"id": 3
}, {
"x": 452,
"y": 113,
"id": 2
}]
}
I have to iterate through all elements with a specific class to retrieve the data for the json:
$(".marker").each(function()
{
var x = $(this).attr("data-x");
var y = $(this).attr("data-y");
var id = $(this).attr("data-id");
});
How could I create the json object to be like I described?
Try this
var json = {"sensors":[]};
$(".marker").each(function()
{
var x = $(this).attr("data-x");
var y = $(this).attr("data-y");
var id = $(this).attr("data-id");
json.sensors.push({"x":x, "y":y,"id":id});
});
Look JSON.parse method on MDN ou MSDN
var jsontext = '{"firstname":"Jesper","surname":"Aaberg","phone":["555-0100","555-0120"]}';
var contact = JSON.parse(jsontext);
document.write(contact.surname + ", " + contact.firstname);
// Output: Aaberg, Jesper
I am working on application which I need to do grouping of different sets of javascript object and those will be based on month,day and year.
For day I am doing like below
var calculateByDay = function(inputList){
var outPutList = [];
var result = {}
var item = null, key = null;
for(i=0; c<inputList.length; i++) {
item=inputList[c];
key = Object.keys(item)[0];
item=item[key];
if(!result[key]) {
result[key] = item;
}
else {
result[key] += item;
}
for (r in result)
{
var docs = {};
docs["date"] = r;
docs["amount"] = result[r];
outPutList.push(docs);
}
}
return outPutList;
}
How can I improve above code and use it for month and year calculation also?
I went thorough underscore.js and it has a groupBy method. but seems not fits with my requirement.
I want to group by months and year also,
for
var inputList = [{"2012-12-02T00:00": 2000}, {"2013-01-01T00:00": 1200},{"2013-02-02T00:00": 550}, {"2013-02-02T00:00": 1000}];
The output should be:
Monthly :
[{"December 2012": 2000}, {"January 2013": 1200},{"February 2013": 1550}];
Yearly
[{"year 2012": 2000}, {"year 2013": 2750}];
And it seems I need to this kind of map,reduce approach for large data(array sets), is there any other library or practices I can do to make the code solid?
Thanks in advance.
Given a slightly different structure of data:
var data = [{
"date": "2011-12-02T00:00",
"value": 1000
}, {
"date": "2013-03-02T00:00",
"value": 1000
}, {
"date": "2013-03-02T00:00",
"value": 500
}, {
"date": "2012-12-02T00:00",
"value": 200
}, {
"date": "2013-04-02T00:00",
"value": 200
}, {
"date": "2013-04-02T00:00",
"value": 500
}, {
"date": "2013-03-02T00:00",
"value": 500
}, {
"date": "2013-04-12T00:00",
"value": 1000
}, {
"date": "2012-11-02T00:00",
"value": 600
}];
You could use underscore:
var grouped = _.groupBy(data, function(item) {
return item.date;
});
var groupedByYear = _.groupBy(data, function(item) {
return item.date.substring(0,4);
});
var groupedByMonth = _.groupBy(data, function(item) {
return item.date.substring(0,7);
});
console.log(groupedByYear);
See related answer: Javascript - underscorejs map reduce groupby based on date
Please see if the following refactor is useful for you
http://jsfiddle.net/wkUJC/
var dates = [{"2012-12-02T00:00": 2000}, {"2013-01-01T00:00": 1200},{"2013-02-02T00:00": 550}, {"2013-02-02T00:00": 1000}];
function calc(dates) {
var response = {};
dates.forEach(function(d){
for (var k in d) {
var _ = k.split("-");
var year = _[0]
var month = _[1]
if (!response[year]) response[year] = {total: 0}
response[year][month] = response[year][month] ? response[year][month]+d[k] : d[k]
response[year].total+= d[k]
}
});
console.log(response);
return response;
}
calc(dates);