How to layout a non-tree hierarchy with D3

d3-hierarchy is not a function
d3 tree layout multiple parents
d3 pack
d3 collapsible tree
d3 hierarchical network graph
hierarchy js
angular-d3 collapsible tree
d3 org chart

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.

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;
});

javascript - How to layout a non-tree hierarchy with D3, 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  The utility we will use to make a hierarchy for our data is d3.rollup. According to the d3-array docs: d3.rollup “groups and reduces the specified iterable of values into a Map from key to value”.

As this example: "Force Directed Trees" illustrates there is a trick that often works. In the example the force direction's behavior is adjusted on each tick so that nodes drift slightly up or down depending on the direction of the links. As shown this will do a fine job for trees, but I've found it also works tolerable well for acyclic graphs. No promises, but it may help.

tree layout, For example the tree layout takes a hierarchical data structure and adds x and y values to each node such that the nodes form a tree-like shape: D3 has a  Runs the tree layout, returning the array of nodes associated with the specified root node. The tree layout is part of D3's family of [[hierarchical|Hierarchy-Layout]] layouts. These layouts follow the same basic structure: the input argument to the layout is the root node of the hierarchy, and the output return value is an array representing

Speaking generally of trees and the data hierarchy, you just need to have "D" in the children list for both B and C.

Creating your node list, make sure you have a unique id returned so that "D" doesn't appear twice.

vis.selectAll("g.node").data(nodes, function(d) { return d.id; });

Then when you call

var links = tree.links(nodes)

you should get D appearing as the "target" twice (with B and C as the "source" respectively) which results in two lines to the single node "D".

d3/d3-hierarchy: 2D layout algorithms for visualizing , And even non-hierarchical data may be arranged empirically into a hierarchy, The “tidy” tree is delightfully compact, while the dendrogram places leaves at the​  Before you can compute a hierarchical layout, you need a root node. If your data is already in a hierarchical format, such as JSON, you can pass it directly to d3.hierarchy; otherwise, you can rearrange tabular data, such as comma-separated values (CSV), into a hierarchy using d3.stratify. d3.hierarchy(data[, children]) Source. Constructs a

