How to use a javascript map functionality for multiple values - javascript

I have sensor data in the following format:
zdata =
{ "data": [
{
"timestamp": 10,
"sensor_id": 1,
"temp": 14.5,
"hum":13,
"light":11,
},
{
"timestamp": 20,
"sensor_id": 1,
"temp": 18,
"hum":12,
"light":20,
},
{
"timestamp": 5,
"sensor_id": 2,
"temp": 24.5,
"hum":12,
"light":15,
},
{
"timestamp": 20,
"sensor_id": 2,
"temp": 29.5,
"hum":12,
"light":2,
}
]
};
I using Chart js to display the sensor readings. The data I am using is coming from two different sensor_ids (sensor 1 and sensor 2), that may not necessarily have the same timestamps. Each sensor sends readings for light, humidity, and temperature. I need to plot the readings for both sensors on a graph against the time, so would need the above data like so:
Timestamps = [5, 10, 20]
Sensors = [1,2]
tempValueArray = [ [ '', 14.5, 18 ], [ 24.5, '', 29.5 ] ]
humidityValueArray = [ [ '', 13, 18 ], [ 24.5, '', 29.5 ] ]
lightValueArray = [ [ '', 13, 12 ], [ 12, '', 12 ] ]
Initially, I was just using a temperature sensor using a time map and the code posted as the answer here: Organising object data by timestep, so as to chart multiple sensor readings against time using Chart JS
However, I have updated the code here to loop through each type of reading (i.e. temp, hum, light):
var sensorNames = ['temp','hum','light'];
var allSensors = [];
for (i = 0; i < sensorNames.length; i++) {
let {sensors ,...sensorTimeMap} = zdata.data.reduce((acc,val) => {
sensorTypes = [val.temp, val.hum, val.light];
if(!acc[val.timestamp]) acc[val.timestamp] = {};
acc[val.timestamp][val.sensor_id] = sensorTypes[i];
if(!acc.sensors.includes(val.sensor_id))
acc.sensors.push(val.sensor_id)
return acc;
},{sensors:[]}); // get available sensors and create a timeStamp map for future iterations
let timestamp = Object.keys(sensorTimeMap);
allSensors.push(sensors.map(sensor => (Object.values(sensorTimeMap).map(obj => obj[sensor] || ''))));
};
console.log(sensors);
console.log(allSensors);
Is there a more efficient way to do this loop? I am new to javascript so am unsure how to add a number of readings in the map and save each to a new array.

Related

How to use Highcharts React to create chart with multiple lines for same XAxis?

I have a dataset containing a date value, and 3 other values. For example:
{
"minimum": "71",
"maximum": "74",
"meanAverage": "72",
"dateTime": "2018-03-28T13:46:00"
},
{
"minimum": "57",
"maximum": "87",
"meanAverage": "71",
"dateTime": "2018-03-28T18:00:01"
},
I'd like to create a chart using react highcharts with the dates in the x axis, and then 3 lines on the y axis showing the corresponding 3 values for all the dates.
So far I thought using 3 different arrays to pass to series.data. Each array would have the x value (date) and then the y value. For the minimuns, it would be:
['2018-03-28T13:46:00', '71']
['2018-03-28T18:00:01', '57']
...
And in the options object, I would have something like:
series: [
{
data: minimuns
},
{
data: maximuns
},
{
data: meanAverages
},
]
But this isn't working and I'm having some trouble finding the info to correctly do this. Any help?
You need to parse the json object into a suitable data format.
See the docs for accepted data formats:
https://api.highcharts.com/highcharts/series.line.data
Notice, that y value should be a number.
The example config:
const json = '[{"minimum": 71, "maximum": 74, "meanAverage": 72, "dateTime": "2018-03-28T13:46:00"}, {"minimum": 57,"maximum": 87, "meanAverage": 71, "dateTime": "2018-03-28T18:00:01"}]',
parsed = JSON.parse(json);
const minimum = [];
parsed.forEach(data => {
minimum.push([new Date(data.dateTime).getTime(), data.minimum])
})
const maximum = [];
parsed.forEach(data => {
maximum.push([new Date(data.dateTime).getTime(), data.maximum])
})
const meanAverage = [];
parsed.forEach(data => {
meanAverage.push([new Date(data.dateTime).getTime(), data.meanAverage])
})
Then you can use your data arrays as you expected:
series: [{
data: minimum
},
{
data: maximum
},
{
data: meanAverage
}
]
Demo:
https://jsfiddle.net/BlackLabel/2ncb83eh/

