Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

D3: Using node attribute for links instead of index in array

I'm a D3.js beginner working on a network visualization, and I can't figure out how to properly specify my links for the force layout. The problem is that by default, d3 interprets the "source" and "target" of the links to be the indices of the nodes in the "nodes" array. However, in my data, the source and target refer to the id numbers of the nodes, which I've stored in a node attribute. How do I get the links to point to node.id instead of node.index? Here is where I guess I should do it:

var nodes = data.nodes;
var edges = data.edges;
var force = d3.layout.force()
            .nodes(d3.values(nodes))
            .links(edges)
            .size([w, h])
            .linkDistance(80)
            .charge(-500)
            .gravity(0.2)
            .on("tick", tick)
            .start();

... but I'm not sure if I should be modifiying the .nodes() part or the .links() part. I tried adding this just before it:

var nodes = data.nodes;
for (var i = 0; i < nodes.length; i++) {
    nodes[i].index = nodes[i].id;
    console.log(i + " " + nodes[i].index + " " + nodes[i].id);
}

... but the index attribute just gets overwritten when I create the force.

I read this question, but the only answer there seems like a bit of a hack. They also mention "data keys", but I can't find much on those, and I don't know how I would incorporate them, since I'm not actually using the enter() function.

like image 710
FrancesKR Avatar asked May 29 '13 21:05

FrancesKR


1 Answers

I don't think that you can force D3 to use the attribute node.id as index, but you can process the links to have the right references:

var edges = [];

data.edges.forEach(function(e) { 
    // Get the source and target nodes
    var sourceNode = data.nodes.filter(function(n) { return n.id === e.source; })[0],
        targetNode = data.nodes.filter(function(n) { return n.id === e.target; })[0];

    // Add the edge to the array
    edges.push({source: sourceNode, target: targetNode});
});

var force = d3.layout.force()
    .nodes(data.nodes)
    .links(edges)
    // the rest of your code here
    .start();

The force layout overwrite the index if you set it, but will keep the references for the source and target of each node in the links.

like image 146
Pablo Navarro Avatar answered Oct 22 '22 13:10

Pablo Navarro