Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can D3 force layout visualize multigraph?

It seems that if there exist multiple links between two nodes in D3 force layout, D3 just picks up one and ignores others. Is it possible to visualize multigraph?

like image 769
Dong Avatar asked Dec 27 '22 13:12

Dong


1 Answers

So, it turns out that d3 does render multiple links between nodes, it's just that it draws them on top of one another. My approach to addressing this is to draw the links as paths (instead of lines) and to add a different curve to each path. This means that each link object needs something to differentiate it from others that the same source and target nodes. My links look like this:

links: [
  {"source": 0,"target": 1,"count": 1}, 
  {"source": 1,"target": 2,"count": 1},
  {"source": 1,"target": 3,"count": 1}, 
  {"source": 1,"target": 4,"count": 1},

  // same source and target with greater count
  {"source": 1,"target": 4,"count": 2}, 
  {"source": 1,"target": 4,"count": 3}, 
  {"source": 1,"target": 4,"count": 4}
]

And then the path rendering code looks like

function tick() {
  link.attr("d", function(d) {
    var x1 = d.source.x,
        y1 = d.source.y,
        x2 = d.target.x,
        y2 = d.target.y,
        dx = x2 - x1,
        dy = y2 - y1,
        // Set dr to 0 for straight edges.
        // Set dr to Math.sqrt(dx * dx + dy * dy) for a simple curve.
        // Assuming a simple curve, decrease dr to space curves.
        // There's probably a better decay function that spaces things nice and evenly. 
        dr = Math.sqrt(dx * dx + dy * dy) - Math.sqrt(300*(d.count-1)); 

   return "M" + x1 + "," + y1 + "A" + dr + "," + dr + " 0 0,1 " + x2 + "," + y2;
  });

  node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
}

Here is a jsfiddle that demonstrates the approach.

like image 138
mes5k Avatar answered Jan 17 '23 12:01

mes5k