# Smaller roofs for forest

I have the following tree. I want the roofs to be as wide as the text not wider. Is there a way to do this with forest? In particular it should be the width of the upper text. This is important in cases in which the translation is much wider than the original text. The roof should fit the original text since this is what is analyzed, the translation is extra and logically not part of the structure.

\documentclass{minimal}

\usepackage{forest}

\forestset{
sn edges/.style={for tree={parent anchor=south, child anchor=north,align=center,base=bottom,where n children=0{tier=word}{}}},
background tree/.style={for tree={text opacity=0.2,draw opacity=0.2,edge={draw opacity=0.2}}}
}

\begin{document}

\begin{forest}
sn edges
[NP
[Det [das\\the] ]
[N'
[N'
[N [Bild\\picture] ]
[PP [vom Gleimtunnel\\of.the Gleimtunnel,triangle ] ] ]
[PP [im Gropiusbau\\in.the Gropiusbau,triangle ] ] ] ]
\end{forest}

\end{document}


Edit: There is an almost perfect solution by Sašo below. However, one problem remains. I defined a command \tracewhich I want to use in trees. If I use it with the translation code, I get the following error:

! Argument of \@rsbox has an extra }.
<inserted text>
\par
l.45 \end{forest}

?


This is the code:

\documentclass{minimal}

\usepackage{forest}

