d3.nest() sum for object array data - javascript

I have data in the format of
data={
"Month": "Jan",
"typeA": [
{
"A": 24000,
"B": 24000,
"C": 24000
}],
"typeB": [
{
"A": 20000,
"B": 14000,
"C": 10000
}],
"typeC": [
{
"A": 34000,
"B": 44000,
"C": 54000
}]
},
{
"Month": "Feb",
"typeA": [
{
"A": 84000,
"B": 64000,
"C": 14000
}],
"typeB": [
{
"A": 20000,
"B": 34000,
"C": 10000
}],
"typeC": [
{
"A": 30000,
"B": 40000,
"C": 50000
}]
}
]
I want to calculate sum of each type( ie typeA, TypeB) for indivisual months,
Ie I want data in the format below,
Month: jan
typeA:72000
typeB:44000
typeC:13200
Month:feb
typeA:162000
typeB:64000
typeC:120000
I am using d3.nest() to achieve this,
This is my code,
var months= d3.nest()
.key(function (d) { return (d.Month) })
.key(function (d) { return (d.typeA) })
.key(function (d) { return (d.typeB) })
.key(function (d) { return (d.typeC) })
.rollup(function (leaves) {
return d3.sum(leaves, function (d) { return d3.sum(sum,d3.values(d.A,d.B,d.C,d.D)) });
})
.entries(data);
I am not able to get the sum of the elements here. I'm getting zero as sum. Can anybody suggest me where I am doing wrong?

Unfortunately my other answer was for a different question but I'll leave it in case it's useful.
The answer by #Gabriel is very cool but is using d3 functions but its not generic and the categories are hard-coded in which is not ideal.
Here is a way to do it in (mostly) plain JS that is completely generic. The only assumption is that the first member of each array element is the heading being grouped and the other members are the ones to be rolled up. Anyway, as well as generic, this way is quite short.
I also included a version of the #Gabriel answer to show it's easy to generalise also.
var data = [{
"Month": "Jan",
"typeA": [
{
"A": 24000,
"B": 24000,
"C": 24000
}],
"typeB": [
{
"A": 20000,
"B": 14000,
"C": 10000
}],
"typeC": [
{
"A": 34000,
"B": 44000,
"C": 54000
}]
},
{
"Month": "Feb",
"typeA": [
{
"A": 84000,
"B": 64000,
"C": 14000
}],
"typeB": [
{
"A": 20000,
"B": 34000,
"C": 10000
}],
"typeC": [
{
"A": 30000,
"B": 40000,
"C": 50000
}]
}],
//////////////////////////////////////////////////////////////////////////////////
//Method one: without rollup
// assume that the first member of each object in the array is a heading
// e.g. Month
//////////////////////////////////////////////////////////////////////////////////
headings = data.reduce(function(headings, d) {
var h = d3.keys(d)[0]; //get the heading
return (headings [d[h]] = d3.keys(d).filter(function(p, i){return i}) //filter out the heading
.reduce(function(s, p){ //sum each of the other members
//p is the category being summed
return (s[p] = d3.sum(d3.values(d[p][0])), s);
}, {}), headings);
}, {});
d3.select("#output").text(JSON.stringify(headings));
//////////////////////////////////////////////////////////////////////////////////
//Method two: #Gabriel solution generalised
//////////////////////////////////////////////////////////////////////////////////
var months = d3.nest()
.key(function(d) { return (d.Month) })
.rollup(function (v) {
return d3.keys(v[0]).filter(function(p, i){return i}) //filter out the heading
.reduce(function(s, p){ //sum each of the other members
//p is the category being summed
return (s[p] = d3.sum(d3.values(v[0][p][0])), s);
}, {});
})
.map(data);
d3.select("#output2").text(JSON.stringify(months));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="output"></div></br>
<div id="output2"></div>

