More Graphing with Graphviz
I started working on Prim’s Minimum Spanning tree algorithm again. Last time, I wanted to ‘see’ the input graph so I can determine the final value.
This time, I needed help debugging my implementation and wanted to graph the algorithm’s progress. Graphing the algorithm’s progress was a lot more work and I want to share some details and tips.
Tools I used to display the algorithm’s progress:
Graphviz is a fantastic tool. As I use it more and understand the ins and outs of the tool, I am happy using a free and open source tool for graphing. Graphviz will do most of the graphing work.
ImageMagick another great tool. For this problem, I only use ImageMagick to put together images.
I constructed all the graphs with these basic primitives:
- Rendering with Dot
- Basic Graph
- Weight Highlight
- Node Highlight
- Source Node
- Additional Graphviz Tips
Rendering Graphs with Dot
To create the images from the graph file:
meaning | |
---|---|
dot | graphviz’s renderer using the dot engine |
-O | option to output the filename |
-Tpng | output file type: PNG |
*.dot | all the dot files generated |
Basic Graph
This basic graph representation is:
graph {
a [color = black]
b [color = black]
c [color = black]
d [color = black]
e [color = black]
a -- b [label="2"];
a -- d [label="6"];
b -- c [label="3"];
b -- d [label="8"];
b -- e [label="5"];
c -- e [label="7"];
d -- e [label="9"];
}
Weight Highlight
To highlight a weight, add: fontcolor=<color>
to the label:
graph {
a [color = black]
b [color = black]
c [color = black]
d [color = black]
e [color = black]
a -- b [label="2" fontcolor=red];
a -- d [label="6"];
b -- c [label="3"];
b -- d [label="8"];
b -- e [label="5"];
c -- e [label="7"];
d -- e [label="9"];
}
Node Highlight
To highlight the node, change the: color=<color>
in the node info:
graph {
a [color = red]
b [color = red]
c [color = black]
d [color = black]
e [color = black]
a -- b [label="2"];
a -- d [label="6"];
b -- c [label="3"];
b -- d [label="8"];
b -- e [label="5"];
c -- e [label="7"];
d -- e [label="9"];
}
Source Node
I use the attributes fillcolor=grey style=filled
to highlight the
source node by filling it to stand out from the other nodes:
graph {
a [color = black fillcolor=grey style=filled]
b [color = black]
c [color = black]
d [color = black]
e [color = black]
a -- b [label="2"];
a -- d [label="6"];
b -- c [label="3"];
b -- d [label="8"];
b -- e [label="5"];
c -- e [label="7"];
d -- e [label="9"];
}
Creating Animated Graphs
To animate the all images generated:
meaning | |
---|---|
convert | ImageMagick utility |
-delay | how long to show the image before the next one |
100 | delay in milliseconds |
loop | number of times to loop the sequence, 0 = infinity |
*.png | input file names ending in .png |
prims_mst.gif | output file name |
This combined with the basic attributes I animated Prim’s Minimum Spanning Tree algorithm:
Whew! What a lot of work to just see what’s going on inside Prim’s Minimum Spanning Tree algorithm.
Additional Graphviz Tips
Things I also learned in Graphviz while working on this problem.
Same Nodes, Different Order, Different Layout
Dot layout engine produces different graph layout with different input, even if the nodes are the same
- Graph 1:
graph { a -- b [label="2"]; a -- d [label="6"]; b -- c [label="3"]; b -- d [label="8"]; b -- e [label="5"]; c -- e [label="7"]; d -- e [label="9"]; }
- Graph 2:
graph { a -- d [label="6"]; a -- b [label="2"]; b -- d [label="8"]; b -- c [label="3"]; c -- e [label="7"]; b -- e [label="5"]; d -- e [label="9"]; }
![graph node order 1](https://www.dropbox.com/s/yo79q8xzd6plwzy/graph_node_order1.dot.png?raw=1 "Graph Node Order 1") | ![graph node order 2](https://www.dropbox.com/s/n4xudhijpzalczo/graph_node_order2.dot.png?raw=1 "Graph Node Order 2") |
Same Nodes, Same Order, Same Layout
Dot layout will be more consistent if nodes attributes appear at the beginning, in the same order, even with different attributes and/or order:
- Graph 1:
graph { a [color = black] b [color = black] c [color = black] d [color = black] e [color = black] a -- b [label="2"]; a -- d [label="6"]; b -- c [label="3"]; b -- d [label="8"]; b -- e [label="5"]; c -- e [label="7"]; d -- e [label="9"]; }
- Graph 2:
graph { a [color = red fillcolor=red style=filled] b [color = black] c [color = black] d [color = black] e [color = black] a -- b [label="2" fontcolor=red]; a -- d [label="6"]; b -- c [label="3"]; b -- d [label="8"]; b -- e [label="5"]; c -- e [label="7"]; d -- e [label="9"]; }
![graph pin node 1](https://www.dropbox.com/s/8rieh5oxoja2gfn/graph_pin_node1.nea.png?raw=1 "Graph Pin Node 1") | ![graph pin node 2](https://www.dropbox.com/s/fl2c1m5rztzgxyq/graph_pin_node2.nea.png?raw=1 "Graph Pin Node 2") |
Pinning Nodes
If it is absolutely necessary, nodes are pinnable to a location. Neato, another graphviz layout engine that works on undirected graphs, can place nodes a specified positions, even nodes appear in different order.
Neato takes the same arguments as dot:
-
Pinned Graph 1
graph { a [color = black pos="0,0!"] b [color = black pos="0,1!"] c [color = black pos="1,0!"] d [color = black pos="1,1!"] e [color = black pos="0,2!"] a -- b [label="2"]; a -- d [label="6"]; b -- c [label="3"]; b -- d [label="8"]; b -- e [label="5"]; c -- e [label="7"]; d -- e [label="9"]; }
-
Pinned Graph 2
graph { a [color = black pos="1,1!"] b [color = black pos="1,0!"] c [color = black pos="0,1!"] d [color = black pos="0,0!"] e [color = black pos="1,2!"] a -- b [label="2"]; a -- d [label="6"]; b -- c [label="3"]; b -- d [label="8"]; b -- e [label="5"]; c -- e [label="7"]; d -- e [label="9"]; }
![graph pin node 1](https://www.dropbox.com/s/8rieh5oxoja2gfn/graph_pin_node1.nea.png?raw=1 "Graph Pin Node 1") | ![graph pin node 2](https://www.dropbox.com/s/fl2c1m5rztzgxyq/graph_pin_node2.nea.png?raw=1 "Graph Pin Node 2") |
Clustering Nodes
Dot has a ‘cluster’ feature to outline a group of nodes:
graph {
a [color = red fillcolor=grey style=filled]
b [color = black]
c [color = black]
d [color = black]
e [color = black]
a -- b [label="2" fontcolor=red];
a -- d [label="6"];
b -- c [label="3"];
b -- d [label="8"];
b -- e [label="5"];
c -- e [label="7"];
d -- e [label="9"];
subgraph cluster_0 {
a -- b;
color = blue;
}
}
Conclusion
From this experience with Graphviz, I enjoy working with graph algorithms more. I like being able to see what is going on with the algorithm, not just the start or end result.
Developing and/or debugging a graphing algorithm is so much nicer to have visual representation than the final ‘weight’ value.
Next time I have to work with a graphing algorithm, I’ll use these to help visualize what is going on.