4

I've written myself a custom style for forest, to get trees looking the way I'd like them to. The idea of the style is to keep the branches at a fixed angle, and automatically handle empty nodes "correctly" -- that is, to align lines symmetrically for empty head nodes and continue with unbroken lines for empty non-head nodes. The trouble is that the style I've written gives me the desired output, but also sometimes (unpredictably to me) gives me errors that are beyond my ability to troubleshoot.

The desired output looks more or less like this (although the branch for c is a tad short):

desired output

The style looks like this (with some code annotation to make things clearer):

default/.style={baseline, % align tree properly to example numbering
for tree={ %give every node in the tree these properties
parent anchor=south, child anchor=north, % make lines go from bottom of parent to top of child properly
calign=fixed edge angles,calign angle=60, % make all lines have the same angle
delay={ % do this stuff after processing how many nodes you have:
    where content={} % for all nodes with empty content...
        {if n children={0} % if they are heads...
            {content=\strut} % ...insert a strut;
            {shape=coordinate, % if they are not heads, make them points...
            for parent={for children={l*=0.8}} % <<If commented out, errors ensue!
            %for parent={for children={align=north,l*=0.8}} % <<If commented in, errors ensue!
            }
        }
        { % for all nodes with non-empty content:
        if n children={0} % if they are heads...
            { align=center } % allow line breaking; note that trying to allow line breaking for all nodes adds some weird extra space below the node text, and when TiKZ tries to put this extra space into the point nodes stuff explodes
            {} % otherwise do nothing
        } 
    },
},
}

The style as it is compiles without error. However, if I comment out the line that starts with for parent, or add in something like align=north (as in the commented-out line above), I get errors -- but only for larger trees.

For instance, the following small tree compiles just fine regardless of what I do:

\begin{forest}
default
[a
    [b]
    [ [c] [d] 
    ]
]
\end{forest}

But the following slightly larger tree gives me a dimension too large error if I omit the for parent line, and a dividing-by-zero error if I add in align=north.

\begin{forest}
default
[a
    [b]
    [ [c] 
        [ [d] [e] 
        ]
    ]
]
\end{forest}

What exactly is resulting in these errors? I'm uncomfortable with the fact that I can't predict what will break, and I feel like maybe if my style is so fragile I'm doing something wrong. Any ideas? (Am I being clear?)

  • 1
    Could you give the complete code for your two examples (including loaded packages)? – cryingshadow Dec 4 '15 at 10:19
  • 2
    I'm guessing this is the same (pgf) bug as in tex.stackexchange.com/questions/204094 – Sašo Živanović Dec 4 '15 at 11:27
  • 1
    @SašoŽivanović The (first anyhow) error is due to an illegal array specification due to align=north. At least, that's what I get. – cfr Dec 4 '15 at 13:56
  • @cryingshadow That is the complete code for my two examples -- sorry it's not in one complete document. The only package loaded is forest. – rcraioveanu Dec 4 '15 at 14:59
  • @SašoŽivanović You're right, this looks like the same thing. I didn't spot that previous thread! Thanks for your detailed answer over there. – rcraioveanu Dec 4 '15 at 15:00
5

align expects a value of left, right, center or specification of an array e.g. |c|lp{4cm} or whatever. The error when the line is commented in complains that

! LaTeX Error: Illegal character in array arg.

Because n is not a known column type.

You might want anchor=north or you might want something else - I'm not sure what this is supposed to be doing.

Even with the above fix, you'll get errors due to the PGF bug referred to in comments. I wrote a pretty nice empty nodes style for use in these cases which is almost, but not quite, just like nice empty nodes. Here, I provide my pretty nice empty nodes and my nice empty nodes which are modified in accordance with the settings you want for the tree.

My original solution works with either version 1 or version 2 of forest. However, if you are using the current version of the package, this updated code is both simpler and more flexible. If you need code which will work with earlier versions of the package, please see below for the original solution.

