# Drawing a collaboration graph or tree with TikZ

I'm trying to draw a collaboration graph for C data structures. originally I got dot files from Doxygen which I tried to convert using dot2tex with varying degrees of success, though none produced decent output (ie. no alignment, none of the typical "proper" look of well made TikZ diagrams). This kind of graph is similar to a dependency graph, except it contains references for each data structure link to the linked struct (in other words, an edge/path is connected between the pointer/reference field to the struct it references).

I would like to know if tikz-qtree could work for this purpose, since I want to optimize space usage and dot/graphvix/dot2tex (and manually tweaking the output) is suboptimal

Example of collaboration diagram:

The original dot syntax:

digraph G
{
edge [fontname="Helvetica",fontsize="10",labelfontname="Helvetica",labelfontsize="10"];
node [fontname="Helvetica",fontsize="10",shape=record];
Node1 [label="faultstate",height=0.2,width=0.4,color="black", fillcolor="grey75", style="filled" fontcolor="black"];
Node2 -> Node1 [dir="back",color="darkorchid3",fontsize="10",style="dashed",label=" entry" ,fontname="Helvetica"];
Node2 [label="vm_map_entry",height=0.2,width=0.4,color="black", fillcolor="white", style="filled",URL="$structvm__map__entry.html"]; Node2 -> Node2 [dir="back",color="darkorchid3",fontsize="10",style="dashed",label=" prev\nnext\nright\nleft" ,fontname="Helvetica"]; Node3 -> Node2 [dir="back",color="darkorchid3",fontsize="10",style="dashed",label=" object" ,fontname="Helvetica"]; Node3 [label="vm_map_object",height=0.2,width=0.4,color="black", fillcolor="white", style="filled",URL="$unionvm__map__object.html"];
Node4 -> Node3 [dir="back",color="darkorchid3",fontsize="10",style="dashed",label=" sub_map" ,fontname="Helvetica"];
Node4 [label="vm_map",height=0.2,width=0.4,color="black", fillcolor="white", style="filled",URL="$structvm__map.html"]; Node2 -> Node4 [dir="back",color="darkorchid3",fontsize="10",style="dashed",label=" root\nheader" ,fontname="Helvetica"]; Node5 -> Node3 [dir="back",color="darkorchid3",fontsize="10",style="dashed",label=" vm_object" ,fontname="Helvetica"]; Node5 [label="vm_object",height=0.2,width=0.4,color="black", fillcolor="white", style="filled",URL="$structvm__object.html"];
Node5 -> Node5 [dir="back",color="darkorchid3",fontsize="10",style="dashed",label=" backing_object" ,fontname="Helvetica"];
Node4 -> Node1 [dir="back",color="darkorchid3",fontsize="10",style="dashed",label=" map" ,fontname="Helvetica"];
Node5 -> Node1 [dir="back",color="darkorchid3",fontsize="10",style="dashed",label=" first_object\nobject" ,fontname="Helvetica"];
}


