6

When horizontally aligning terminal nodes in trees using the package forest, I run into problems when I try to use the 'nice empty nodes' option, which makes sure that unlabeled nodes connect (this question relates to this one):

\documentclass{article}

\usepackage{forest}

\forestset{
 sn edges/.style={for tree={parent anchor=south, child anchor=north}},
 rectangle tree/.style={
 draw tree stage/.style={
 for root'={
   draw tree box=0,
   draw tree,
   TeX={\tikz{\node {\box0};}},
   }}},
   nice empty nodes/.style={
 for tree={calign=fixed edge angles},
 delay={where content={}{shape=coordinate,for parent={for children=   
{anchor=north}}}{}}
 }
 }

\begin{document}

\noindent Terminal nodes aligned on one line:

\begin{forest}  baseline, sn edges, rectangle tree, where n 
children=0{tier=word}{},

 [VP$_1$,   [read] [NP$_1$,  [the] [ [note] [PP$_1$ [on the table, 
triangle]]]]] 

\end{forest}

\ \\
This doesn't play nice with nice `nice empty nodes':

\begin{forest}  baseline, sn edges, rectangle tree, where n 
children=0{tier=word}{},

 [VP$_1$, nice empty nodes,  [read] [NP$_1$,  [the] [ [note] [PP$_1$ [on the    
table, triangle]]]]] 

\end{forest}


\end{document}

Output:

example trees

How can I fix this?

5
  • Welcome! The manual does indicate that tier.... may not always work. Although I would have thought it would here. Nonetheless, forest seems to get extremely confused no matter what I try. Your results are actually pretty good compared with what it seems to want to do in slightly variant cases! – cfr Aug 22 '15 at 2:57
  • 1
    This nice empty nodes/.style={ delay={where content={}{shape=coordinate}{}} } doesn't give such a nice final effect for the children of empty nodes, but at least tier works as expected. – Gonzalo Medina Aug 22 '15 at 4:45
  • @Gonzalo, thanks for your comment. The following returns what looks like the first tree again, so I think it doesn't fix the issue: \begin{forest} baseline, sn edges, rectangle tree, where n children=0{tier=word}{}, [VP$_1$, nice empty nodes/.style={ delay={where content={} {shape=coordinate}{}} }, [read] [NP$_1$, [the] [ [note] [PP$_1$ [on the table, triangle]]]]] \end{forest} – mchlmchl Aug 22 '15 at 15:37
  • What I meant was \documentclass{article} \usepackage{forest} \forestset{ sn edges/.style={for tree={parent anchor=south, child anchor=north}}, rectangle tree/.style={ draw tree stage/.style={ for root'={ draw tree box=0, draw tree, TeX={\tikz{\node {\box0};}}, }}}, nice empty nodes/.style={ delay={where content={}{shape=coordinate}{}} } } \begin{document} \begin{forest} baseline, sn edges, rectangle tree, where n children=0{tier=word}{}, [VP$_1$, nice empty nodes, [read] [NP$_1$, [the] [ [note] [PP$_1$ [on the table, triangle]]]]] \end{forest} \end{document} – Gonzalo Medina Aug 22 '15 at 16:01
  • I've delved into the code and I can confirm that this is a bug. I completely forgot about tier alignment when I was developing fixed (edge) angles calign method: it is the latter process that destroys the tier alignment. I'll see what I can do to fix this: the problem is harder than it seems ... – Sašo Živanović Aug 26 '15 at 10:45
4

Here's a solution which I think comes pretty close to what you want. It is not perfect, but it is hard for me, at least, to see the imperfections. Rather than nice empty nodes and sn edges, this uses pretty nice empty nodes because the empty nodes are not entirely nice, but they are pretty close.

This answer has two versions. The first is for version 2 of forest. The second is for version 1. If you use this code, please be sure to choose the appropriate version as neither will work with both versions of the package.


Forest v2

Rather than shape=coordinate, we set inner sep=0pt. We then alter the edge path so that child anchor=children. This avoids a tiny gap between the end of one edge and the start of the next. We also set parent anchor=children and calign=fixed edge angles for the tree but, crucially, we don't use child anchor=parent which causes things to go all over the place. (I'm not sure why, but it does.)

[For a south-growing tree, the parent anchor is north and the children anchor is south. But if you change the direction of growth, these will adapt accordingly. So these anchors are more flexible than hard-coding the direction as was required in version 1 of the package.]

This means that the lines are not quite straight when there is an empty node. But they are very nearly almost straight.

Here's the result:

pretty nice empty nodes 2

Here's the complete example:

\documentclass[tikz,border=10pt,multi]{standalone}
\usepackage{forest}
\useforestlibrary{linguistics}
\standaloneenv{forest}
\forestset{
  rectangle tree/.style={
    draw tree stage/.style={
      for root'={
        draw tree box=0,
        draw tree,
        TeX={
          \tikz{\node {\box0};}
        },
      }
    }
  },
  pretty nice empty nodes/.style={
    for tree={
      calign=fixed edge angles,
      parent anchor=children,
      delay={if content={}{
          inner sep=0pt,
          edge path={\noexpand\path [\forestoption{edge}] (!u.parent anchor) -- (.children)\forestoption{edge label};}
        }{}}
    }
  }
}
\begin{document}
\begin{forest}
 baseline,
 rectangle tree,
 where n children=0{
   tier=word
 }{},
 pretty nice empty nodes
 [VP$_1$
   [read]
   [NP$_1$,
     [the]
     [
       [note]
       [PP$_1$
         [on the table, roof]
       ]
     ]
    ]
  ]
\end{forest}
\end{document}

Forest v1

Rather than shape=coordinate, we set inner sep=0pt. We then alter the edge path so that child anchor=south. This avoids a tiny gap between the end of one edge and the start of the next. We also set parent anchor=south and calign=fixed edge angles for the tree but, crucially, we don't use child anchor=north which causes things to go all over the place. (I'm not sure why, but it does.)

This means that the lines are not quite straight when there is an empty node. But they are very nearly almost straight.

Here's the result:

pretty nice empty nodes

Here's the complete example:

\documentclass[tikz,border=10pt]{standalone}
\usepackage{forest}
\standaloneenv{forest}
\forestset{
  rectangle tree/.style={
    draw tree stage/.style={
      for root'={
        draw tree box=0,
        draw tree,
        TeX={
          \tikz{\node {\box0};}
        },
      }
    }
  },
  pretty nice empty nodes/.style={
    for tree={
      calign=fixed edge angles,
      parent anchor=south,
      delay={if content={}{
          inner sep=0pt,
          edge path={\noexpand\path [\forestoption{edge}] (!u.parent anchor) -- (.south)\forestoption{edge label};}
        }{}}
    }
  }
}
\begin{document}
\begin{forest}
 baseline,
 rectangle tree,
 where n children=0{
   tier=word
 }{},
 pretty nice empty nodes
 [VP$_1$
   [read]
   [NP$_1$,
     [the]
     [
       [note]
       [PP$_1$
         [on the table, triangle]
       ]
     ]
    ]
  ]
\end{forest}
\end{document}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.