Reading DOT files in javascript/d3
Asked Answered
G

4

36

Is there a standard way to read and parse DOT graph files in javascript, ideally in way that will work nicely in d3?

Currently, the only thing I can think of doing is reading plain text and doing my own parsing. Hopefully this'd be reinventing the wheel though.

d3.text("graph.dot", function(error, dotGraph) {
    ....
)};
Gunter answered 23/3, 2014 at 18:56 Comment(2)
Have you seen graphlib-dot?Reprise
Yeah, but haven't been able to get it to work..Gunter
I
43

⚠ Solution proposed here depends on two libraries marked as unsupported by their authors.

To get Graphviz DOT files rendered in Javascript, combine the graphlib-dot and dagre-d3 libraries.

The graphlibDot.read() method takes a graph or digraph definition in DOT syntax and produces a graph object. The dagreD3.render() method can then output this graph object to SVG.

You can then use additional D3 methods to add functionality to the graph, retrieving additional node and edge attributes from the graphlib graph object as needed.

A trivial self-contained example is:

window.onload = function() {
  // Parse the DOT syntax into a graphlib object.
  var g = graphlibDot.read(
    'digraph {\n' +
    '    a -> b;\n' +
    '    }'
  )

  // Render the graphlib object using d3.
  var render = new dagreD3.render();
  render(d3.select("svg g"), g);


  // Optional - resize the SVG element based on the contents.
  var svg = document.querySelector('#graphContainer');
  var bbox = svg.getBBox();
  svg.style.width = bbox.width + 40.0 + "px";
  svg.style.height = bbox.height + 40.0 + "px";
}
svg {
  overflow: hidden;
}
.node rect {
  stroke: #333;
  stroke-width: 1.5px;
  fill: #fff;
}
.edgeLabel rect {
  fill: #fff;
}
.edgePath {
  stroke: #333;
  stroke-width: 1.5px;
  fill: none;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://dagrejs.github.io/project/graphlib-dot/v0.6.4/graphlib-dot.min.js"></script>
<script src="https://dagrejs.github.io/project/dagre-d3/v0.5.0/dagre-d3.min.js"></script>

<html>

<body>
  <script type='text/javascript'>
  </script>
  <svg id="graphContainer">
    <g/>
  </svg>
</body>

</html>
Imparipinnate answered 14/7, 2014 at 12:19 Comment(6)
This looks great! I'm having a problem with your example though.. my graph is larger than my screen, and there are no scrollbars to pan around.. is there an easy way to fix that?Gunter
You need to set the width and height of your SVG element. I haven't found a really good way of setting these automatically from the graph content, so I currently set them to really large values, or use trial and error.Imparipinnate
My graphs are generated dynamically, so it would definitely be nice to figure them out from content.. I'll let you know if I figure something out!Gunter
I've got something working in Firefox and Chrome, but haven't tested it extensively. After rendering the graph, call getBBox() on your SVG element to get the bounding box of the contents, then set the style.width and style.height attributes based on the bounding box plus any padding. I will update the example to reflect this.Imparipinnate
Great! How do you change var g to read from a file? is it something lie: fs.readFileSync('graph.dot', 'UTF-8')?Steer
@Steer that's a different question. I suggest you try a few things, see what problems you run into, search for solutions and ask another question if you don't find an answer.Imparipinnate
C
12

Late to the party, but if you're still interested, here's a way to do it with the new d3-graphviz plug-in that I just released:

<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="https://d3js.org/d3.v7.js"></script>
<script src="https://unpkg.com/@hpcc-js/[email protected]/dist/graphviz.umd.js"></script>
<script src="https://unpkg.com/d3-graphviz@5/build/d3-graphviz.js"></script>
<div id="graph" style="text-align: center;"></div>
<script>

d3.select("#graph").graphviz()
    .renderDot('digraph  {a -> b}');

</script>

EDIT 2024-07-27: Updated the example to the latest d3-graphviz version and use https exclusively.

Culbertson answered 10/8, 2017 at 14:5 Comment(2)
@Culbertson will your library also read json?Stover
@Stover No, it can only read DOT source files.Culbertson
P
4

Same example, using latest version of graphlib-dot and dagre-d3.

window.onload = function() {
      // Parse the DOT syntax into a graphlib object.
      var g = graphlibDot.read(
        'digraph {\n' +
        '    a -> b;\n' +
        '    }'
      )

      // Render the graphlib object using d3.
      var renderer = dagreD3.render();
      d3.select("svg g").call(renderer, g);


      // Optional - resize the SVG element based on the contents.
      var svg = document.querySelector('#graphContainer');
      var bbox = svg.getBBox();
      svg.style.width = bbox.width + 40.0 + "px";
      svg.style.height = bbox.height + 40.0 + "px";
    }
svg {
  overflow: hidden;
}
.node rect {
  stroke: #333;
  stroke-width: 1.5px;
  fill: #fff;
}
.edgeLabel rect {
  fill: #fff;
}
.edgePath {
  stroke: #333;
  stroke-width: 1.5px;
  fill: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="http://cpettitt.github.io/project/graphlib-dot/latest/graphlib-dot.min.js"></script>
<script src="http://cpettitt.github.io/project/dagre-d3/latest/dagre-d3.js"></script>

    <html>

    <body>
      <script type='text/javascript'>
      </script>
      <svg id="graphContainer">
        <g/>
      </svg>
    </body>

    </html>
Piccard answered 25/10, 2016 at 13:34 Comment(1)
This updated code works, but the svg rendering of the DOT file output is very dependent on the parse order of the Nodes and Edges. The older versions seemed to render the DOT file without issue.Emlen
M
4

The question asks for a possibility to visualise .dot files einther in javascript or D3js. I think the solution from the highest rated answer will work for most of you.

I was unhappy because of these 3 reasons:

  1. It involves libraries like lowdash, dagre and graphlib additionally to D3js and is heavyweight.
  2. Parser output is not a D3js "friedly" data-structure.
  3. Usage (API) in not D3js style.

That's why I created an adapter which will basically allow you to use .dot files with any of thousands of D3js samples by changing just one statement. If you have some D3js visualisation working on following data-structure:

{
  "nodes": [ {"id": "Myriel"}, {"id": "Napoleon"}],
  "links": [ {"source": "Myriel"}, {"target": "Napoleon"}]
} 

Just include following script and call d3.dot:

<script src="https://cdn.jsdelivr.net/gh/gmamaladze/[email protected]/build/d3-dot-graph.min.js"></script>
<script>

d3.dot(url, function(graph) {
   ...
});

</script>

instead of:

d3.json(url, function(graph) {...});

GitHub repository with code and examples

Marcelmarcela answered 1/9, 2017 at 14:34 Comment(1)
This is exactly what I was looking for. I'm amazed that there's 2.5k lines of code in this. Brilliant stuff - I'm going to give it a try and talk about it to others if it works because many of the other routes I have tried, as you say, involve zillions of dependencies. This deserves wider 'visibility' ;-)Slippery

© 2022 - 2024 — McMap. All rights reserved.