Plotly.js multiple subplots not working as expected

Edit to add: Looking for the "plotly.js" way to do this. This "small multiple" visualization should have some "plotly.js" solution out there but haven't found it yet.
I am using an array (example element below) to populate traces for plotly.js multiple subplots per their multiple-subplots example
[{
"key": "Ontario|Toronto",
"values": [{
"key": "2020-01-25",
"value": 1
}, {
"key": "2020-01-27",
"value": 1
}, {
"key": "2020-05-12",
"value": 218
}, {
"key": "2020-05-13",
"value": 169
}]
}, {
etc
}]
The array has 94 elements which contain info needed to create each trace. This would result in 94 subplots, one per trace. This plotly.js visualization could also be called "small multiples".
I am creating the traces dynamically and populating subplot definitions in a loop using code below:
// create chart data
var traces = [];
var rowCount = (caseRegionByDate.length / 2).toFixed()
for (var i=0; i<caseRegionByDate.length; i++) {
//console.log(caseRegionByDate[i]['key']);
var trace = {};
var x = [];
var y = [];
for (var j=0; j<caseRegionByDate[i]['values'].length; j++) {
//console.log(caseRegionByDate[i]['values'][j]['key']);
x.push(caseRegionByDate[i]['values'][j]['key']);
y.push(caseRegionByDate[i]['values'][j]['value']);
}
// create trace i
trace = {
"x":x,
"y":y,
"xaxis":"x"+i,
"yaxis":"y"+i,
"type":"scatter"
}
// push trace to traces
traces.push(trace);
}
console.log(JSON.stringify(traces));
var layout = {
grid: {rows: rowCount, columns: 2, pattern: 'independent'},
};
Plotly.newPlot('multiple_charts', traces, layout);
This creates the traces variable populated by each trace that looks like example below. It looks correct:
[{
"x": ["2020-03-16", "2020-03-23", "2020-03-24", "2020-03-25", "2020-03-31", "2020-04-01", "2020-04-02", "2020-04-03", "2020-04-06", "2020-04-07", "2020-04-08", "2020-04-09", "2020-04-10", "2020-04-11", "2020-04-13", "2020-04-14", "2020-04-15", "2020-04-16", "2020-04-17", "2020-04-18", "2020-04-21", "2020-04-22", "2020-04-23", "2020-04-24", "2020-04-25", "2020-04-26", "2020-04-27", "2020-04-28", "2020-04-29", "2020-04-30", "2020-05-01", "2020-05-02", "2020-05-03", "2020-05-04", "2020-05-05", "2020-05-06", "2020-05-07", "2020-05-08", "2020-05-09", "2020-05-10", "2020-05-11", "2020-05-12", "2020-05-13"],
"y": [1, 1, 1, 1, 9, 35, 3, 16, 33, 13, 9, 5, 5, 1, 22, 3, 4, 7, 19, 4, 7, 2, 18, 11, 9, 9, 9, 13, 1, 3, 7, 18, 5, 4, 4, 5, 3, 1, 2, 2, 3, 1, 2],
"xaxis": "x0",
"yaxis": "y0",
"type": "scatter"
}, {
"x": ["2020-03-14", "2020-03-26", "2020-03-27", "2020-04-02", "2020-04-06", "2020-04-09", "2020-04-14", "2020-04-17", "2020-04-18", "2020-04-20", "2020-04-22"],
"y": [1, 1, 1, 2, 2, 3, 1, 1, 1, 2, 1],
"xaxis": "x1",
"yaxis": "y1",
"type": "scatter"
},
etc
]
However, the result appears to be one row with two columns that have all of the traces (there are 94 traces) squashed into them. Here is screenshot.
Any ideas what is happening? I expect to have 48 rows with 2 columns, one subplot per trace.
The only difference from the multiple subplots example is that my xaxis have date strings instead of numbers. Everything else is same.
The subplots are actually being created in 3 x rowCount grid. However they are all squashed vertically as in screenshot.
It appears that a chart's default height and width dimensions, where they are not explicitly defined using layout.height, are what is shown in my screenshot eg too small for 94 subplots.
The quick fix is to simply increase the chart's layout.height size. Then all subplots are visible. Dynamically calculating layout.height, in spirit of Juan's suggestion, relative to number of rows works well.
Apparently it is also possible to set each subplot's x and y domain attributes to resize subplots which will also give desired results.

