Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to layout a non-tree hierarchy with D3

Tags:

D3 has a variety of layouts for directed graphs that are strict trees, such as the following:

A |\ B C  / \ D   E 

I need to draw a hierarchy of nodes that is not a tree, but is a directed acyclic graph. This is a problem for a tree layout, because several of the branches converge:

A |\ B C  \|   D 

Does anyone know of a D3 layout for general hierarchies? Or alternatively, some clever hack to the existing treelayout? I've noticed GraphVis handles this situation well, but D3 produces a graph that better suits the requirements here.

like image 705
John Walthour Avatar asked Jun 15 '12 15:06

John Walthour


People also ask

What does d3 hierarchy do?

hierarchy() function in D3. js library is used to construct a root node data from a given hierarchical data. The data that is given must be of an object and must represent a root node.

How will you invoke the link method while constructing a tree layout using d3 choose the correct syntax?

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 does d3 layout produce?

But D3 layouts don't result in charts; they result in the settings necessary for charts. You have to put in a bit of extra work for charts, but you have enormous flexibility (as you'll see in this and later chapters) that allows you to make diagrams and charts that you can't find in other libraries.

What is d3 stratify?

d3. stratify transforms a tree from link representation to hierarchy. a b c d e f g h i. Here's a typical tree, visualized as a root node a with links to other nodes at deeper levels. It can be represented by a flat list of links, connecting labels from parent to child.


1 Answers

You could create your own code without having to rely on a D3 layout in order to get it done.

I've provided an example in a jsFiddle. The example is pretty simplistic and would need to be worked a little bit to accommodate more complex examples.

The example could be re-worked to process hierarchical data as well with relatively little effort.

Here is the code I have used in the jsFiddle:

 // Sample data set var json = {     nodes: [{         name: 'A'},     {         name: 'B'},     {         name: 'C'},     {         name: 'D'}],     links: [{         source: 'A',         target: 'B'},     {         source: 'A',         target: 'C'},     {         source: 'B',         target: 'D'},     {         source: 'C',         target: 'D'}                                                                                    ]  };  var vis = d3.select('#vis').attr('transform', 'translate(20, 20)');  // Build initial link elements - Build first so they are under the nodes var links = vis.selectAll('line.link').data(json.links); links.enter().append('line').attr('class', 'link').attr('stroke', '#000');  // Build initial node elements var nodes = vis.selectAll('g.node').data(json.nodes); nodes.enter().append('g').attr('class', 'node').append('circle').attr('r', 10).append('title').text(function(d) {     return d.name; });  // Store nodes in a hash by name var nodesByName = {}; nodes.each(function(d) {     nodesByName[d.name] = d; });  // Convert link references to objects links.each(function(link) {     link.source = nodesByName[link.source];     link.target = nodesByName[link.target];     if (!link.source.links) {         link.source.links = [];     }     link.source.links.push(link.target);     if (!link.target.links) {         link.target.links = [];     }     link.target.links.push(link.source); });  // Compute positions based on distance from root var setPosition = function(node, i, depth) {     if (!depth) {         depth = 0;     }     if (!node.x) {         node.x = (i + 1) * 40;         node.y = (depth + 1) * 40;         if (depth <= 1) {             node.links.each(function(d, i2) {                 setPosition(d, i2, depth + 1);             });         }      }  }; nodes.each(setPosition);  // Update inserted elements with computed positions nodes.attr('transform', function(d) {     return 'translate(' + d.x + ', ' + d.y + ')'; });  links.attr('x1', function(d) {     return d.source.x; }).attr('y1', function(d) {     return d.source.y; }).attr('x2', function(d) {     return d.target.x; }).attr('y2', function(d) {     return d.target.y; }); 
like image 174
Phil Laliberte Avatar answered Oct 07 '22 18:10

Phil Laliberte