I am not much familiar with d3.nest. But I think you can get your results by using JavaScript Array map function. Try this code.
var data=[{
"Month": "Jan",
"typeA": [
{
"A": 24000,
"B": 24000,
"C": 24000
}],
"typeB": [
{
"A": 20000,
"B": 14000,
"C": 10000
}],
"typeC": [
{
"A": 34000,
"B": 44000,
"C": 54000
}]
},
{
"Month": "Feb",
"typeA": [
{
"A": 84000,
"B": 64000,
"C": 14000
}],
"typeB": [
{
"A": 20000,
"B": 34000,
"C": 10000
}],
"typeC": [
{
"A": 30000,
"B": 40000,
"C": 50000
}]
}
];
var results = data.map(function(d){
return {
Month: d.Month ,
typeA: d3.sum(d3.values(d.typeA[0])),
typeB: d3.sum(d3.values(d.typeB[0])),
typeC: d3.sum(d3.values(d.typeC[0]))
}
});
alert(JSON.stringify(results));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

You can do it with nesting like this...
data = [{
"Month": "Jan",
"typeA": [
{
"A": 24000,
"B": 24000,
"C": 24000
}],
"typeB": [
{
"A": 20000,
"B": 14000,
"C": 10000
}],
"typeC": [
{
"A": 34000,
"B": 44000,
"C": 54000
}]
},
{
"Month": "Feb",
"typeA": [
{
"A": 84000,
"B": 64000,
"C": 14000
}],
"typeB": [
{
"A": 20000,
"B": 34000,
"C": 10000
}],
"typeC": [
{
"A": 30000,
"B": 40000,
"C": 50000
}]
}],
months = d3.nest()
var months = d3.nest()
.key(function(d){return d.Month})
.rollup(function(leaves){
//leaves is an array so use d3.sum
return d3.sum(leaves, function(d) {
//d can be an object who's value can be an array
//use d3.sum
return d3.sum(d3.values(d), function(e){
//
return d3.sum(e, function(f) {
return d3.sum(d3.values(f))
});
})
} )
})
.entries(data);
d3.select("#output").text(JSON.stringify(months));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="output"></div>

You just need to change your code like this:
Add ]; end of data
data = [
{
"Month": "Jan",
"typeA": [
{
"A": 24000,
"B": 24000,
"C": 24000
}
],
"typeB": [
{
"A": 20000,
"B": 14000,
"C": 10000
}
],
"typeC": [
{
"A": 34000,
"B": 44000,
"C": 54000
}
]
},
{
"Month": "Feb",
"typeA": [
{
"A": 84000,
"B": 64000,
"C": 14000
}
],
"typeB": [
{
"A": 20000,
"B": 34000,
"C": 10000
}
],
"typeC": [
{
"A": 30000,
"B": 40000,
"C": 50000
}
]
}
];
Change your code to:
var months = d3.nest()
.key(function(d) { return (d.Month) })
.rollup(function (v) {
return {
typeA: d3.sum(d3.values(v[0].typeA[0])),
typeB: d3.sum(d3.values(v[0].typeB[0])),
typeC: d3.sum(d3.values(v[0].typeC[0]))
} })
.map(data);
console.log(JSON.stringify(months));
Edit:
You can use this type of d3.sum() function too, But remember the value's that return are string 'the part that you missed in your code' to see the actual result need to parse data.
var months = d3.nest()
.key(function(d) { return (d.Month) })
.rollup(function(v) {
return {
typeA: d3.sum(v, function(d) {
var type = d3.values(d.typeA[0]);
var array = type.map(function (x) { return parseInt(x, 10) });
return d3.sum(array);
}),
typeB: d3.sum(v, function (d) {
var type = d3.values(d.typeB[0]);
var array = type.map(function (x) { return parseInt(x, 10) });
return d3.sum(array);
}),
typeC: d3.sum(v, function (d) {
var type = d3.values(d.typeC[0]);
var array = type.map(function (x) { return parseInt(x, 10) });
return d3.sum(array);
})
}
})
.entries(data);
console.log(JSON.stringify(months));

Related

How can i create an array in defined order as below?