\documentclass[tikz,border=10pt,multi]{standalone}
\usepackage[linguistics]{forest}% needs version 2
\begin{document}
\forestset{
  my nice empty nodes/.style={% modified from manual page 52 of v1 manual (updated version is now on page 65)
    for tree={
      calign=fixed edge angles,
      calign angle=60,
    },
    delay={
      where n children=0{
        if content={}{
          content=\strut,
          anchor=parent,
        }{
          align=center
        },
      }{
        if content={}{
          shape=coordinate,
          !u.for children={
            anchor=parent
          }
        }{}
      }
    },
  },
  my pretty nice empty nodes/.style={
    for tree={
      calign=fixed edge angles,
      calign angle=60,
      parent anchor=children,
      delay={
        where n children=0{
          if content={}{
            content=\strut,
            anchor=parent,
          }{
            align=center
          },
        }{
          if content={}{
            inner sep=0pt,
            edge path={\noexpand\path [\forestoption{edge}] (!u.parent anchor) -- (.children)\forestoption{edge label};}
          }{}
        }
      }
    }
  }
}
\begin{forest}
baseline,
sn edges,
my nice empty nodes
[a
    [b]
    [ [c] [d]
    ]
]
\end{forest}
\begin{forest}
baseline,
sn edges,
my pretty nice empty nodes
[a
    [b]
    [ [c]
        [ [d] [e]
        ]
    ]
]
\end{forest}
\end{document}

nice!

Here's the second tree, where that bug bites, with my pretty nice empty nodes:

pretty nice!


Compatibility Version

This is my original code. It works fine with both version 1 and version 2 of forest, but the updated solution above is recommended if you do not need backwards-compatibility.

\documentclass[tikz,border=10pt,multi]{standalone}
\usepackage{forest}
\begin{document}
\forestset{
  sn edges/.style={% manual page 8
    for tree={
      parent anchor=south,
      child anchor=north
    }
  },
  my nice empty nodes/.style={% modified from manual page 52
    for tree={
      calign=fixed edge angles,
      calign angle=60,
    },
    delay={
      where n children=0{
        if content={}{
          content=\strut,
          anchor=north,
        }{
          align=center
        },
      }{
        if content={}{
          shape=coordinate,
          for parent={
            for children={
              anchor=north
            }
          }
        }{}
      }
    },
  },
  my pretty nice empty nodes/.style={
    for tree={
      calign=fixed edge angles,
      calign angle=60,
      parent anchor=south,
      delay={
        where n children=0{
          if content={}{
            content=\strut,
            anchor=north,
          }{
            align=center
          },
        }{
          if content={}{
            inner sep=0pt,
            edge path={\noexpand\path [\forestoption{edge}] (!u.parent anchor) -- (.south)\forestoption{edge label};}
          }{}
        }
      }
    }
  }
}
\begin{forest}
baseline,
sn edges,
my nice empty nodes
[a
    [b]
    [ [c] [d]
    ]
]
\end{forest}
\begin{forest}
baseline,
sn edges,
my pretty nice empty nodes
[a
    [b]
    [ [c]
        [ [d] [e]
        ]
    ]
]
\end{forest}
\end{document}

Here's the my nice empty nodes version:

nice compatibility!

Here's the second tree, where that bug bites, with my pretty nice empty nodes:

pretty nice compatibility!

| improve this answer | |
  • Ugh, yes I did mean anchor=north -- that was a typo (which was exclusively in this post and not in my actual code). Thanks for pointing that out. – rcraioveanu Dec 5 '15 at 17:06
  • Thanks, the pretty nice empty nodes style is definitely more symmetrical and streamlined than mine, and it avoids the coordinate node shape too, so I'm happy to accept this as an answer. – rcraioveanu Dec 5 '15 at 17:26
  • Glad it helps. Always test the exact code you post compiles - it is just way to easy to be sure that it is the same when it isn't ;). – cfr Dec 5 '15 at 20:31

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.