Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

D3 force layout - linking nodes by name instead of index

Tags:

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/

like image 399
Blair Avatar asked Jun 02 '14 02:06

Blair


People also ask

How will you invoke the link method while constructing a tree layout using D3?

In the update() function, links = d3. layout. tree(). links(nodes); is 'selecting' the nodes in the tree and their specified links in the JSON file.

What is force layout in D3?

D3's force layout uses a physics based simulator for positioning visual elements. Forces can be set up between elements, for example: all elements can be configured to repel one another. elements can be attracted to center(s) of gravity.

What is a node in D3?

node() function in D3. js is used to return the first element in the selection.


1 Answers

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.)

like image 151
FernOfTheAndes Avatar answered Sep 29 '22 19:09

FernOfTheAndes