Search code examples
javascripthtmlvis.jsvis.js-network

In a vis.js network, how to set the level of a node automatically based on its depth?


I'm trying to create a hierarchical graph using vis.js. I can create the hierarchical graph, but the layout is not what I'm looking for: the nodes are on seemingly arbitrary levels. I want the nodes to be on different levels based on how many edges between them and the root.

The data originally comes from SQL. Currently, I have a Python script that processes the data into DOT language (and I can display the graph with the layout that I want using Graphviz), so that's why I'm using the .convertDot method. I could re-process the network after being imported into vis.js and add the correct "level" attribute to each node individually, but there must be a better way.

Here's the full HTML/JS document that I have so far:

<!DOCTYPE HTML>
<html>
<head>
  <script src="./vis/dist/vis.js"></script>
  <link href="./vis/dist/vis.css" rel="stylesheet" type="text/css" />
</head>

<body>
<div id="graph", style="height: 1000px"></div> 

  <script> 
    // provide data in the DOT language
    var DOTstring = 'digraph {"13332500" -> "13483400" "13567500" -> "13483400" "10037901" -> "10037902" "10037902" -> "13483400" "15038400" -> "13455700" "13455700" -> "13455702" "13455702" -> "13483400" "13567300" -> "13483400" "11890500" -> "13483400" "13483400" -> "13554900"}';
    var parsedData = vis.network.convertDot(DOTstring);

    var data = {
      nodes: parsedData.nodes,
      edges: parsedData.edges
    }

    var container = document.getElementById('graph');
    var options = parsedData.options;

    // you can extend the options like a normal JSON variable:
    options.layout = {
      "hierarchical": true
    }

    // create a network
    var network = new vis.Network(container, data, options);
  </script>

</body>
</html>

Here's what the code will produce: a graph made by vis.js And here's the layout that I'm looking for, as produced by graphviz: a graph made by graphviz

In case you're wondering why I'm trying to do this in vis.js when I already have it working in graphviz: the reason is I want to make it interactive.


Solution

  • As of vis.js version 6.2, there is a new option that allows the graph to be displayed as desired. Use sortMethod: 'directed' and shakeTowards: 'roots'.

    Sources

    Example

    Modifying options.layout in my original script gives the desired result:

    <!DOCTYPE HTML>
    <html>
    <head>
      <script src="./vis/dist/vis.js"></script>
      <link href="./vis/dist/vis.css" rel="stylesheet" type="text/css" />
    </head>
    
    <body>
    <div id="graph", style="height: 1000px"></div> 
    
      <script> 
        // provide data in the DOT language
        var DOTstring = 'digraph {"13332500" -> "13483400" "13567500" -> "13483400" "10037901" -> "10037902" "10037902" -> "13483400" "15038400" -> "13455700" "13455700" -> "13455702" "13455702" -> "13483400" "13567300" -> "13483400" "11890500" -> "13483400" "13483400" -> "13554900"}';
        var parsedData = vis.network.convertDot(DOTstring);
    
        var data = {
          nodes: parsedData.nodes,
          edges: parsedData.edges
        }
    
        var container = document.getElementById('graph');
        var options = parsedData.options;
    
        // you can extend the options like a normal JSON variable:
        options.layout = {
          hierarchical: {
            sortMethod: 'directed',  // hubsize, directed
            shakeTowards: 'roots',  // roots, leaves
            direction: 'DU'   // UD, DU, LR, RL
            }
        }
        
        // create a network
        var network = new vis.Network(container, data, options);
      </script>
    
    </body>
    </html>
    

    hierarchical network graph fixed