The converted TeX syntax (after dot to xdot intermediate conversion via graphviz's dot) from dot2tex (TikZ mode):

\documentclass{article}
\usepackage[x11names, rgb]{xcolor}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\usetikzlibrary{snakes,arrows,shapes}
\usepackage{amsmath}

\begin{document}
\pagestyle{empty}

\enlargethispage{100cm}
\begin{tikzpicture}[>=latex',line join=bevel,]
\node (Node1) at (28bp,10bp) [draw=black,fill=grey75,record] {faultstate};
\node (Node3) at (213bp,10bp) [draw=black,fill=white,record] {vm\_map\_object};
\node (Node2) at (65bp,178bp) [draw=black,fill=white,record] {vm\_map\_entry};
\node (Node5) at (140bp,88bp) [draw=black,fill=white,record] {vm\_object};
\node (Node4) at (65bp,88bp) [draw=black,fill=white,record] {vm\_map};
\draw [darkorchid3,<-,dashed] (Node3) ..controls (247.46bp,28.666bp) and (252.35bp,32.972bp)  .. (256bp,38bp) .. controls (258.83bp,41.907bp) and (274.89bp,84.957bp)  .. (266bp,98bp) .. controls (230bp,150.83bp) and (152.79bp,168.33bp)  .. (Node2);
\definecolor{strokecol}{rgb}{0.0,0.0,0.0};
\pgfsetstrokecolor{strokecol}
\draw (284bp,88bp) node { object};
\draw [darkorchid3,<-,dashed] (Node2) ..controls (120bp,183.99bp) and (123bp,181.48bp)  .. (123bp,178bp) .. controls (123bp,172.43bp) and (115.33bp,169.35bp)  .. (Node2);
\draw (134bp,190bp) node { prev};
\draw (134bp,179bp) node {next};
\draw (134bp,168bp) node {right};
\draw (134bp,157bp) node {left};
\draw [darkorchid3,<-,dashed] (Node2) ..controls (32.825bp,146.58bp) and (12.591bp,123.18bp)  .. (4bp,98bp) .. controls (-5.6625bp,69.676bp) and (12.453bp,35.188bp)  .. (Node1);
\draw (16.5bp,88bp) node { entry};
\draw [darkorchid3,<-,dashed] (Node5) ..controls (185.12bp,92.844bp) and (188bp,90.849bp)  .. (188bp,88bp) .. controls (188bp,83.324bp) and (180.25bp,80.95bp)  .. (Node5);
\draw (222.5bp,88bp) node { backing\_object};
\draw [darkorchid3,<-,dashed] (Node4) ..controls (35.128bp,68.878bp) and (31.433bp,64.745bp)  .. (29bp,60bp) .. controls (22.399bp,47.129bp) and (24.124bp,29.744bp)  .. (Node1);
\draw (40bp,49bp) node { map};
\draw [darkorchid3,<-,dashed] (Node5) ..controls (179.37bp,70.063bp) and (185.87bp,65.478bp)  .. (191bp,60bp) .. controls (201.97bp,48.297bp) and (208.13bp,30.2bp)  .. (Node3);
\draw (228.5bp,49bp) node { vm\_object};
\draw [darkorchid3,<-,dashed] (Node5) ..controls (131.95bp,58.339bp) and (126.18bp,45.94bp)  .. (117bp,38bp) .. controls (100.03bp,23.315bp) and (75.247bp,16.617bp)  .. (Node1);
\draw (158bp,50bp) node { first\_object};
\draw (158bp,39bp) node {object};
\draw [darkorchid3,<-,dashed] (Node4) ..controls (61.38bp,57.989bp) and (62.694bp,45.955bp)  .. (70bp,38bp) .. controls (83.331bp,23.486bp) and (133.52bp,16.635bp)  .. (Node3);
\draw (91.5bp,49bp) node { sub\_map};
\draw [darkorchid3,<-,dashed] (Node2) ..controls (65bp,139.31bp) and (65bp,111.67bp)  .. (Node4);
\draw (80bp,128bp) node { root};
\end{tikzpicture}
\end{document}


Output obtained:

Note: this is without --tikzedgelabels. Using the option yields a broken diagram. dot2tex likes straight edges only, so bent curves/edges connecting nodes don't play along.

Output wanted:

• No hideous \draw -(coordinate) constructs. I want TikZ-style edge labels and no fixed drawing points. I want the layout to be fluid and have optimal distribution of the diagram nodes in the canvas.

• --tikzedgelabels won't cut it. just a FYI, i can see it coming in the comments.

-
Can you show us an example of the output that you expect? Also it would be really good for us to see the non-working example that you didn't like. Can you make a small example, say only three nodes and add them to your question? So we can work on something tangible instead of guessing your problem. –  percusse Apr 12 '12 at 19:50
Done, vagueness removed. Please check. –  soze Apr 12 '12 at 20:58
I suggest you have a look at tikz cvs development version. Till Tantau is doing a huge work to make the whole graph/tree libs work with luatex. The results are quite impressive (sorry no compiled pdf version of the documentation yet, you are on your own here). –  cjorssen Apr 12 '12 at 21:32
Just a general tip: Use dashed lines only to highlight something special, not as the default line type. It makes the graph look much noisier than it should, without adding any information. –  Jake Apr 12 '12 at 21:39

Only an answer based on percusse's fine solution but with some modifications for the styles. I try to get a lighter code. I added a scope to use options for the labels. I removed pos=.5 because it's the value by default. I remove the style myline and I placed the options in the scope. I used the possibility to draw several edges from the same vertex with one path.

\documentclass{article}
\usepackage{tikz}
\begin{document}

\begin{tikzpicture}[ %some style declarations
mynode/.style = {draw,inner sep=2mm},
scale=1.5]

% Placing the nodes: you have to place them, no way to know beforehand
\node[fill=red,
mynode] (n0) at (0,0)   {faultstate};
\node[mynode] (n1) at (1,2)   {vm\_map};
\node[mynode] (n2) at (1,5)   {vm\_map\_entry};
\node[mynode] (n3) at (3.5,2) {vm\_object};
\node[mynode] (n4) at (5,0)   {vm\_map\_object};

%Now the edges and labels
\begin{scope}[> = stealth,  ->,blue,thick,
every node/.style = {black,right,align=center}]
\draw (n1) edge              node                 {root\\header}            (n2);
\draw (n0) edge [bend left]  node                 {entry}                   (n2)
edge [bend left]  node                 {map}                     (n1)
edge [bend right] node [pos=0.8,
below right]   {first\_object \\object}  (n3);
\draw (n4) edge [bend left]  node [pos=0.8]       {sub\_map}                (n1)
edge [bend right] node                 {vm\_object}              (n3);
\draw (n3) edge [loop right] node                 {backing\_object}         (n3);
\draw (n2) edge [loop right,
min distance =1 cm,
out=10,
in=-10]       node               {prev\\next\\right\\left} (n2)
edge [looseness=1.8,
out=30,
in=20]      node  [below left]   {object}                  (n4) ;
\end{scope}
\end{tikzpicture}
\end{document}


-
Beautiful code, I'm impressed. I will have to try with the real graph data now and see how it looks like. This one was only example information so I cannot use it as-is. On the other hand I am not totally convinced about the graph style itself, but collaboration graphs seem the right ones, or at least, better than a tree. How would it look like if we did this with a tree? Growing down the tree and then using the bottom to draw the connections between each entity? –  soze Apr 13 '12 at 18:14
I'm not sure if a tree is a good solution for this kind of graph. –  Alain Matthes Apr 13 '12 at 18:32

Here is something with lots of different options in action. You can then opt for some library with more specialization towards trees and graphs however I recommend getting used to the TikZ language first before such attempt.

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[>=stealth,%some style declarations
myline/.style={->,blue,thick,dashed},
mynode/.style={draw,inner sep=2mm},scale=1.5]
% Placing the nodes: you have to place them, no way to know beforehand
\node[mynode,fill=red] (n0) at (0,0) {faultstate};
\node[mynode] (n1) at (1,2) {vm\_map};
\node[mynode] (n2) at (1,5) {vm\_map\_entry};
\node[mynode] (n3) at (3.5,2) {vm\_object};
\node[mynode] (n4) at (5,0) {vm\_map\_object};
%Now the edges and labels
\draw[myline] (n0) edge[bend left] node[pos=0.5,black,right] {entry} (n2) ;
\draw[myline] (n0) edge[bend left] node[pos=0.5,black,right] {map} (n1);
\draw[myline] (n0) edge[bend right] node[pos=0.8,black,below right,align=center] {first\_object \\object} (n3);
\draw[myline] (n4) edge[bend left] node[pos=0.8,black,right] {sub\_map}(n1);
\draw[myline] (n4) edge[bend right] node[pos=0.5,black,right] {vm\_object} (n3) ;
\draw[myline] (n3) edge[loop right] node[pos=0.5,black,right] {backing\_object} () ;
\draw[myline] (n1) edge node[pos=0.5,black,right,align=center] {root\\header} (n2);
\draw[myline] (n2) edge[loop right,min distance =1 cm,out=10,in=-10] node[pos=0.5,black,right,align=center] {prev\\next\\right\\left} (n2) ;
\draw[myline] (n2) edge[out=30,in=20,looseness=1.8] node[pos=0.5,black,right] {object} (n4) ;
\end{tikzpicture}
\end{document}


After drawing, I used a 1.5 scaling to make it a little more open, it's not needed but looks better in my opinion.

-

My answer tries to explain why @soze got that strange result.

First of all, when in dot you define colors, you have to use the same syntax of xcolor, thus:

fillcolor="grey75" is wrong => fillcolor="gray!75"

color="darkorchid3" is wrong again => color="DarkOrchid3"

Another thing: the record shape gives me errors for each node, while using shape rectangle no problems occur.

I called graph.dot @soze file modified:

digraph G
{
edge [fontname="Helvetica",fontsize="10",labelfontname="Helvetica",labelfontsize="10"];
node [fontname="Helvetica",fontsize="10",shape=rectangle];
Node1 [label="faultstate",height=0.2,width=0.4,color="black", fillcolor="gray!75", style="filled" fontcolor="black"];
Node2 -> Node1 [dir="back",color="DarkOrchid3",fontsize="10",style="dashed",label=" entry" ,fontname="Helvetica"];
Node2 [label="vm_map_entry",height=0.2,width=0.4,color="black", fillcolor="white", style="filled",URL="$structvm__map__entry.html"]; Node2 -> Node2 [dir="back",color="DarkOrchid3",fontsize="10",style="dashed",label=" prev\nnext\nright\nleft" ,fontname="Helvetica"]; Node3 -> Node2 [dir="back",color="DarkOrchid3",fontsize="10",style="dashed",label=" object" ,fontname="Helvetica"]; Node3 [label="vm_map_object",height=0.2,width=0.4,color="black", fillcolor="white", style="filled",URL="$unionvm__map__object.html"];
Node4 -> Node3 [dir="back",color="DarkOrchid3",fontsize="10",style="dashed",label=" sub_map" ,fontname="Helvetica"];
Node4 [label="vm_map",height=0.2,width=0.4,color="black", fillcolor="white", style="filled",URL="$structvm__map.html"]; Node2 -> Node4 [dir="back",color="DarkOrchid3",fontsize="10",style="dashed",label=" root\nheader" ,fontname="Helvetica"]; Node5 -> Node3 [dir="back",color="DarkOrchid3",fontsize="10",style="dashed",label=" vm_object" ,fontname="Helvetica"]; Node5 [label="vm_object",height=0.2,width=0.4,color="black", fillcolor="white", style="filled",URL="$structvm__object.html"];
Node5 -> Node5 [dir="back",color="DarkOrchid3",fontsize="10",style="dashed",label=" backing_object" ,fontname="Helvetica"];
Node4 -> Node1 [dir="back",color="DarkOrchid3",fontsize="10",style="dashed",label=" map" ,fontname="Helvetica"];
Node5 -> Node1 [dir="back",color="DarkOrchid3",fontsize="10",style="dashed",label=" first_object\nobject" ,fontname="Helvetica"];
}


Compiling this with:

dot2tex -ftikz -tverbatim graph.dot > graph.tex
pdflatex graph.tex


I get (without errors):

-