Search code examples
javascriptd3.jsdataformat

d3 data parse/convert (from long to wide)


I have a dataset that looks like this in csv format:

continents  countries   values
Europe  Germany 20
Europe  France  30
Europe  Spain   40
Asia    Singapore   100
Asia    Japan   300
Asia    China   30
Asia    Tiwan   500
America USA 50
America Canada  35
America Brazil  30
America Equador 14

When I parse it using d3.csv and map then the data looks like this:

[
{continents: "Europe", countries: "Germany", values: 20}
{continents: "Europe", countries: "France", values: 30} 
{continents: "Europe", countries: "Spain", values: 40} and so forth. ]

What I'd like to do is to convert the format into wide one by continents group, so that the data looks like this

[
{continents: "Europe", 
    values: {"Germany" : 20},
            {"France" : 30},
            {"Spain" : 40}},
{continents: "Asia",
    values: {"Singapore" : 100},
            {"Japan" : 300},
            {"China" : 30}}
]    

That's how I'm doing at the moment.

d3.csv("/data/data.csv").then(function(csv) { 
    data = csv.map(function(d) {
        return {
            continents: d.continents,
            countries: d.countries,
            values: +d.values}
    }); 

The format doesn't need to be exactly the same like the example above but the point is to make key:value pairs with country and values which belong to their respective continents group.

Could anyone let me know how to make?


Solution

  • Updated to use d3.nest

    d3.nest is d3's object for grouping data. You can use it to get you most of the way and then perform a quick transformation afterward:

    var groups = d3.nest().key(d => d.continents).entries(rows),
        result = groups.map(function(d){
        return {
            continents: d.key,
            values: d.values
      };
    

    This will produce something like:

    [{"continents":"Europe",
      "values":[
        {"continents":"Europe","countries":"Germany","values":"20"}, ...
      ],
     },
     {"continents":"Asia",
      "values": [...]
     }, ... ]
    

    Alternative: used3.group

    Another way you can get most of the way there is using d3.group, which is part of d3-array:

    var groups = Array.from(d3.group(rows, d => d.continents));
    

    You can then use these groups to get the object you wanted:

    groups.map(function(d){
        return {
        continents: d[0],
          values: d[1]
        };
    });