Search code examples
javascriptjsond3.jsmergerollup

D3: Merge JSON object entries


Given the following JSON object:

{"links":[
{"source": 0, "target": 3, "value": 5},
{"source": 0, "target": 2, "value": 3},
{"source": 0, "target": 2, "value": 3},
{"source": 0, "target": 1, "value": 2},
{"source": 0, "target": 6, "value": 1},
{"source": 0, "target": 6, "value": 1},
{"source": 0, "target": 6, "value": 1},
{"source": 1, "target": 3, "value": 2}
]}

I would like to group/merge/rollup the entries so that the source-target pairs have their values summed up, like this:

{"links":[
{"source": 0, "target": 3, "value": 5},
{"source": 0, "target": 2, "value": 6},
{"source": 0, "target": 1, "value": 2},
{"source": 0, "target": 6, "value": 3},
{"source": 1, "target": 3, "value": 2}
]}

Is there a way to use D3 to achieve this? I have tried with rollup(), but I don't know how to define a key that consists of more than one key (source, target).

I think I can work with the answers to this question by using for loop and array operations, but I would be glad to know if a D3 function can already take care of this.

Thanks for any help.


Solution

  • One way to handle this is with D3.nest():

    var nest = d3.nest()
       .key(function(d) { return "" + d.source + d.target; })
       .rollup(function(leaves) {
           var sum = d3.sum(leaves, function(g) { return g.value;    });
           return {
             source: leaves[0].source,
             target: leaves[0].target,
             value: sum
           };
       });
    

    Then, use that nest on the links array:

    data.links = d3.values(nest.map(data.links));
    

    Working example here: http://jsfiddle.net/qAHC2/830/