How to push data to same array in java script in several time in same function?

I'm getting values from database in json structure. and i want to display them in table in javascript.Data come in following format.
"free_issue": [
{
"product_id": [14, 15, 16],
"free_product_ids": [15],
"structure": [
{
"req_qty": 10,
"free_qty": 2
},
{
"req_qty": 20,
"free_qty": 5
},
{
"req_qty": 50,
"free_qty": 10
}
]
}
From those data i want to push this data to table row. data in same row with 4 columns.I used array push method to push data. but i'm unable to get it in correct way.
in here all the data should in one row.
Please help me to do this.......
have You tried to do like this?
"free_issue": [
{
"product_id": [14, 15, 16],
"free_product_ids": [null, 15, null],
"structure": [
{
"req_qty": 10,
"free_qty": 2
},
{
"req_qty": 20,
"free_qty": 5
},
{
"req_qty": 50,
"free_qty": 10
}
]
}
I mean You've to generate these arrays before and then attach these arrays to fields of object. Notice: all of arrays must be same length to be able aligned to correct rows.

generate javascript object with some conditions

I have object like below.
{
"lastViewTime": "May 09, 2013 08:36:09 PM GMT",
"browser":
{
"Firefox": 200,
"Others": 800,
"Safari": 0,
"Chrome": 522,
"IE": 45
}
}
from this I want to generate like below(I need to pass this in this manner only to some plugin the [] are important)
var browserData = [
['Firefox', data.browser.Firefox],
['IE', data.browser.IE],
['Safari', data.browser.Safari],
['Others', data.browser.Others],
['Chrome', data.browser.Chrome]
];
Now I want to add this key value pairs to browserData only if data.browser.Firefox means those values are > 0.
for this I need to have a for loop . but i m not able to understand how I can make this kind of object. if I m making an array and pushing int to that key value pairs it is not giving me this kind of structure.
If some one can guide me in this it will be great.
var browserData = [];
for(var i in data.browser){
if(data.browser.hasOwnProperty(i) {
browserData.push([i, data.browser[i]]);
}
}

Javascript nested array transformation

I'm trying to get my head around Javascript array functions. I have a nested array like this, where every row covers the same time period:
[{
"category": "fruit",
"variety": "apple",
"data": [{
"day": 1,
"units": 2
}, {"day": 2,
"units": 4
}]
},{
"category": "fruit",
"variety": "orange",
"data": [{
"day": 1,
"units": 3
}, {"day": 2,
"units": 5
}]
},{
"category": "veg",
"variety": "tomato",
"data": [{
"day": 1,
"units": 4
}, {"day": 2,
"units": 2
}]
}]
I would like to sum the units by day by category, to get an array like this:
[{
"category": "fruit",
"data": [{
"day": 1,
"units": 5
}, {"day": 2,
"units": 9
}]
},{
"category": "veg",
"data": [{
"day": 1,
"units": 4
}, {"day": 2,
"units": 2
}]
}]
I've been tackling this through long looping if statements, and making a bit of a hash of it. Can you see an elegant way to solve this?
Many thanks!
The solution is pretty obvious: Loop through the array, and store the data in a key-value pair. Then, loop through the has, and construct the resulting array using Array.prototype.map. Finally, if you want a nicely formatted JSON-string, use JSON.stringify(result, null, 4);, where 4 is the number of spaced for pretty formatting.
Demo: http://jsfiddle.net/jde6S/
var list = [ ... ];
var hash = {};
for (var i=0; i<list.length; i++) {
var obj = list[i];
// This part makes sure that hash looks like {fruit:[], veg: []}
var hashObjCat = hash[obj.category];
if (!hashObjCat) {
hashObjCat = hash[obj.category] = {};
}
// This part populates the hash hashObjCat with day-unit pairs
for (var j=0; j<obj.data.length; j++) {
var data = obj.data[j];
if (hashObjCat[data.day]) hashObjCat[data.day] += data.units;
else hashObjCat[data.day] = data.units;
}
}
// Now, we hash looks like {fruit: {1:5, 2:9} }
// Construct desired object
var result = Object.keys(hash).map(function(category) {
// Initial object
var obj = {category: category, data:[]};
var dayData = Object.keys(hash[category]);
// This part adds day+units dicts to the data array
for (var i=0; i<dayData.length; i++) {
var day = dayData[i];
var units = hash[category][day];
obj.data.push({day: day, units: units});
}
return obj;
});
// Test:
console.log(JSON.stringify(result, null, 4));
reduce the array to an object (See #RobW's answer on how to do that with loops):
var data = [...] // your input
// Iterate the data with reduce...
var sumsbycategory = data.reduce(function(map, fruit) {
var cat = fruit.category;
// set an property to an object, iterating the days array...
map[cat] = fruit.data.reduce(function(sums, day) {
var d = day.day;
// set or update the units for this day
sums[d] = (sums[d] || 0) + day.units;
return sums; // into the next iteration
}, map[cat] || {}) // ...passing in the already existing map for this cat or a new one
return map; // into the next iteration
}, {}); // ...passing in an empty object
Now we have the following format:
{"fruit":{"1":5,"2":9},"veg":{"1":4,"2":2}}
...which I think is much easier to handle, but lets build your array:
var result = []; // init array
for (var cat in sumsbycategory) { // loop over categories
var data = []; // init array
// add category object:
result.push({category:cat, data:data});
for (var day in sumsbycategory[cat]) // loop over days in category
// add day object
data.push({day:day, units:sumsbycategory[cat][day]});
}
But, wait! An object has no order, and it could happen that day2 comes before days1 in the result array (which might break your appplication?) So, you could use map on the keys of that object which also can be sorted before, to generate the array in one clean-looking expression:
var result = Object.keys(sumsbycategory).map(function(cat) {
return {
category: cat,
data: Object.keys(sumsbycategory[cat])
.sort(function numbercompare(a,b){ return a-b; })
.map(function(day) {
return {
day: day,
units: sumsbycategory[cat][day]
};
})
};
});
result:
[{
"category": "fruit",
"data": [{"day":"1","units":5},{"day":"2","units":9}]
},{
"category": "veg",
"data": [{"day":"1","units":4},{"day":"2","units":2}]
}]
(Demo at jsfiddle.net)
If you're willing to grab some external code and use it to essentially re-index your structure you could probably do something. I know the old dojo data api was a mess to work with, but could allow something like what you seem to be asking.
Personally I'd stick with loops, just keep your variable names readable. Also remember the object literals can be addressed as either an array/hash syntax x[y] or dot syntax x.y

Categories

Resources