A quick primer on Graphviz

One of the tools I use to make figures for papers and books—if I need to make a graph, of course—is Graphviz. Graphviz is flexible, powerful, but also a rather finicky beast that will repeatedly bite your fingers. Today, I’ll share some of my tricks with you.

Graphviz uses a graph description language, the DOT language. Fairly simple, it does have its idiosyncrasies one must grok before getting anything really useful done. But let’s start at the beginning.

In Graphviz, a graph might be a graph, that is, an undirected graph, or a digraph, a directed graph. The first kind will have edges (links) between vertices (or nodes) that are just lines (possibly curvy). The second kind, the directed graph, will have edges that have a pointy end (you can define the style) that indicate direction of the edge. So a graph is either directed or not directed, contains vertices (nodes) and edges (links). Now remains to express connectivity—the list of links—between nodes.

Let’s start with something simple. We fill define nodes with labels, and links between the nodes. Here the double dash -- indicates an undirected link between two nodes.

```graph g {

node1 [label="1"]
node2 [label="2"]
node3 [label="3"]
node4 [label="4"]
node5 [label="5"]
node6 [label="6"]
node7 [label="7"]

node1 -- node2
node1 -- node3
node1 -- node4
node1 -- node5

node2 -- node3
node2 -- node4
node2 -- node6

node3 -- node4
node4 -- node5
node4 -- node7
node4 -- node6

node5 -- node7

}
```

Invoke neato:

```neato -T svg -o yourgraph.svg yourgraph.dot
```

This will create the following SVG (here converted to PNG):

So far, so good. It gave a somewhat decent layout, but it feels crude. Elliptic nodes, maybe too close together, a solid white background. Don’t worry. All of that is configurable.

You can change almost everything:

• Node aspect. You can specify other shapes, like square, circle, doublecircle, etc.. You can change its size, border color, its fill color, the style, size and color of the font used to render labels.
• Edge aspect. You can change its color, the shape of the arrowheads, and the width of the line.
• Background. You can specify the background color you want, even using alpha (transparency).

Let’s look at an example:

```
graph g {

bgcolor="#ffffff00" # RGBA (with alpha)
splines=true # use splines for edges, if needed to avoid overlap
overlap=scale # (try to) stretch everything if edges overlap

node [shape=circle,
fixedsize=true, # don't allow nodes to change sizes dynamically
width=0.25, # relative to the underlying coordinate grid?
color="black", # node border color (X11 or HTML colors)
fillcolor=white, # node fill color (X11 or HTML colors)
style="filled,solid",
fontcolor=darkred, # text color (X11 or HTML colors)
fontsize=12]

edge [ penwidth=0.75, color=black ]

node1 [label="1"]
node2 [label="2"]
node3 [label="3"]
node4 [label="4"]
node5 [label="5"]
node6 [label="6"]
node7 [label="7"]

node1 -- node2
node1 -- node3
node1 -- node4
node1 -- node5

node2 -- node3
node2 -- node4
node2 -- node6

node3 -- node4
node4 -- node5
node4 -- node7
node4 -- node6

node5 -- node7

}
```

This source will output

For directed graph, we replace the graph keyword by digraph and -- links by -> links. With -> links, the first node is the initial node of the link and the second its terminal node and, yes, the order is important. n1->n2 yields an edge with the arrowhead by n2, and n2->n1 will put the arrowhead at n1. Starting from the previous example:

```digraph g {

bgcolor="#ffffff00" # RGBA (with alpha)
splines=true
overlap=scale

node [shape=circle,
fixedsize=true,
width=0.25,
color="black", # node border color (X11 or HTML colors)
fillcolor=white, # node fill color (X11 or HTML colors)
style="filled,solid",
fontcolor=darkred, # text color (X11 or HTML colors)
fontsize=12]

edge [ penwidth=0.75, color=black ]

node1 [label="1"]
node2 [label="2"]
node3 [label="3"]
node4 [label="4"]
node5 [label="5"]
node6 [label="6"]
node7 [label="7"]

node1 -> node2
node1 -> node3
node1 -> node4
node1 -> node5

node2 -> node3
node2 -> node4
node2 -> node6

node3 -> node4
node4 -> node5
node4 -> node7
node4 -> node6

node5 -> node7

}
```

