Reputation: 406
I'm drawing a network graph on D3 with data that looks like this:
target source value
Baird JON CARLSON 100
Baird JASON CONRAD 100
Baird JASON CONRAD 100
Baird JASON CONRAD 100
Baird JANET ESKRIDGE 100
Baird LINDA GARNER MULLIN 100
Baird JAMES HARRIS 100
...etc.
The three "Baird | JASON CONRAD | 100" rows are not duplicates; I want D3 to sum over the individuals to give "Baird | JASON CONRAD | 300" before it inputs the link.
I'm new to JS and D3 and don't really have a clue how I'd go about that, but here's your classic csv import function in question:
d3.csv("xxx.csv", function(error, links) {
var nodes = {};
links.forEach(function(link) {
link.source = nodes[link.source] ||
(nodes[link.source] = {name: link.source});
link.target = nodes[link.target] ||
(nodes[link.target] = {name: link.target});
link.value = +link.value;
});
force
.nodes(d3.values(nodes))
.links(links)
.start()
EDIT
I used nest() to sum the values up, but now I've no idea how to input the result into usable links and nodes arrays for force().
Any ideas? This is my nest() code:
var nested_links = d3.nest()
.key(function(link) { return link.source; })
.key(function(link) { return link.target; })
.rollup(function(link) {
return d3.sum(link, function(l) { return l.value; });
}).entries(links);
Upvotes: 0
Views: 1388
Reputation: 570
As @meetamit said you can use d3.nest()
for this task.
How d3.nest()
works?
if you have
var data = [
["Baird JON CARLSON", 100],
["Baird JASON CONRAD", 100],
["Baird JASON CONRAD", 100],
["Baird JASON CONRAD", 100],
["Baird JANET ESKRIDGE", 100],
["Baird LINDA GARNER MULLIN", 100],
["Baird JAMES HARRIS", 100]
];
and execute
var nested_data = d3.nest()
.key(function(d) {
return d[0];
})
.entries(data);
nested_data
will be something like this
[{
"key":"Baird JON CARLSON",
"values":[
["Baird JON CARLSON",100]
]
},{
"key":"Baird JASON CONRAD",
"values":[
["Baird JASON CONRAD",100],
["Baird JASON CONRAD",100],
["Baird JASON CONRAD",100]
]
},{...
}]
with Javascript normaly you can use Array.reduce()
for reduce the array to the sum of the values, but with D3js
the best option is use d3.nest().rollup()
. D3js
has too a helper to reduce an Array()
to a sum of the returned value and if you have
var values = [
["Baird JASON CONRAD",100],
["Baird JASON CONRAD",100],
["Baird JASON CONRAD",100]
];
then you can make
var sum = d3.sum(values, function(d) {
return parseFloat(d[1]);
});
and sum
will be 300
. Glueing all this will be
var nested_data = d3.nest()
.key(function(d) {
return d[0];
})
.rollup(function(leaves) {
return d3.sum(leaves, function(d) {
return parseFloat(d[1]);
});
})
.entries(data);
after that you'll have on nested_data
something like this
[{
"key":"Baird JON CARLSON",
"values": 100
},{
"key":"Baird JASON CONRAD",
"values": 300
},{
"key":"Baird JANET ESKRIDGE",
"values": 100
},{
"key":"Baird LINDA GARNER MULLIN",
"values": 100
},{
"key":"Baird JAMES HARRIS",
"values": 100
}]
Check my Fiddle here
To create your link array as you need it, you've to map the keys and values to the correct position on the array. Take on care that if you use 2 key function you will finish with a double nested object.
var nested_data = d3.nest()
.key(function(d) {
return [d[0],d[1]];
})
.rollup(function(leaves) {
return d3.sum(leaves, function(d) {
return parseFloat(d[2]);
});
})
.entries(data)
.map( function (d) {
var val = d.key.split(',');
return {source: val[0], target: val[1], value: d.values};
});
Check my Fiddle here
Upvotes: 2