As Qrrbrbirlbel explains forest
can be used with a phantom
root, and offers flexible options for specifying the tree layout.
Specifying l sep
and s sep
does not, however, guarantee that the centre child will be aligned with the parent. If the node contents are of different widths, this is likely to fail:
\begin{forest}
for tree={
l sep=1cm,
s sep=1cm,
draw,
align=center
}
[,phantom
[
[some text here]
[a multiline node\\in the middle]
[not much]
]
[
[this\\node\\needs\\five\\lines]
[this\\one\\only\\four]
[finally\\just\\three]
]
]
\end{forest}
This happens because the s sep
specifies only the minimum distance. It would be possible to force s
to a certain value, which would set the distance. However, it would be better to allow forest
to figure out the best value and just give it some hints about what we want it to do. calign with current
tells forest
to align the current child with its parent and is just what is wanted in this case.
\begin{forest}
for tree={
draw,
if={isodd(n_children())}{
for children={
if={
equal(n,int((1+n_children("!u"))/2))
}{calign with current}{}
}
}{},
align=center
}
[,phantom
[
[some text here]
[a multiline node\\in the middle]
[not much]
]
[
[this\\node\\needs\\five\\lines]
[this\\one\\only\\four]
[finally\\just\\three]
]
]
\end{forest}
This works by testing to see if a node has an odd number of children. If it does, then the centre child is aligned with its parent:
It would be better, however, if the edge from the parent went to the north of the child rather than crossing the nodes. Adding child anchor=north
achieves this:
If the root nodes also contain content and this content has different heights in the two cases, the vertical alignment will be thrown:
To avoid this, we can use tier
to ensure that all nodes at a given level are aligned vertically. Adding tier/.wrap pgfmath arg={tier #1}{level()}
, we get the following:
The complete code:
\documentclass[tikz,border=5pt,multi]{standalone}
\usepackage{forest}
\standaloneenv{forest}
\begin{document}
\begin{forest}
for tree={
draw,
if={isodd(n_children())}{
for children={
if={
equal(n,int((1+n_children("!u"))/2))
}{calign with current}{}
}
}{},
align=center,
child anchor=north,
tier/.wrap pgfmath arg={tier #1}{level()}
}
[,phantom
[left tree\\(needs additional explanation)
[some text here]
[a multiline node\\in the middle]
[not much]
]
[right tree
[this\\node\\needs\\five\\lines]
[this\\one\\only\\four]
[finally\\just\\three]
]
]
\end{forest}
\end{document}
Applied to the original tree with empty nodes, this also produces a more compact result:
\documentclass[tikz,border=5pt,multi]{standalone}
\usepackage{forest}
\standaloneenv{forest}
\begin{document}
\begin{forest}
for tree={
draw,
if={isodd(n_children())}{
for children={
if={
equal(n,int((1+n_children("!u"))/2))
}{calign with current}{}
}
}{},
align=center,
child anchor=north,
tier/.wrap pgfmath arg={tier #1}{level()}
}
[,phantom
[
[]
[]
[]
]
[
[]
[]
[]
]
]
\end{forest}
\end{document}