Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

d3 on how to sum values

I have the data below:

[
  { id: 0, Department: "Civil", Value: "40000", Title:"Sustainability", ComID: "45", organisation: { City: "New York", ComID: 45, Country: "USA" } },
  { id: 1, Department: "Energy", Value: "82000", Title: "Wind Energy", ComID: "62", organisation: { City: "Paris" , ComID: 62, Country: "France" } },
  { id: 2, Department: "Medical", Value: "67000", Title: "Neuroscience", ComID: "21", organisation: { City: "Berlin", ComID: 21, Country: "Germany" } },
  { id: 3, Department: "Computer", Value: "100000", Title: "Security", ComID: "67", organisation: { City: "Amsterdam", ComID: 67, Country: "Holland" } }
]

the data is an array of about 100 objects like the ones above.

In the data I have organizations of the same country. I want to sum the Value attribute of each Country and put it in a new table.

For example I would like to create:

[ { Name: "each Country", Value: "the summed value" } ]
like image 279
IsidIoan Avatar asked Oct 23 '16 18:10

IsidIoan


2 Answers

Edited to respond to updated question

You can use d3.nest() to group objects by a given key (in this case, the country) and then "roll them up" to sum the value across each of the items belonging to a given country. In your case, a one-liner would look something like this:

d3.nest().key(function(d){
    return d.organisation.Country; })
.rollup(function(leaves){
    return d3.sum(leaves, function(d){
        return d.Value;
    });
}).entries(data)
.map(function(d){
    return { Country: d.key, Value: d.values};
});

Here I'm using d3.sum, passing in an accessor function to specify that you want to sum the Value of each item:

This returns four objects on your example data:

[{"Country":"USA","Value":40000},
 {"Country":"France","Value":82000},
 {"Country":"Germany","Value":67000},
 {"Country":"Holland","Value":100000}]

Javascript converts the strings into numbers for you. Note that you have some typos in your example data that I had to fix, giving the following:

var data = [ { id:0,Department: "Civil",Value : "40000",Title :"Sustainability",ComID : "45", organisation:{ City:"New York",ComID:"45",Country: "USA"}}, { id:1,Department: "Energy",Value : "82000",Title : "Wind Energy",ComID : "62", organisation:{ City:"Paris",ComID:"62",Country: "France"}}, { id:2,Department: "Medical",Value : "67000",Title : "Neuroscience",ComID : "21", organisation:{ City:"Berlin",ComID:"21",Country: "Germany"}}, { id:3,Department: "Computer",Value : "100000",Title : "Security",ComID : "67", organisation:{ City:"Amsterdam",ComID:"67",Country: "Holland"}}]
like image 139
mdml Avatar answered Oct 18 '22 19:10

mdml


Since d3-collection has been deprecated in favor of d3.array, we can use d3.rollups to achieve what used to work with d3.nest:

d3
  .rollups(
    data,
    xs => d3.sum(xs, x => x.Value),
    d => d.organisation.Country
  )
  .map(([k, v]) => ({ Country: k, Value: v }))

This:

  • Applies a d3.rollups:
    • d3.rollups takes 3 parameters: the input array, a reducing function and a grouping function
    • d => d.organisation.Country groups items by Country
    • xs => d3.sum(xs, x => x.Value) reduces grouped values by extracting their Value and summing them using d3.sum
  • Formats the rollups' output in order to get the expected output (the map transformation).

var data = [
  { id: 0, Department: "Civil", Value: "40000", Title:"Sustainability", ComID: "45", organisation: { City: "New York", ComID: 45, Country: "USA" } },
  { id: 1, Department: "Energy", Value: "82000", Title: "Wind Energy", ComID: "62", organisation: { City: "Paris" , ComID: 62, Country: "France" } },
  { id: 2, Department: "Medical", Value: "67000", Title: "Neuroscience", ComID: "21", organisation: { City: "Berlin", ComID: 21, Country: "Germany" } },
  { id: 3, Department: "Computer", Value: "100000", Title: "Security", ComID: "67", organisation: { City: "Amsterdam", ComID: 67, Country: "Holland" } }
];

var output =
  d3.rollups(
      data,
      xs => d3.sum(xs, x => x.Value),
      d => d.organisation.Country
    )
    .map(([k, v]) => ({ Country: k, Value: v }))

console.log(output);
<script src="https://d3js.org/d3-array.v2.min.js"></script>
like image 40
Xavier Guihot Avatar answered Oct 18 '22 20:10

Xavier Guihot