The array in this order:
I want to create a new array as:
You can apply map() function on your data to get your desired output like you posted above. According to question, a possible solution would be as below
const data = [{
"date": "2020-01-01",
"point": {
"a": "1",
"b": "2"
}
},
{
"date": "2020-02-01",
"point": {
"a": "3",
"b": "4"
}
},
{
"date": "2020-03-01",
"point": {
"a": "5",
"b": "6"
}
},
{
"date": "2020-04-01",
"point": {
"a": "7",
"b": "8"
}
}
];
const res = data.map((_, index) => {
return {
series: {
data: data.slice(0, index + 1).map(i => [Number(i.point.a), Number(i.point.b)])
}
}
});
console.log(res);
You could try something like this:
resultArray = yourarray.map(function(data){
return {
series:{
"data":[data.points.a,data.points.b]
}
}
})
I believe this will get you what you want:
const orig = [
{
"date": "2020-01-01",
"point": {
"a": "1",
"b": "2"
}
},
{
"date": "2020-02-01",
"point": {
"a": "3",
"b": "4"
}
},
{
"date": "2020-03-01",
"point": {
"a": "5",
"b": "6"
}
},
{
"date": "2020-04-01",
"point": {
"a": "7",
"b": "8"
}
}
];
// Make the new array.
const points = [];
const newArray = orig.map( x => {
points.push([x.point.a, x.point.b]);
return {
"series": {
"data": points.slice(0)
}
}
});
// Log the new array.
console.log(newArray);

Iterate through nested JSON object array and store as key-value pair

