Is there a way to automatically draw curved edges using tikz's algorithmic graph drawing?

I can easily draw automatically-laid out trees in tikz, but with straight edges between nodes. I'd like for edges to be automatically curved similar to this tree drawing software: https://mindnode.com. An example is:

Approximately Desired Image

With tikz, I can draw the below but is there any way for it to automatically bend/curve edges for aesthetics / saving space? Can one also colorize siblings / descendants automatically without implementing a custom Lua drawing script?

Tikz Image:

Code:

\RequirePackage{luatex85}
\documentclass[tikz,border=10pt]{standalone}
\usetikzlibrary{graphdrawing}
\usetikzlibrary{graphs}
\usegdlibrary{trees}
\begin{document}
\begin{tikzpicture}[>=, every node/.style={rectangle, draw, anchor=west, minimum size=0.75cm}]
\graph [tree layout, grow'=right, fresh nodes, tail anchor=east, head
anchor=west, level sep=0.5in, sibling distance=0.5in]
{
Root -> {
a -> {d, e, f},
b -> {g, h},
c -> {i -> {l, m}, j, k}
}
};
\end{tikzpicture}
\end{document}


Thanks for any help!

• use \draw [->] (a) to [out=0, in=180] (b); see slide 40 at computational-logic.org/content/study/master/documents/… – Julian_W Dec 5 '17 at 16:48
• Welcome to TeX.SX! – Bobyandbob Dec 5 '17 at 16:50
• @Julian_W: Thanks, but per Section 27.1 of the Tikz manual, latest, 3.0.1.a In the graphdrawing package, you cannot use \draw inside \graph because (as I understand) node creation is deferred. My goal is to maintain the concise -> syntax, just have curved edges handled by automatic layout, if that makes sense? – menger Dec 5 '17 at 17:18
• Have you considered Forest? – cfr Dec 5 '17 at 23:19

You can do at least some of this with the graph-drawing facilities. Probably, use of color classes would facilitate greater automation. However, I'm not immediately sure how to make that work and the manual is extremely vague on what is possible and how. (Or I just don't understand its approach - I admit to finding the graph-drawing stuff almost entirely opaque.)

Here's an example:

\RequirePackage{luatex85}
\documentclass[tikz,border=10pt]{standalone}
\usetikzlibrary{graphdrawing,graphs}
\usegdlibrary{trees}
\begin{document}
\begin{tikzpicture}
[>=, every node/.style={rectangle, draw, anchor=west, minimum size=0.75cm}, line width=1pt]
\graph [tree layout, simple, grow'=right, level sep=0.5in, sibling distance=0.5in]
{
Root -> {
a ->[draw=cyan] {d, e, f},
b ->[draw=blue] {g, h},
c ->[draw=green] {i -> {l, m}, j, k}
};
i -> [bend left, green] l;
i -> [bend right, green] m;
Root -> [bend left, cyan] a;
Root -> [blue] b;
Root -> [bend right, green] c;
a -> [bend left, cyan] d;
a -> [bend right, cyan] f;
b -> [bend left, blue] g;
b -> [bend right, blue] h;
c -> [bend left, green] i;
c -> [bend right, green] k;
};
\end{tikzpicture}
\end{document}


Personally, I wouldn't bother with the graph-drawing stuff for drawing trees. If you need arbitrary graphs, it is different - options are very limited. But trees have lots of support from specialised packages, many of which support very concise syntax, albeit not the same syntax as the graph-drawing stuff provided by TikZ.

For example, with Forest, I can define a style - tracks, say - which allows me to write

\begin{forest}
tracks
[Root
[a, colour me down=cyan!50!blue [d][e][f] ]
[b, colour me down=blue [g][h] ]
[c, colour me down=green!75!black [i [l][m] ][j][k] ]
]
\end{forest}


to produce

which is particularly useful if you need to use a style for many trees. The colouring could be built into the style, but I assumed this was more likely to vary than other elements, so just used a simple convenience wrapper for use in specifying colouring for a particular tree.

In this case, the colouring is specified for each of the root's children and automatically propagated to each child's descendants.

\documentclass[tikz,border=10pt]{standalone}
\usepackage{forest}
\usetikzlibrary{calc}
\forestset{
tracks/.style={
for tree={
grow'=0,
l sep'+=50pt,
s sep'+=30pt,
font=\bfseries\sffamily,
edge path'={
(!u.parent anchor) -- ($(.child anchor)-(20pt,0pt)$) -- (.child anchor)
},
edge+={ultra thick, rounded corners}
},
before typesetting nodes={
for descendants={
edge label/.process={ Ow {content} {node [above, font=\bfseries\sffamily, anchor=south, pos=.75] {##1}} },
content=,
shape=coordinate,
},
where={>Ow+P {n children} {isodd(##1)} }{
calign=child edge,
calign primary child/.process={ Ow+n {n children} {(##1+1)/2} }
}{}
},
},
colour me/.style={
#1,
edge+={#1},
},
colour me down/.style={
for tree={colour me=#1},
}
}
\begin{document}
\begin{forest}
tracks
[Root
[a, colour me down=cyan!50!blue [d][e][f] ]
[b, colour me down=blue [g][h] ]
[c, colour me down=green!75!black [i [l][m] ][j][k] ]
]
\end{forest}
\end{document}

• If you don't want the labels coloured, but only the edges, use edge+={draw=#1} rather than edge+={#1} in the colour me style and maybe delete the previous line containing #1. – cfr Dec 6 '17 at 0:26
• Hmm, so in the first example, still using graphdrawing, bending could be done automatically if we could glean the information of whether the child was within the first n/2 (bend left), last n/2 (bend right) or == n/2 (don't bend) children. I know graphdrawing defers graph creation so perhaps this is possible... As for your second example, I can't get it to compile when I include tracks within the forest definition, error: "Illegal parameter number in definition of \pgf@temp <to be read again> 1 1.44 \end{forest}." If I remove the tracks line after \begin{forest} it works, though... – menger Dec 6 '17 at 19:10
• @menger I don't really understand what you did which didn't work. Does the example work as-is for you? If you don't use a style, but include the style definition in the tree, you need to adjust the argument specifiers. Use of .style doubles the hashes, so removing the definition from .style requires halving them. However, I'm not sure if that's what you did or not. I recommend keeping the style out of the forest environment in most cases, because some modifications are possible only if some stuff is set outside forest and it is generally easier to keep stuff together. At least, for me. – cfr Dec 6 '17 at 23:24
• @menger I don't know whether you can detect that with the graph-drawing stuff or not. I don't really have an understanding of how graph-drawing works in TikZ. I can do certain things, but it is mostly beyond my ken :(. In particular, I don't find the documentation terribly helpful - it suggests experiments, but it takes lots of trial-and-error for me to figure out even quite simple things. Probably just me, of course. – cfr Dec 6 '17 at 23:27

You are welcome :) could be a little more automated and also needs some finetuning, but I gotta go for now. Feedback is also welcome!

\RequirePackage{luatex85}
\documentclass[tikz,border=10pt]{standalone}
\usetikzlibrary{graphdrawing}
\usetikzlibrary{graphs}
\usegdlibrary{trees}
\usetikzlibrary{shapes.misc, positioning}
\begin{document}
\begin{tikzpicture}[xscale=0.5,yscale=0.5]

\fill[black!20!white] (0,0) rectangle (16,11);

\coordinate (root) at (2,5);

\coordinate (a) at (6,8);
\coordinate (d) at (10,9);
\coordinate (e) at (10,8);
\coordinate (f) at (10,7);
\coordinate (b) at (6,5);
\coordinate (g) at (10,5.5);
\coordinate (h) at (10,4.5);
\coordinate (c) at (6,2);
\coordinate (i) at (10,3);
\coordinate (l) at (13,3.5);
\coordinate (m) at (13,2.5);
\coordinate (j) at (10,2);
\coordinate (k) at (10,1);

\node [above=0.05of a] {a};
\node [above=0.05of d] {d};
\node [above=0.05of e] {e};
\node [above=0.05of f] {f};
\node [above=0.05of b] {b};
\node [above=0.05of g] {g};
\node [above=0.05of h] {h};
\node [above=0.05of c] {c};
\node [above=0.05of i] {i};
\node [above=0.05of l] {l};
\node [above=0.05of m] {m};
\node [above=0.05of j] {j};
\node [above=0.05of k] {k};

\draw [out=45, in=180,line width = 0.1cm,blue] (root) to (a);
\draw [out=0, in=180,line width = 0.1cm,blue!40!white](root) to (b);
\draw [out=-45, in=180,line width = 0.1cm,green](root) to (c);

\draw [out=0, in=180,line width = 0.1cm,blue!90!white](a) to (d) -- ++(2,0);
\draw [out=0, in=180,line width = 0.1cm,blue!90!white](a) to (e) -- ++(2,0);
\draw [out=0, in=180,line width = 0.1cm,blue!90!white](a) to (f) -- ++(2,0);

\draw [out=0, in=180,line width = 0.1cm,blue!40!white](b) to (g) -- ++(2,0);
\draw [out=0, in=180,line width = 0.1cm,blue!40!white](b) to (h) -- ++(2,0);

\draw [out=0, in=180,line width = 0.1cm,green](c) to (i);
\draw [out=0, in=180,line width = 0.1cm,green](c) to (j) -- ++(2,0);
\draw [out=0, in=180,line width = 0.1cm,green](c) to (k) -- ++(2,0);

\draw [out=0, in=180,line width = 0.1cm,green](i) to (l) -- ++(2,0);
\draw [out=0, in=180,line width = 0.1cm,green](i) to (m) -- ++(2,0);

\node at (root) [fill=white, rounded rectangle] {Root};

\end{tikzpicture}

\end{document}

• As it is, commenting out \RequirePackage{luatex85}, \usetikzlibrary{graphdrawing} and \usegdlibrary{trees} your code compiles without issue under pdfLaTeX. I would streamline the code a bit by using some TikZ styles. – sgmoye Dec 5 '17 at 17:58
• \coordinate [label=above:a] (a) at (x,y); would spare you the trouble of having both a \coordinate and a \node. And as all the to-paths have the same in angle, you could set \begin{tikzpicture}[in=180,...] – Torbjørn T. Dec 6 '17 at 8:06
• Thank you; this is helpful! But my goal is to maintain concise syntax and not think about coordinates. – menger Dec 6 '17 at 19:06
• I prefer styling before automation, but thats my personal taste I guess. Also usually the automated version usually needs some manual tweaking. – Julian_W Dec 6 '17 at 19:29