4

I was seeing around that the forest package is better at drawing trees than tikz-qtree. I want to migrate my drawings, however, I can't find a way to easily format the tree.

I see that there are ways of defining styles and applying them to each node individually (like {Tikz}{Tree} How to reduce leaves placement). However, I want a syntax similar to tikz-qtree where you can say every leaf node or every tree node and that automatically all the nodes are formatted.

\documentclass[convert]{standalone}

\usepackage{tikz}
\usepackage{tikz-qtree}
\usepackage{forest}

\tikzset{
every leaf node/.style={draw=cyan, fill=cyan!50, ellipse, text width=1cm},
every tree node/.style={draw=blue, fill=blue!50, rectangle, text width=2cm, align=center, font=\ttfamily}
}

\begin{document}
\begin{tikzpicture}
\Tree [./
  [.usr 
    [.mji
      \texttt{sh.c}
    ]
  ]
  [.bin 
    \texttt{sh}
    \texttt{ls}
  ]
  ]
\end{tikzpicture}

\begin{forest}
  % insert here a similar "every leaf node"
  % insert here a similar "every tree node"
  [/
  [usr 
    [mji
      \texttt{sh.c}
    ]
  ]
  [bin 
    \texttt{sh}
    \texttt{ls}
  ]
  ]
\end{forest}

\end{document}

enter image description here

  • every leaf node = node with no children? every tree node = node with children? – Qrrbrbirlbel Jun 4 '15 at 14:00
  • Yes, that is correct. But those are semantics. I need a way to apply a style to several nodes, without explicitly putting it into the tree. I search the documentation, but the only have checks for the content, not sure if there is meta information regarding number of children. – adn Jun 4 '15 at 14:13
  • Yes, there is if={n_children==0}{<no children>}{<children>} or even if n children={0}{<no children>}{<children>}. – Qrrbrbirlbel Jun 4 '15 at 14:15
7

You can use

if n children={0}
  {<style(s) when no children are present>}
  {<style(s) when children are present>}

or the more customizable

if={n_children==0}
  {<style(s) when no children are present>}
  {<style(s) when children are present>}

The first argument of if will be evaluated by PGFmath. If the result ist 0 (false) the third argument will be executed, otherwise the second argument.

Code

\documentclass[tikz]{standalone}
\usepackage{forest}
\tikzset{
  every leaf node/.style={draw=cyan, fill=cyan!50, ellipse, text width=1cm, align=center},
  every tree node/.style={draw=blue, fill=blue!50, rectangle,
    text width=2cm, align=center, font=\ttfamily},
  tt/.style={font=\ttfamily},
}
\forestset{tikzQtree/.style={for tree={if n children=0{
        node options=every leaf node/.try}{node options=every tree node/.try}}}}
\begin{document}
\begin{forest} tikzQtree, % for tree={parent anchor=south, child anchor=north}
[/
  [usr 
    [mji
      [sh.c, tt]
    ]
  ]
  [bin 
    [sh, tt]
    [ls, tt]
  ]
]
\end{forest}
\end{document}
4

Note that I don't think forest is 'better' for drawing trees. It is more powerful and more flexible. It is particularly good at some things e.g. compact trees.

But if you have perfectly good trees drawn with another package and you are happy with them, I think recoding them is a waste of time. Unless you are doing it to learn how to use the package either because you just want to or because you need greater flexibility for future projects.

If you are not happy with the trees you already have, that's different.

But just switching existing trees to forest on the grounds that forest is somehow 'better' i.e. can also draw other kinds of trees (even though you aren't trying to draw those other trees) strikes me as the kind of thing I'd do to procrastinate, rather than actually constructive.

If you want some flexibility e.g. you want to be able to say that the leaves should be so-and-so for this tree but such-and-such for the next, you might take a slightly different approach. For example:

\documentclass[tikz, border=5pt, multi]{standalone}
\usepackage{forest}
\tikzset{
  my colour/.style={draw=#1, fill=#1!50},
  my leaf/.style={my colour=cyan, ellipse, text width=1cm, align=center},
  my tree/.style={my colour=blue, rectangle, text width=2cm, align=center, font=\ttfamily},
}
\forestset{
  every leaf node/.style={
    if n children=0{#1}{}
  },
  every tree node/.style={
    if n children=0{}{#1}
  },
}
\begin{document}
\begin{forest}
  for tree={
    every leaf node={my leaf},
    every tree node={my tree},
    parent anchor=south,
    child anchor=north
  }
  [/
    [usr
      [mji
        [sh.c]
      ]
    ]
    [bin
      [sh]
      [ls]
    ]
  ]
\end{forest}
\begin{forest}
  for tree={
    align=center,
    thick,
    every leaf node={rounded corners=2pt, text=red, draw=red!50!black},
    every tree node={font=\small, text=blue!50!black, draw=blue!25!black},
    grow=0
  }
  [long lines of text in\\a smaller font size
    [this is another long line
      [short\\leaf]
      [short\\leaf]
    ]
    [this is very long indeed
      [short\\leaf]
    ]
  ]
\end{forest}

\end{document}

flexible styles

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.