Invoking neato on it will give you the following graph:

*
* *

Graphviz also knows about clusters, which allows you, to a limited extent, to control how nodes are placed, but also to delimit explicitly parts of your graph. For example:

```graph g {

bgcolor="#ffffff00"
overlap=scale

layout=fdp

start=2
edge [penwidth=0.75,arrowsize=0.6]
edge [color=black, fontsize=8, forcelabels=true]

node [shape=circle,
fixedsize=true,
width=0.25,
color="black",
fillcolor="white",
style="filled,solid",
fontsize=12];

node1 [label="s₁"] # u+2081 (yes, it can do unicode!)
node2 [label="s₂"]
node3 [label="s₃"]
node4 [label="t₁",pos="0,0"]
node5 [label="t₂",pos="0,1"]
node6 [label="t₃",pos="1,1"]
node7 [label="t₄",pos="1,0"]

subgraph clusterG0 {
label="G∪T" # union u+222a

subgraph clusterG1 {
label="G"
bgcolor=white
node1--node2
node2--node3
node3--node1
}

node3--node6[style=dashed,penwidth=1]

subgraph clusterG2 {
label="H"
bgcolor=white
node4--node5
node5--node6
node6--node4
node6--node7
}
}

}
```

Outputs:

But beware! The cluster names must be of the form clusterxyz otherwise Graphviz does not recognize them. Why? No Idea.

*
* *

There are other commands than neato you can invoke, depending of the specific type of graph you want. If you want a flowchart-type graph, you may invoke dot, fdp or fsdp, if you’d rather have a radial-type graph, you’d invoke twopi. However, caveat emptor, they’re all pretty as finicky as the others.

*
* *

Another big limitation of neato and its friend is stability. Progressively adding nodes does not make the graph grow in a stable fashion, even if the graph is planar. Adding one node may suddenly transform the graph layout so that basically nothing is at the same place!

To avoid that, we can either suggest or force node placement using the pos="..." option. For example:

```graph g {

ratio=fill
splines=spline
overlap=scale

node [shape=circle,
fixedsize=true,
width=0.3,
color="black",
fillcolor="#eeeeee",
style="filled,solid",
fontsize=12]

q0 [label="0", xlabel="000", pos="0,0"]
q1 [label="1", xlabel="001", pos="0,1"]
q2 [label="2", xlabel="010", pos="1,0"]
q3 [label="3", xlabel="011", pos="1,1"]

q4 [label="4", xlabel="100", pos="-0.5,-0.5"]
q5 [label="5", xlabel="101", pos="-0.5,0.5"]
q6 [label="6", xlabel="110", pos="0.5,-0.5"]
q7 [label="7", xlabel="111", pos="0.5,0.5"]

q0--q1
q0--q2
q1--q3
q2--q3

q4--q5
q4--q6
q5--q7
q6--q7

q0--q4
q1--q5
q2--q6
q3--q7
}
```

will suggest placement. It yields:

If you end your position with a bang !, Graphviz will treat the position as absolute, and place nodes exactly were you want them. However, it’s difficult to get natural-looking graphs this way.

*
* *

Graphviz is a really great tool to draw all kinds of graph. Here, I’ve shown a few example drawn from my discrete math lecture notes. I must admit that while I tried to make it sound like it was easy to produce these graphs with Graphviz, you should be warned that instability will likely cause you problems. Graphviz has also difficulty figuring out a graph is planar and drawing it like so. You will more than likely have to place a good number of nodes manually to make your planar graph… planar.

Despite these limitations, Graphviz is a really great tool I have used before and will use again.

One Response to A quick primer on Graphviz

1. […] // Bibliography : gviz : GraphVizで立方体図形を描いている例　cool! […]