Reputation: 363
I have a function that is polling for temperature data:
{"a":"43",
"b":"43",
"c":"42",
"d":"43",
"e":"40",
"f":"41",
"g":"100",
"h":"42.6"}
I want to be able to graph that data over time, but I can't figure out the best way to map the above data, to something like the below data:
temps: [{
name: "a",
data: ["43","42","43"]
},
name: "b",
data: ["43","42","43"]
},
etc...
]
I have tried the code below, and tried to figure out the javascript map function, but I keep running into scoping problems where "this" isn't the same thing as it was in the parent:
this.temp_names.forEach(function(e){
if(typeof this.temps[e] == "undefined") {
this.temps[e] = []
}
this.temps.e.unshift(this.sys_telemetry.S.temps)
if (this.temps.e.length > 10) {
this.temps.e.pop()
}
})
where "temp_names" was an array of the keys.
I'm doing this in VueJS, so the "this" is accessing the data in my component.
Upvotes: 1
Views: 88
Reputation: 17606
Using Array#from, Object#entries, Array#map and destructuring you could do something like this.
const data={"a":"43","b":"43","c":"42","d":"43","e":"40","f":"41","g":"100","h":"42.6"}
const res = Object.entries(data)
.map(([name, data])=>({name, data:[data]}));
console.log(res);
Alternative using Array#reduce, Map,
const data={"a":"43","b":"43","c":"42","d":"43","e":"40","f":"41","g":"100","h":"42.6"}
const res = Array.from(Object
.entries(data)
.reduce((a,[k,v])=>{
if(!a.has(k)) a.set(k, []);
a.get(k).push(v);
return a;
}, new Map()))
.map(([name, data])=>({name, data}));
console.log(res);
Upvotes: 2
Reputation: 147343
It seems to me that you want to be able to add multiple datasets to the data object. One approach is to have a data object with methods that know how to do things like add data to themselves, maybe something like the following. You might want to keep the index property private, and maybe sort it so it's always in a particular order regardless of the order the values are added.
var data0 = {"a":"43",
"b":"43",
"c":"42",
"d":"43"};
var data1 = {"a":"53",
"b":"53",
"c":"52",
"d":"53",
"e":"65"
};
class DataObject {
constructor (data) {
this.index = [];
this.data = [];
if (data) {
this.addData(data);
}
}
addData (data) {
Object.keys(data).forEach(key => {
let idx = this.index.indexOf(key);
if (idx == -1) {
idx = this.index.push(key) - 1;
this.data.push({name:key, data:[]});
}
this.data[idx].data.push(data[key]);
});
}
}
// Initialise object with some data
let myData = new DataObject(data0);
console.log(JSON.stringify(myData.data));
// Add more data
myData.addData(data1);
console.log(JSON.stringify(myData.data));
Upvotes: 0
Reputation: 10102
You might be able to get away with a simpler data structure like, eg. { a: [43, 42, 43], b: [1, 2, 3] }
ie. instead of having separate name
and data
keys, you could use name
as the key, and the data
array as the value.
If this would work to represent the timeline for each key, and your initial data is structured like, eg. [{ a: 43, b: 1, c: 3 }, { a: 42, b: 2, c: 3 }]
, then something like this might be suitable to transform the latter into the former:
const output = {};
temp_data.forEach(x => {
for (const key in x) {
const y = x[key];
if (typeof output[key] === 'undefined') {
output[key] = [];
}
output[key].push(y);
}
});
This produces an object whose keys match the keys in your data points (eg. "a", "b", "c", etc), and whose values are an array of all the values for each of these keys, which might be suitable for plotting a timeline.
(Incidentally, if you want to plot these as values on a graph, it might be better to treat the values as numbers - eg. 1, 2, 3
- rather than strings - eg. "1", "2", "3"
).
There are probably more elegant, functional-style ways of doing this, but this might do the job!
Upvotes: 0
Reputation: 24181
graph that data over time
Because you want to do this over time, it would make sense to create an array and then using Object.entries
, & Array.find
, update the results.
Here is an example.
const values1 =
{"a":"43", "b":"43", "c":"42", "d":"43", "e":"40", "f":"41",
"g":"100", "h":"42.6"};
const values2 =
{"c":"44", "e":"39"};
const results = [];
function addData(data) {
Object.entries(data).forEach(([k, v]) => {
let find = results.find(f => f.name === k);
if (!find) {
find = {
name: k,
data: []
}
results.push(find);
}
find.data.push(v);
});
}
addData(values1); //data packet one arrives
addData(values2); //data packet two arrives
console.log(results); //results contains both data packet one & two.
Upvotes: 1