# Drawing a Decision Diagram with Tikz and layout manager

I'm trying to draw decision diagrams (DD) in an automated fashion. A DD is a DAG, where all nodes are partitioned in layers. Edges typically go from a node in layer l to another node in layer l+1. Each edge has a label, and there can be multiple edges between the same pair of nodes. Two example DDs can be found below. These are drawn by manually specifying all coordinates of all nodes. Since I need to draw a large number of those, I'd like to automate this. Therefore I'm using the layout manager of tikz. Here's an example:

\RequirePackage{luatex85}
\documentclass{standalone}

\usepackage{tikz}
\usetikzlibrary{graphs,graphdrawing,quotes}
\usegdlibrary{layered}

\begin{document}
\begin{tikzpicture}[rounded corners]
\graph [layered layout,
edge quotes={fill=white,inner sep=1pt,font=\scriptsize,pos=0.2},
nodes={circle,draw,inner sep=.1,outer sep=0, minimum size=.35cm},
level sep=1cm
]
{
r ->["a"] 1,
r ->["b"] 0,
r ->["c"] 2,
r ->["d"] 3,
3 ->["e"] 4,
1 ->["f"] 4,
1 ->["g"] 6,
0 ->["h"] 4,
0 ->["i"] 5,
0 ->["j"] 6,
2 ->["k"] 6,
4 ->["l"] t,
5 ->["m"] t,
6 ->["n"] t;
};
\end{tikzpicture}
\end{document}


The above code works pretty well, especially since I can specify each arc individually. Next I'm looking for a way to do the following:

1. how to specify the vertical space between layers? Answer: use level sep=2cm
2. how to draw multiple edges between the same pair of nodes? In the right most figure, you see nodes with 2 edges, e.g. v2,v4. There can be more than 2 edges between the same pair of nodes. The edges must be drawn non-overlapping. E.g. what if I had 10 edges with different labels between the same pair of nodes?
3. Next to the left most graph, there are labels pi_1, pi_2. These labels are vertically aligned and are next to the edges. How do I add those?

Note: I'm not looking to exactly replicate the graphs in the figure. Something else that is aesthetically pleasing is good enough. • For (2), it is pretty easy if you use pure TikZ: just draw one or two curves from a node to another. With positioning (3) is also not difficult to achieve. However, drawing such weighted graphs is very painful with pure TikZ.
– user156344
Mar 29, 2019 at 9:15
• @JouleV I've no idea how to get (3) done. The graph nodes are on their own layers. The labels pi_1, pi_2 etc are in between layers. Mar 29, 2019 at 11:53
• @JorisKinable I have absolutely zero experience with your approach, so I can do nothing. I just said that using normal TikZ, we can have (3) done quite easily if we already have the graph.
– user156344
Mar 29, 2019 at 11:55

It depends a bit on what you want. If you just want to add extra bent arrows and pi's, that's easy.

\documentclass{standalone}

\usepackage{tikz}
\usetikzlibrary{graphs,graphdrawing,quotes}
\usegdlibrary{layered}
\begin{document}
\begin{tikzpicture}[rounded corners]
\begin{scope}[local bounding box=graph]
\graph [layered layout,
edge quotes={auto,inner sep=1pt,font=\scriptsize},
nodes={circle,draw,inner sep=.1,outer sep=0, minimum size=.35cm},
level sep=1cm
]
{
r ->["a"] 1,
r ->["b"] 0,
r ->["c"] 2,
r ->["d"] 3,
3 ->["e"] 4,
1 ->["f"] 4,
1 ->["g"] 6,
0 ->["h"] 4,
0 ->["i"] 5,
0 ->["j"] 6,
2 ->["k"] 6,
4 ->["l"] t,
5 ->["m"] t,
6 ->["n"] t;
};
\begin{scope}[nodes={auto,inner sep=1pt,font=\scriptsize}]
\draw[->] (r) to[bend left,"$c'$"] (2);
\end{scope}
\path (r) -- (3) coordinate[pos=0.5] (p1)
(3) -- (4) coordinate[pos=0.5] (p2) (4) -- (t) coordinate[pos=0.5] (p3);
\end{scope}
\foreach \X in {1,2,3}
{\node at ([xshift=-1cm]graph.west|-p\X) {$\pi_{\X}$}; }
\end{tikzpicture}
\end{document} The nice thing about this is that the output is close to the screen shot, the not-so-nice part that you need to issue many commands of the sort \draw[->] (r) to[bend left,"$c'$"] (2); (which can be shortened somewhat using edges).

