Graphviz is a very hand graph vizualization tool. And since every problem is a graph problem in disguise, it's a handy tool to have in your arsenal. I will discuss the Dot Graphviz renderer (there are many)
The basic syntax is fairly simple, but can be highly configurable. Graphs are defined by listing their edges.
graph example01 {
NODE_1 -- NODE_2;
NODE_1 -- NODE_3;
NODE_2 -- NODE_3;
}
Despite the simplicity, and the generally good defaults, here are some common tweaks that you might need.
By default, graphs are layed out top-to-bottom in the order nodes are specified. But you can add
rankdir=LR
grapha ttribute to force a left-to-right layout. This can make the graph more legible if you add
edge labels.
graph example02 {
rankdir=LR;
NODE_1 -- NODE_2;
NODE_1 -- NODE_3;
}
You do not have control of node placement. The goal here isn't to produce a perfect diagram a la TikZ, it's to produce a decent diagram that gets the point across with minimal effort.
Notice that the nodes were split into two ranks (columns).
digraph example03 {
NODE_1 -> NODE_2;
NODE_1 -> NODE_3;
NODE_3 -> NODE_2;
}
Notice here that there are three ranks.
You can use the
nodesep
and
ranksep
graph parameters to set the distance between nodes and ranks respectively. Units are in inches.
digraph example04 {
ranksep=0.5;
NODE_1 -> NODE_3;
NODE_2 -> NODE_3;
}
Note that the
ranksep
is the
vertical
distance between the horizontal ranks.
digraph example05 {
ranksep=0.75;
NODE_1 -> NODE_3;
NODE_2 -> NODE_3;
}
digraph example06 {
nodesep=1;
NODE_1 -> NODE_3;
NODE_2 -> NODE_3;
}
Notice that
nodesep
also applies to the distance between ranks, but that this distance is measured from node to
node.
Perhaps ovals aren't your thing. See
https://graphviz.org/doc/info/shapes.html
for the different node shapes you can use. Note that
record
shapes are special, and are how you can build things like tables or arrays.
digraph example07 {
node [shape=box] NODE_2;
// The node keyword is optional.
NODE_1 [shape=circle];
// Sets default node shape.
node [shape=square];
NODE_1 -> NODE_2 -> NODE_3;
NODE_1 -> NODE_4;
}
A very common thing you'll want to do is to add labels to your nodes and edges
digraph example08 {
rankdir=LR;
ranksep=0.75;
nodesep=0.5;
node [shape=point] START;
node [shape=doublecircle] INITIAL;
node [shape=circle];
START -> INITIAL [label="startup"];
INITIAL -> STATE_1 [label="event a\naction 1"];
INITIAL -> STATE_2 [label="event b\naction 2"];
STATE_1 -> STATE_1 [label="event c"];
}
digraph example09 {
rankdir=LR;
node [shape=point] START;
node [shape=doublecircle] INITIAL;
node [shape=circle];
START -> INITIAL;
INITIAL -> STATE_1;
STATE_1 -> STATE_2 [color=blue];
STATE_1 -> STATE_3 [style=dashed];
// quotes necessary when specifying multiple colors.
STATE_2 -> STATE_3 [color="black:red:black"];
STATE_3 -> STATE_3;
}
digraph example10 {
rankdir=LR;
subgraph cluster_1 {
node [style=box];
color=red;
label="process 1";
a1 -> a2 -> a3;
}
subgraph cluster_2 {
node [style=dashed];
label="process 2";
b1 -> b2;
}
// Shorthand for start -> a1; start -> b1;
start -> {a1, b1};
{a3, b2} -> end;
}
This is very handy for prototyping Graphviz diagrams. Use
dot -Tx11 <filename>
to run the live preview in an X11 window. The preview is regenerated every time the given file
is written to. Note that the zooming is a bit touchy; use
<ctrl-scroll>
to zoom to/from the cursor.
Use
dot -Tsvg -o <output> <input>
. Or you can use
-Tpng
if you
really
want to.
This is one of the things that makes Graphviz really quite powerful as a design tool. You can embed your design directly in the source code where the desgin is implemented. This makes it easier to update the diagrams when you refactor (something that should be caught in code review).
Include the Graphviz code wrapped between
@dot
and
@enddot
Doxygen tags. You can also use
@dotfile
to read the diagram from a
*.dot
file saved in the
DOTFILES_DIRS
configuration variable.