D3 force layout - linking nodes by name instead of index

d3.js, javascript, json

Solution

Here is a straightforward way to do this:

var edges = [];
json.Links.forEach(function(e) {
    var sourceNode = json.Nodes.filter(function(n) {
        return n.Id === e.Source;
    })[0],
        targetNode = json.Nodes.filter(function(n) {
            return n.Id === e.Target;
        })[0];

    edges.push({
        source: sourceNode,
        target: targetNode,
        value: e.Value
    });
});

force
    .nodes(json.Nodes)
    .links(edges)
    .start();

var link = svg.selectAll(".link")
    .data(edges)
    ...

Here is a working PLUNK. (You should fork it to be safe, in case I inadvertently delete it.)

Problem

I am attempting to link d3 nodes by an ID instead of index (The node ID is generated by my application). Here are my nodes: ``` "Nodes": [ { "Id": "338", "Name": "TEST NODE ONE", "Url": "http://www.google.com" }, { "Id": "340", "Name": "TEST NODE TWO", "Url": "http://www.yahoo.com" }, { "Id": "341", "Name": "TEST NODE THREE", "Url": "http://www.stackoverflow.com" }, { "Id": "342", "Name": "TEST NODE FOUR", "Url": "http://www.reddit.com" } ] ``` They are currently linked by index: ``` "links": [ { "source": 0, "target": 0, "value": "0" }, { "source": 0, "target": 1, "value": "0" }, { "source": 1, "target": 2, "value": "0" }, { "source": 3, "target": 2, "value": "0" } ] ``` However, I want to link them by "Id": ``` "Links": [ { "Source": "338", "Target": "338", "Value": "0" }, { "Source": "338", "Target": "340", "Value": "0" }, { "Source": "340", "Target": "341", "Value": "0" }, { "Source": "342", "Target": "341", "Value": "0" } ] ``` I've attempted the solution proposed here: https://groups.google.com/forum/#!msg/d3-js/LWuhBeEipz4/0kZIojCYvhIJ by adding the following lines before calling force.nodes: ``` // make links reference nodes directly for this particular data format: var hash_lookup = []; // make it so we can lookup nodes in O(1): json.Nodes.forEach(function(d, i) { hash_lookup[d.Id] = d; }); json.Links.forEach(function(d, i) { d.source = hash_lookup[d.Source]; d.target = hash_lookup[d.Target]; }); ``` I've tried debugging the above, but I can't manage to figure it out. I get the following error message (which usually means I haven't set links correctly): `Uncaught TypeError: Cannot read property 'weight' of undefined` Link to my full JS: http://jsfiddle.net/9sMrw/

Original source

Related problems