Using GraphViz to visualize property graphs
To properly document our new project, I was trying to find a programmatic way to statically visualize property graphs. I stumbled upon GraphViz and the DOT family of languages which are fairly simple but powerful tools.
By “fairly simple” I mean compared to LaTex and ConTexT used with Tikz & PGF. If I had time to learn it I would because it is really powerful — just take a look at the examples at TeXample.net. Although these people are not kidding about the steep learning curve: the TikZ manual is 880 pages long, and it is “just” a module.
Again, GraphViz is more rudimentary but the above graph output only required minor tweaks. (Time will tell though how more complex property graphs could be rendered. This post will be updated with lessons learned.)
The DOT language is straightforward with only a handful of keywords but the GraphViz attributes can be a confusing bunch. The best way for me was to learn through examples (search results to Stackoverflow posts mostly.) as the attribute descriptions can be too vague.
Graph height and width
For example, there is a height
and a width
attribute but these are to alter the dimensions of a node. This Stackoverflow post has very clear examples on how to use the proper attributes: nodesep
and ranksep
.
Positioning edge labels
There is the lp
(i.e., label position) attribute but I wasn’t able to figure out how it works and I used the solutions in this Stackoverflow answer instead.
The relationship between label
and headlabel
, taillabel
is similar to the CSS box model positioning:
label
is fixed to the edge and it can be quite off when there are multiple parallel edges with labels. It is not a very format-friendly attribute (and there is no way that it could follow the curves of an edge as in TikZ)- but
headlabel
andtaillabel
are, used in conjunction with the modifierslabeldistance
andlabelangle
. They detach the label from the edge and the label can be positioned relative to the edge endpoint that meets with the head or the tail.
Ordering nodes into specific columns
My problem was that my address graph model had cycles in it plus I wanted the nodes to be in a specific order. In contrast, as the DOT guide states, “the layout procedure used by dot relies on the graph being acyclic” and so it “assigns nodes to discrete ranks or levels” during the rendering process.
Here is a simplified version of the graph at the top:
Without the lines
{rank=same; A; kilgore; logan; }
{rank=same; B; unit1; unit2; }
{rank=same; C; street1; street2; }
it would look like this:
Semantically they are both the same but I had a shape in mind that requires less tracing. This example and these helped a lot to figure it out.
(1) Just create a straight (named or anonym) subgraph in the needed length,
digraph G {
rankdir=LR;
node [shape=record]; { a->b->c->d->e; }
}
(2) make all the “ordering” graph’s nodes and edges invisible
digraph G {
rankdir=LR;
node [shape=record]; {
node [style="invis"];
edge [style="invis"];
a->b->c->d->e;
}
}
(3) and assign the main nodes to a specific node in the subgraph that has the right rank.
So kilgore and logan would go with a
,
{ rank=same, a; kilgore; logan;}
apt and another_apt would go with b
, { rank=same, b; apt; another_apt;}
and so on.
This would create a raster effectively:
Try it out
Here are some extra examples and the webgraphviz website was an invaluable help to prototype.
Try it out by using the code below:
Or use dot -Tsvg first.gv -o first.svg
from the command line. (Provided that your filename is first.gv
).