I have to iterate through this JSON:
{
"data": 321563,
"group": [
{
"added": 42421,
"normal": {
"x": 39,
"y": "0.1300",
"b": "0.4326",
"c": "0.0552",
"f": 166833
},
"j": "240313",
"b": "0.2251",
"a": "dda",
"b": "0.101",
"a": 922,
"f": {
"c": 39,
"d": "0.263",
"a": "2.8955",
"h": "0.3211",
"d": 274
},
"a": false,
"k": 5,
"w": "0.072",
"d": "0.045",
"e": 3
},
I only want the j and k stored like a key value pair e.g. "j":k
I need to loop all of it, and store it to a file.
You can use a map to get a new array of items, this will not affect the old array.
const data = {
"game_count": 8750,
"sets": [
{
"appid": "221540",
"true_count": 9,
"bgs_avg": "0.10",
// Other data here
},
{
"appid": "123456",
"true_count": 9,
"bgs_avg": "0.20",
// Other data here
}
]
}
// Use "data.sets = data.sets.map(...)" to replace the data
// The following will only assign to a new variable
const newArray = data.sets.map(itm => { return {appid: itm.appid, true_count: itm.true_count} })
console.log(newArray)
We can also take the data and assign it directly back to the original overwriting it just by using data.sets = data.sets.map(...) as seen here:
const data = {
"game_count": 8750,
"sets": [
{
"appid": "221540",
"true_count": 9,
"bgs_avg": "0.10",
// Other data here
},
{
"appid": "123456",
"true_count": 9,
"bgs_avg": "0.20",
// Other data here
}
]
}
data.sets = data.sets.map(itm => { return {appid: itm.appid, true_count: itm.true_count} })
console.log(data)
In simple javascript this should work -
let newObj = {}
for(let i=0; i<obj.group.length; i++){
newObj[obj.group[i].j] = obj.group[i].k
}
Where 'obj' is your object
newObj will be you new Object which will contain all the key value pair

Angular 6 merge two array to count the length of key

I have an array of two objects which has another array of objects, i want the count of all objects of property "value" in the following sample.
var data = [
{
"x": "123",
"values": [
{
"a": "1"
},
{
"b": "2"
}
]
}, {
"y": "123",
"values": [
{
"a": "1"
},
{
"b": "2"
}
]
}
];
I have used the following logic :-
let _data = data.RESULT;
console.log(JSON.stringify(_data));
_data.forEach(element => {
this.someObj = element;
});
The expected result should be the length of values property, i.e. 4
If you want to find only length of "values" array then you need to do this
data = [
{
"x": "123",
"values": [
{
"a": "1"
},
{
"b": "2"
}
]
}, {
"y": "123",
"values": [
{
"a": "1"
},
{
"b": "2"
}
]
}
]
length = 0;
constructor() {
this.data.forEach((d) => {
length = length + d.values.length;
});
console.log('length', length);
}
https://stackblitz.com/edit/angular-3daqcy?file=src%2Fapp%2Fapp.component.ts
Created a function that adds the lengths of the values array
var arr = [
{
"x": "123",
"values": [
{
"a": "1"
},
{
"b": "2"
}
]
}, {
"y": "123",
"values": [
{
"a": "1"
},
{
"b": "2"
}
]
}
]
function getKeysLength(arr){
var count = 0;
arr.forEach((val)=>{count= count+ val.values.length})
return count
}
var ans = getKeysLength(arr);
console.log("ans",ans);
If you want to do it in a single line then you can do it with map and reduce,map creates a new array with the elements as the length of the values property and reduce calculates the sum of the new array elements . Which gives you the sum of the length of all values property arrays.
Here is the code below -
let data = [
{
"x": "123",
"values": [
{
"a": "1"
},
{
"b": "2"
}
]
}, {
"y": "123",
"values": [
{
"a": "1"
},
{
"b": "2"
}
]
}
];
let totalLength = data.map(x => x.values.length).reduce((a,b) => a+b,0);
console.log(temparr);
Here is a working Stackblitz with Angular 6
https://stackblitz.com/edit/hello-angular-6-ewa5tb?file=src/app/app.component.ts

Converting one data structure to another

Hi I need to parse some structure to to show some data in line chart. I have this data structure , and I need to convert it for array example_output:
data = {
"el1": [{
"date": "2017.01",
"data1": {
"series_1": {
"a": 10,
"b": 20,
"c": 50,
"d": 15,
"e": 8
},
"Series_2": {
"yes": 5,
"no": 3
},
"Series_3": {
"s": 2,
"n": 9
}
},
"text": [{
"t": "header",
"c": "text"
}, {
"t": "header2",
"c": "text2"
}]
}, {
"date": "2017.02",
"data1": {
"series_1": {
"a": 56,
"b": 23,
"c": 45,
"d": 69,
"e": 14
},
"Series_2": {
"yes": 2,
"no": 1
},
"Series_3": {
"s": 6,
"n": 4
}
},
"text": [{
"t": "header",
"c": "text"
}, {
"t": "header2",
"c": "text2"
}]
}, {
"date": "2017.03",
"data1": {
"series_1": {
"a": 15,
"b": 12,
"c": 10,
"d": 54,
"e": 4
},
"Series_2": {
"yes": 20,
"no": 16
},
"Series_3": {
"s": 9,
"n": 7
}
},
"text": [{
"t": "header",
"c": "text"
}, {
"t": "header2",
"c": "text2"
}]
}
]
};
and I need OUTPUT like this for chartist.js
var example_output = [{
labels: ['2017.01', '2017.02', '2017.03'],
series: {
[10, 56, 15],
[20, 23, 12],
[50, 45, 10],
[15, 69, 54],
[8, 14, 4]
},
labels: ['2017.01', '2017.02', '2017.03'],
series: {
[5, 2, 20],
[3, 1, 16]
},
labels: ['2017.01', '2017.02', '2017.03'],
series: {
[2, 6, 9],
[9, 4, 7]
},}] ;
Please compare digits from the original and the example_output to better understand how this should look like. I use code for parse this but someting goes wrong:
function parseData(data) {
var _newData = {};
var allSeries = [];
data.elements.forEach(function(el){
_newData[el.date] = el.info
if(allSeries.length==0)
allSeries = Object.keys(el.info);
});
return allSeries.map(function(el) {
var obj = {
labels: [],
series: []
};
obj.labels = Object.keys(_newData);
Object.keys(_newData).forEach(function(_el) {
obj.series.push(Object.values(_newData[_el][el]));
});
var _newSeries = [];
obj.series[0].forEach(function(el, i){
_newSeries.push([el, obj.series[1][i]]);
});
obj.series = _newSeries;
return obj;
});
}
You can use array#forEach and array#reduce. Use first loop to iterate through el1 and then use reduce for the series key and accumulate the result in the output_example.
NOTE: The series in your output is incorrect. It should be an array instead of object.
const data = {"el1": [{"date": "2017.01","data1": {"series_1": {"a": 10,"b": 20,"c": 50,"d": 15,"e": 8},"Series_2": {"yes": 5,"no": 3},"Series_3": {"s": 2,"n": 9}},"text": [{"t": "header","c": "text"}, {"t": "header2","c": "text2"}]}, {"date": "2017.02","data1": {"series_1": {"a": 56,"b": 23,"c": 45,"d": 69,"e": 14},"Series_2": {"yes": 2,"no": 1},"Series_3": { "s": 6,"n": 4 }},"text": [{"t": "header","c": "text"}, {"t": "header2","c": "text2"}]}, {"date": "2017.03","data1": {"series_1": {"a": 15,"b": 12,"c": 10,"d": 54,"e": 4},"Series_2": {"yes": 20, "no": 16},"Series_3": {"s": 9, "n": 7}},"text": [{"t": "header","c": "text"}, {"t": "header2","c": "text2" }]}]};
transpose = (arr) => arr.reduce((r,v,i) => {
(r[i] = r[i] || []).push(v);
return r;
},[]);
let example_output = [];
data.el1.forEach((o) => {
Object.keys(o.data1).reduce((r, k, i) => {
r[i] = r[i] || {};
if('labels' in r[i])
r[i]['labels'].push(o.date);
else
r[i]['labels'] = [o.date];
if('series' in r[i])
Object.values(o.data1[k]).forEach((v,j) => r[i]['series'][j].push(v));
else
r[i]['series'] = transpose(Object.values(o.data1[k]));
return r;
},example_output);
},[]);
console.log(example_output);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Generating dictionaries and lists in JavaScript after a JSON

I'm receiving a JSON in this format:
{
"0": {
"a": 0.0,
"b": 1.0,
"G": 6.0,
"w": 0.0,
"F": -1.0
},
"1": {
"a": 0.0,
"b": 0.1429004669189453,
"G": 0.000301361083984375,
"w": 0.1429004669189453,
"F": -1.0
},
"2": {
"a": 0.0,
"b": 0.1429004669189453,
"G": 0.000301361083984375,
"w": 0.1429004669189453,
"F": -1.0
},
"3": {
"a": 0.0,
"b": 0.1429004669189453,
"G": 0.000301361083984375,
"w": 0.1429004669189453,
"F": -1.0
....
Let's say I call that a json variable. I'm trying to turn it into something like:
[
{"key": "series1",
values: [
[`json`["1"]["a"],`json`["1"]["F"]],[`json`["1"]["b"],`json`["1"]["G"]]
]
},
{"key": "series2",
values: [
[`json`["2"]["a"],`json`["2"]["F"]],[`json`["2"]["b"],`json`["2"]["G"]]
]
},
{"key": "series3",
values: [
[`json`["3"]["a"],`json`["3"]["F"]],[`json`["3"]["b"],`json`["3"]["G"]]
]
},
....
]
I tried this JavaScript for accomplishing it but got lost :S
var data = function myData(json) {
series = {}
for (iteracion in json) {
series.push({
key: iteracion, values: [[x: iteracion['a'], y: iteracion['F']],[x: iteracion['b'], y: iteracion['G']]]
})
}
return series
A solution to your problem is:
var result = [];
for (var series in json) {
result.push({
key : 'series' + series,
values : [
json[series].a,
json[series].F,
json[series].b,
json[series].G,
]
});
}
If you don't really need an array of objects that contain a key and a value, i organized your information slightly better:
var result = {};
for (var series in json) {
result['series' + series] = [
json[series].a,
json[series].F,
json[series].b,
json[series].G,
];
}
This results in something like this:
{
series0 : [ 0, -1, 1, 6 ],
series1 : [ 0, -1, 0.14, 0.0003],
...
}

Categories