I was able to do this using a combination of Dagre(https://github.com/dagrejs/dagre) and cytoscape

There's a library called Dagre-D3 that you can use as a renderer for this library so it looks like the D3 solution you want.

Check out this fiddle to see the basic implementation with Dagre and Cytoscape: https://jsfiddle.net/KateJean/xweudjvm/

var cy = cytoscape({
  container: document.getElementById('cy'),
  elements: {
          nodes: [
            { data: { id: '1' } },
            { data: { id: '2' } },
            { data: { id: '3' } },
            { data: { id: '4' } },
            { data: { id: '5' } },
            { data: { id: '6' } },
            { data: { id: '7' } },
            { data: { id: '8' } },
            { data: { id: '9' } },
            { data: { id: '10' } },
            { data: { id: '11' } },
            { data: { id: '12' } },
            { data: { id: '13' } },
            { data: { id: '14' } },
            { data: { id: '15' } },
            { data: { id: '16' } },
            { data: { id: '17' } },
            { data: { id: '18' } }
          ],
          edges: [
            { data: { source: '1', target: '2' } },
            { data: { source: '1', target: '3' } },
            { data: { source: '2', target: '4' } },
            { data: { source: '4', target: '5' } },
            { data: { source: '4', target: '6' } },
            { data: { source: '5', target: '6' } },
            { data: { source: '5', target: '7' } },
            { data: { source: '7', target: '8' } },
            { data: { source: '3', target: '9' } },
            { data: { source: '3', target: '10' } },
            { data: { source: '10', target: '11' } },
            { data: { source: '11', target: '12' } },
            { data: { source: '12', target: '13' } },
            { data: { source: '12', target: '14' } },
            { data: { source: '14', target: '15' } },
            { data: { source: '15', target: '16' } },
            { data: { source: '16', target: '17' } },
            { data: { source: '16', target: '18' } }

          ]
        },
  layout: {
    name: "dagre",
    rankDir: 'TB' //love this. you can quickly change the orientation here from LR(left to right) TB (top to bottom), RL, BT. Great dropdown option for users here. 
  },
  style: [{
    selector: 'node',
    style: {
      'label': 'data(id)',
      'width': '30%',
      'font-size': '20px',
      'text-valign': 'center',
      'shape': 'circle',
      'background-color': 'rgba(113,158,252,1)', 
      'border': '2px grey #ccc'
    }
  }, {
    selector: 'edge',
    style: {
      'width': 2,
      'line-color': '#ccc',
      'target-arrow-color': '#ccc',
      'target-arrow-shape': 'triangle'
    }
  }]
});

d3-hierarchy/README.md at master · d3/d3-hierarchy · GitHub, And even non-hierarchical data may be arranged empirically into a hierarchy, This hierarchy can now be passed to a hierarchical layout, such as d3.tree, for  Layouts. D3 layouts help you create more advanced visualisations such as treemaps: packed circles: and network graphs: In essence a layout is just a JavaScript function that takes your data as input and adds visual variables such as position and size to it. For example the tree layout takes a hierarchical data structure and adds x

d3.hierarchy / D3 / Observable, To visualize a hierarchy, you'll want one of d3-hierarchy's layouts, such. A d3.​hierarchy is a nested data structure representing a tree: each node (By consequence, an empty children array is not allowed in the current API.). You must call root.sum before passing the hierarchy to the partition layout. You probably also want to call root.sort to order the hierarchy before computing the layout. # partition.size([size]) If size is specified, sets this partition layout’s size to the specified two-element array of numbers [width, height] and returns this partition layout.

Hierarchy Layout, [[Treemap|Treemap-Layout]] - use recursive spatial subdivision to display a tree of nodes. Although not a hierarchy layout, the bundle layout is also designed to  The only viz that could handle all of the terms in the taxonomy is D3’s collapsible tree. Still, you don’t want to keep all the branches open at the same time! Click on the image to see it with your eyes. An approach to deal with large quantities of data is obviously to show them a little bit at a time.

Tree Layout, The tree layout is part of D3's family of [[hierarchical|Hierarchy-Layout]] layouts. If children is not specified, returns the current children accessor function, which  Runs the tree layout, returning the array of nodes associated with the specified root node. The tree layout is part of D3's family of hierarchical layouts. These layouts follow the same basic structure: the input argument to the layout is the root node of the hierarchy, and the output return value is an array representing the computed positions of all nodes.

Comments
  • You might want to have a look at the force directed graph layout.
  • Thanks for the example, Phil! I ended up doing something very similar. It turns out the layout algorithm I really wanted was implemented in GraphViz. It has python bindings, but they don't work. Instead I did the following: 1) Form graph into DOT language (graphviz.org/content/dot-language) 2) Pass graph to graphviz's dot command via commandline, which does the layout and puts (x,y) coordinates into DOT 3) Reformat DOT into javascript objects, embed into page 4) Use D3 to place nodes according to (x,y) coordinates in DOT. This works really well with very large graphs.
  • I was able to get the tree assembled in the manner you describe, but the TreeLayout doesn't seem to be able to handle it. There is a chance I screwed that up somehow; have you had luck getting a layout to run this way? In the meantime, I've managed a pretty suitable workaround using GraphViz on the server side. GraphViz will do a nice hierarchical layout and output in DOT format with (x,y) positions for each node. From there, it's relatively easy to package that information into the page and draw it using D3. Thanks for your help, I appreciate the effort!
  • I played around with it and it was pretty crazy. Depending on the parent it would sometimes fail inside d3: "vom is undefined: 6444" and other times it would render, but put the child in an ugly spot. So short answer is, you're right. The tree layout in the case is the problem.