Forest: Customized edge between parent and grandchildren, when the child node is missing
I don't know what the extended version of the question was as the question now is an answer rather than a question.
For this reason, my aim was to do two things:
answer the non-extended question;
reproduce the result in the extended answer-question.
Basically, I want to propose something much simpler, which does not require drawing anything in, doesn't require a variant on the forked edges
style (though it does use a wrapper around the original version of the style) and let's you specify the missing nodes as just empty nodes.
In addition, the assignment of tier
s is automated and the use of relative anchors makes the code a bit more flexible.
The wrapper style is called, very boringly, my tree
and is defined thus:
\forestset{
my tree/.style={
forked edges,
Note that forked edges
should not be within the scope of for tree
. Either use forked edge
within that scope or, as here, keep forked edges
outside it.
for tree={
grow'=0,
draw,
text width=10mm,
minimum height=5mm,
text centered,
tier/.option=level,
This automates the levels, since the level completely determines the desired tier.
},
delay={
where content={}{content=\phantom{X},draw=none, child anchor=children}{}
If you want to miss a node, leave the node empty. This code will then add a phantom X
(to save messing around trying to figure out the right height to give it - apparently the other nodes exceed the 5mm
minimum). The node will have the standard assigned width, but won't be drawn. Changing the child anchor
, however, has the effect of making it look as if no node is there. Essentially, this runs the branch from the parent all the way through the centre of the node, which is just what would happen if you had a coordinate on the far side, rather than a regular width node.
In some cases, you need a coordinate, but here, it's easier not to go that route. If you really want true coordinate
s rather than look-alikes, I would just move the coordinate later in before drawing tree
.
},
},
}
That's it.
Now, we can write
\begin{forest}
my tree
[A
[B1
[
[D1
[E1]
[E2]
]
[D2
[E3]
[E4]
]
]
]
[B2
[C2
[D3
[E5]
[E6]
]
[D4
[E7]
[E8]
]
]
]
]
\end{forest}
\begin{forest}
my tree,
[A
[B1
[
[D1
[E1]
[E2]
]
[D2
[E3]
[E4]
]
[D3
[E5]
[E6]
]
]
[
[D4
[E7]
[E8]
]
[
[E9]
[E10]
]
]
]
[B2
[C3
[D6
[E11]
[E12]
]
[D7
[E13]
[E14]
]
]
]
]
\end{forest}
to produce
\documentclass[12pt,border=10pt]{standalone}
\usepackage[edges]{forest}
\forestset{
my tree/.style={
forked edges,
for tree={
grow'=0,
draw,
text width=10mm,
minimum height=5mm,
text centered,
tier/.option=level,
},
delay={
where content={}{content=\phantom{X},draw=none, child anchor=children}{}
},
},
}
\begin{document}
\begin{forest}
my tree
[A
[B1
[
[D1
[E1]
[E2]
]
[D2
[E3]
[E4]
]
]
]
[B2
[C2
[D3
[E5]
[E6]
]
[D4
[E7]
[E8]
]
]
]
]
\end{forest}
\begin{forest}
my tree,
[A
[B1
[
[D1
[E1]
[E2]
]
[D2
[E3]
[E4]
]
[D3
[E5]
[E6]
]
]
[
[D4
[E7]
[E8]
]
[
[E9]
[E10]
]
]
]
[B2
[C3
[D6
[E11]
[E12]
]
[D7
[E13]
[E14]
]
]
]
]
\end{forest}
\end{document}
I am not a forest expert but I could look up the definition of the forked edges in the forest manual and use it to define a "new" version in which the distance of the fork to the children (rather than parent) is fixed. EDIT: Moved the my forked edges
out of for tree
, big thanks to @cfr!
\documentclass[12pt,crop=true,border=1cm]{standalone}
\usepackage[edges]{forest}
%\usetikzlibrary{calc}
\forestset{
declare dimen={my fork sep}{0.5em},
my forked edge'/.style={
edge={rotate/.option=!parent.grow},
edge path'={let \noexpand\p1=($(.child anchor)-(!u.parent anchor)$) in
(!u.parent anchor) -- ++(\noexpand\x1-\forestoption{my fork sep},0) |- (.child anchor)},
},
my forked edge/.style={
on invalid={fake}{!parent.parent anchor=children},
child anchor=parent,
my forked edge',
},
my forked edges/.style={for nodewalk={#1}{my forked edge}},
my forked edges/.default=tree,
}
\begin{document}
\begin{forest}
my forked edges,
for tree={
grow'=0,
draw,
my fork sep=8pt,
text width=10mm,
minimum height=5mm,
parent anchor=east,
child anchor=west,
text centered,
}
[A,tier=level1
[B1,tier=level2,name=B1
% [C1 would be here, but it is missing
[D1,tier=level4,name=D1
[E1,tier=level5]
[E2,tier=level5]
]
[D2,tier=level4,name=D2
[E3,tier=level5]
[E4,tier=level5]
]
% ]
]
[B2,tier=level2
[C2,tier=level3
[D3,tier=level4
[E5,tier=level5]
[E6,tier=level5]
]
[D4,tier=level4
[E7,tier=level5]
[E8,tier=level5]
]
]
]
]
\end{forest}
\end{document}