\forestset{
with translation/.style={
l sep=0,inner xsep=0,
append translation/.expanded/.wrap pgfmath arg={\gettranslation{##1}}{content},
content/.expanded/.wrap pgfmath arg={\gettext{##1}}{content},
},
append translation/.style={append={[#1,no edge,l=0,inner xsep=0,inner ysep=0,outer ysep=0,before
computing xy={l-=2pt}]}},
sn edges/.style={for tree={parent anchor=south, child anchor=north,align=center,base=top},
where n children=0{tier=word,delay=with translation}{} %,delay=with translation
}
}

\def\gettext#1{\gettextA#1;;\endget}
\def\gettextA#1;#2;{\removesep#1;}
\def\gettranslation#1{\gettranslationA#1;;\endget}
\def\gettranslationA#1;#2;{\removesep#2;}
\def\removesep#1;#2\endget{#1}

\newcommand{\trace}{\raisebox{0.2ex}{\_}\rule{0cm}{0.7em}}

\begin{document}

\begin{forest}
sn edges
[NP
[Det [eine;a] ]
[N$'$
[A [kluge;smart] ]
[N$'$
[N [\trace ] ] ] ] ]
\end{forest}

\end{document}

\end{forest}


Is there a way to allow such commands in translated trees?

• What is the definition of \nbar?
– user2478
Mar 27, 2014 at 9:13
• Sorry this is just an N with overline. Replaced it by the typewriter version N'. Mar 27, 2014 at 9:28
• Please, don't use the minimal class for examples; it's not meant for this purpose. Prefer article. Mar 27, 2014 at 10:16
• The width of the triangle is based on the width of the node which is determined by the width of the longest line in the node. So I don't think there's a simple way to do this. Mar 27, 2014 at 12:02
• Couldn't one define a new primitive similar to triangle but with other properties. Or a version of triangle that one can pass a string to which can be used to determine the size? I would prefer this over editing trees and putting separation commands in as in the solution by Gonzalo Medina. We want to use these macros also for unexperienced users and having them chose distances might be problematic. Mar 27, 2014 at 14:40

Below, I used a trick shown in the big example in the forest manual (section 4.2) to parse the content of the node. Then, (i) an additional node is created just below the text and filled with the translation (i.e whatever comes after \\ in the original content) and (ii) the translation is deleted from the content. (This parsing mechanism is set to apply to all leaves of the tree.)

Also, tikz's inner xsep is set to 0 for the text and translation nodes, so that the triangles tightly fit the text.

Edit: the code is changed to accept nodes without translations. However, I was only able to do this with a simpler separator; below, ; is used.

Second edit: .expanded handlers in styles append translation and content were replaced by a chain of .expand once and .expand twice to deal with the additional problem posed by \trace (see OP's edited question).

\documentclass{minimal}
\usepackage{forest}

\forestset{
with translation/.style={
l sep=0,inner xsep=0,
append translation/.expand once/.expand twice/.wrap pgfmath arg={\gettranslation{##1}}{content},
content/.expand once/.expand twice/.wrap pgfmath arg={\gettext{##1}}{content},
},
append translation/.style={append={[#1,no edge,l=0,inner xsep=0,inner ysep=0,outer ysep=0,before
computing xy={l-=2pt}]}},
sn edges/.style={for tree={parent anchor=south, child anchor=north,align=center,base=top},
if n children=0{tier=word,delay=with translation}{} %,delay=with translation
}
}

\def\gettext#1{\gettextA#1;;\endget}
\def\gettextA#1;#2;{\removesep#1;}
\def\gettranslation#1{\gettranslationA#1;;\endget}
\def\gettranslationA#1;#2;{\removesep#2;}
\def\removesep#1;#2\endget{#1}

\newcommand{\trace}{\raisebox{0.2ex}{\_}\rule{0cm}{0.7em}}
\begin{document}

\begin{forest}
sn edges,
[NP
[Det [das] ]
[N'
[N'
[N [Bild;picture] ]
[PP [vom Gleimtunnel;of.the Gleimtunnel,triangle]] ] ]
[PP [im Gropiusbau;in.the Gropiusbau,triangle ] ] ] ]
\end{forest}

\begin{forest}
sn edges
[NP
[Det [eine;a] ]
[N$'$
[A [kluge;smart] ]
[N$'$
[N [\trace ] ] ] ] ]
\end{forest}

\end{document}


Third edit: changed where n children=0 within the definition of sn edges to the logically more correct if n children=0. While this makes no difference (except running more slowly) in the current (v1.0.10) version of the package, the where n children version produces a wrong result in the (upcoming) v1.1 of the package. This is so because v1.1 fixes a bug with delay. In v1.0.x, when delay was used more than once on a single node, the first invocation was forgotten. The wrong version of the above code thus works in v1.0.x despite the fact that delay=with translation is called more than once. In v1.1, where calling delay=with translation three times actually calls with translation (later) three times, this results in superfluous empty nodes.

• Thanks! This is very cool! There is one tiny remaining problem: If some or all words are not glossed, LaTeX complains. If one has abstract elements in the tree that are not glossed, such situations could arise. Oct 9, 2014 at 15:53

One option:

\documentclass{article}
\usepackage{forest}

\forestset{
sn edges/.style={for tree={parent anchor=south, child anchor=north,align=center,base=bottom,where n children=0{tier=word,inner xsep=0pt,outer sep=0pt}{}}},
background tree/.style={for tree={text opacity=0.2,draw opacity=0.2,edge={draw opacity=0.2}}}
}

\newcommand\HideWd[1]{%
\makebox[0pt]{#1}%
}

\begin{document}

The default behaviour:\par
\begin{forest}
sn edges,
[NP
[Det [das\\the] ]
[N',s sep=20pt
[N',s sep=15pt
[N [Bild\\picture] ]
[PP [vom Gleimtunnel\\ of.the Gleimtunnel,triangle ] ] ]
[PP [im Gropiusbau\\ in.the Gropiusbau,triangle ] ] ] ]
\end{forest}

Hiding the wider text:\par
\begin{forest}
sn edges,
[NP
[Det [das\\the] ]
[N'
[N'
[N [Bild\\picture] ]
[PP [vom Gleimtunnel\\ \HideWd{of.the Gleimtunnel},triangle ] ] ]
[PP [im Gropiusbau\\ \HideWd{in.the Gropiusbau},triangle ] ] ] ]
\end{forest}

Hiding the wider text and correcting the separation:\par
\begin{forest}
sn edges,
[NP
[Det [das\\the] ]
[N',s sep=20pt
[N',s sep=15pt
[N [Bild\\picture] ]
[PP [vom Gleimtunnel\\ \HideWd{of.the Gleimtunnel},triangle ] ] ]
[PP [im Gropiusbau\\ \HideWd{in.the Gropiusbau},triangle ] ] ] ]
\end{forest}

\end{document}


The idea is to use a box having 0pt width to "hide" the wider text (this is what the \HideWd command does); this, however, will have an undesired effect in the calculation of the distance between the siblings affected (see second tree in the image), so some manual intervention will be needed to provide some appropriate values for s sep (see the third three in the image).

• Thanks! In another question (tex.stackexchange.com/questions/204770/…) I learned that one can pass parameters to annotation of node and set a default value. So wouldn't it be possible to pass a certain length to the triangle annotation and the tree layout would work as usual but the triangle would be drawn according to this length? Even better: One could just pass the string along and let the triangle code determine its length. I am asking because I have lots of such trees ... Thanks! =:-) Oct 9, 2014 at 13:28

This is an answer to the edited question concerning the problem combining the code given in Sašo Živanović's answer with the use of a custom macro.

The trick is to replace the use of \trace in the tree with a new style, trace which executes the macro and overrides the application of with translation to nodes with 0 children.

\documentclass[tikz, border=5pt]{standalone}
\usepackage{forest}
\forestset{
sn edges/.style={for tree={parent anchor=south, child anchor=north,align=center,base=top}, for tree={where n children=0{tier=word, delay=with translation}{}}},
trace/.style={
replace by={[\trace, delay={}, tier=word]}
},
with translation/.style={
l sep=0,
inner xsep=0,
append translation/.expanded/.wrap pgfmath arg={\gettranslation{##1}}{content},
content/.expanded/.wrap pgfmath arg={\gettext{##1}}{content},
},
append translation/.style={
append={
[
#1,
no edge,
l=0,
inner xsep=0,
inner ysep=0,
outer ysep=0,
before computing xy={
l-=2pt
}
]
},
},
}

\def\gettext#1{\gettextA#1;;\endget}
\def\gettextA#1;#2;{\removesep#1;}
\def\gettranslation#1{\gettranslationA#1;;\endget}
\def\gettranslationA#1;#2;{\removesep#2;}
\def\removesep#1;#2\endget{#1}

\newcommand{\trace}{\raisebox{0.2ex}{\_}\rule{0cm}{0.7em}}

\begin{document}

\begin{forest}
sn edges
[NP
[Det [eine;a] ]
[N$'$
[A [kluge;smart] ]
[N$'$
[N [, trace ] ] ] ] ]
\end{forest}

\end{document}