If you want a more automatic version, then the following may provide a starting point.

\documentclass{standalone}

\usepackage{tikz}
\usetikzlibrary{graphs,graphdrawing,quotes}
\usetikzlibrary{decorations.pathreplacing}
\usegdlibrary{layered}
\tikzset{extra bent arrow/.style={decoration={show path construction,
lineto code={
\draw (\tikzinputsegmentfirst) to[bend left=40,#1]
(\tikzinputsegmentlast);
}},postaction=decorate},
extra straight arrow/.style={decoration={show path construction,
curveto code={
\draw (\tikzinputsegmentfirst) -- node[pos=0.5,auto,font=\scriptsize]{#1}
(\tikzinputsegmentlast);
}},postaction=decorate}}
\begin{document}
\begin{tikzpicture}[rounded corners]
\begin{scope}[local bounding box=graph]
\graph [layered layout,
edge quotes={auto,inner sep=1pt,font=\scriptsize},
nodes={circle,draw,inner sep=.1,outer sep=0, minimum size=.35cm},
level sep=1cm
]
{
r ->["a"] 1,
r ->["b"] 0,
r ->[bend left,"c",extra straight arrow=c1] 2,
r ->["d"] 3,
3 ->["e"] 4,
1 ->["f"] 4,
1 ->["g"] 6,
0 ->["h"] 4,
0 ->["i"] 5,
0 ->["j"] 6,
2 ->["k"] 6,
4 ->["l"] t,
5 ->["m"] t,
6 ->["n"] t;
};
\path (r) -- (3) coordinate[pos=0.5] (p1)
(3) -- (4) coordinate[pos=0.5] (p2) (4) -- (t) coordinate[pos=0.5] (p3);
\end{scope}
\foreach \X in {1,2,3}
{\node at ([xshift=-1cm]graph.west|-p\X) {$\pi_{\X}$}; }
\end{tikzpicture}
\end{document} I chose that output as it shows the open issues: the line does not connect as nicely in the above picture, and it is harder to control the edge labels. Both issues can be resolved but this will be more effort.

• In your first approach, what makes that pi_1, pi_2 etc are vertically aligned? Mar 29, 2019 at 18:56
• @JorisKinable I place them relative to the local bounding box, which is, after all, a box with vertical edges.
– user121799
Mar 29, 2019 at 19:06

The following solution seems to work:

\RequirePackage{luatex85}
\documentclass{standalone}

\usepackage{tikz}
\usetikzlibrary{graphs,graphdrawing,quotes}
\usegdlibrary{layered}

\begin{document}
\begin{tikzpicture}[rounded corners]
\graph [layered layout,
edge quotes={fill=white,inner sep=1pt,font=\scriptsize},
nodes={circle,draw,inner sep=.1,outer sep=0, minimum size=.35cm},
level sep=1.5cm, %vertical distance between layers
sibling distance=2cm, %distance between nodes of the same connected component in the same layer
component sep=0cm %distance between connected components
]
{
{
[nodes={draw=none,text opacity=0}, edge={draw=none}]
l1 ->["$\pi_1$"] l2 ->["$\pi_2$"] l3 ->["$\pi_3$"] l4,
},
{
[edge={pos=.45}]
r ->["a"] 1,
r ->["b"] 0,
r ->["c"] 2,
r ->["c'",bend left=-20] 2,
r ->["c''",bend left=20] 2,
r ->["d"] 3,
3 ->["e"] 4,
1 ->["f"] 4,
1 ->["g"] 6,
0 ->["h"] 4,
0 ->["i"] 5,
0 ->["j"] 6,
2 ->["k"] 6,
4 ->["l"] t,
5 ->["m"] t,
6 ->["n"] t;
}
};
\end{tikzpicture}
\end{document}


The result: This solution draws the pi labels on the left hand side as a 2nd graph. The labels are automatically aligned.

• That looks indeed very simple and good. +1 (I didn't try this mainly because I was afraid that drawing too many connections will distort the graph too much, but it is not too bad, and will get better once you add multiple connections at other locations.)
– user121799
Mar 30, 2019 at 0:37
• I also tried adding [same layer] tags, since I know beforehand which nodes are supposed to end up in the same layer. Oddly, this wasn't helpful at all: the graph got really distorted. Simply omitting those tags significantly improved the quality of the graph. Mar 30, 2019 at 10:51