Getting Started With Graphviz and Python
Getting Started With Graphviz and Python
Getting Started With Graphviz and Python
Python
Hello Graphviz
First we need to import the graphviz module:
import graphviz as gv
Now we can create the graph object g1 and add two nodes A and B as well as an edge to
connect the two.
g1 = gv.Graph(format='svg')
g1.node('A')
g1.node('B')
g1.edge('A', 'B')
Let's have a look at the the dot code that this will generate behind the scenes:
print(g1.source)
graph {
A -- B
}
That looks about right. Now it's time to save the graph to disk:
filename = g1.render(filename='img/g1')
print filename
img/g1.svg
As you can see, the graphviz module takes care of appending the correct file extension.
Let's have a look at the result:
A
Directed Graphs
To create a directed version of the previous graph we only need to replace the Graph object
with a Digraph.
g2 = gv.Digraph(format='svg')
g2.node('A')
g2.node('B')
g2.edge('A', 'B')
g2.render('img/g2')
import functools
g3 = graph()
Next, we would like to specify the nodes and edges as simple data structures instead
typing loads of method calls.
Every node is represented by either a string or a tuple. In the latter case the second
element of the tuple holds all attributes of that node as we will see later. The represenation
of edges is quite similar:
edges = [
('A', 'B'),
('B', 'C'),
To actually create nodes and edges from these data structures we implement the
functions add_nodes and add_edges. Note that both functions return the updated graph
which will come in handy in just a second.
for n in nodes:
if isinstance(n, tuple):
graph.node(n[0], **n[1])
else:
graph.node(n)
return graph
for e in edges:
if isinstance(e[0], tuple):
graph.edge(*e[0], **e[1])
else:
graph.edge(*e)
return graph
add_edges(
).render('img/g4')
Labels
Labeling nodes and edges is as easy as adding an entry to their dictionaries of attributes.
add_edges(
add_nodes(digraph(), [
'C'
]),
('B', 'C')
).render('img/g5')
Node A
Edge 1
No de B Edge 2
C
Styling
Graphviz let's you style graphs extensively by setting specific attributes. The following
example will showcase a few of these attributes.
For a complete list of attributes please refer to http://www.graphviz.org/doc/info/attrs.html.
First, let's create an unstyled graph:
g6 = add_edges(
add_nodes(digraph(), [
'C'
]),
('B', 'C')
We will use a simple dictionary to specifiy the attributes that we want to change:
styles = {
'graph': {
'fontsize': '16',
'fontcolor': 'white',
'bgcolor': '#333333',
'rankdir': 'BT',
},
'nodes': {
'fontname': 'Helvetica',
'shape': 'hexagon',
'fontcolor': 'white',
'color': 'white',
'style': 'filled',
'fillcolor': '#006699',
},
'edges': {
'style': 'dashed',
'color': 'white',
'arrowhead': 'open',
'fontname': 'Courier',
'fontsize': '12',
'fontcolor': 'white',
Now we need another helper function apply_styles to actually apply those attributes to the
graph:
graph.graph_attr.update(
graph.node_attr.update(
graph.edge_attr.update(
('edges' in styles and styles['edges']) or {}
return graph
g6 = apply_styles(g6, styles)
g6.render('img/g6')
Node B Edge 2
Edge 1
Node A
A Fancy Graph
Subgraphs
Lastly, we will have a look a subgraphs. First, let's create two seperate graphs g7 and g8,
each with their own styling.
g7 = add_edges(
add_nodes(digraph(), [
'C'
]),
('B', 'C')
g8 = apply_styles(
add_edges(
add_nodes(digraph(), [
'F'
]),
('E', 'F')
),
'nodes': {
'shape': 'square',
'style': 'filled',
'fillcolor': '#cccccc',
Now we combine the two graphs by making g8 a subgraph of g7 and adding an extra edge
to connect the two:
g7.subgraph(g8)
g7.render('img/g7')
Node A
Edge 1
Edge 3
C Node E Edge 4
What's next?
Head over to GitHub to get the complete source code.
Improve or extend the script and let me know what you've come up with.
Learn more about Graphviz and the Dot
language: http://www.graphviz.org/pdf/dotguide.pdf.
2014 by matthiaseisen.com