1

I have a question regarding the forest package. I would like to change the following tree to save some vertical space by changing the folder style at a certain level to be alternating or grow in a different direction. To that, I don't know why the first level is not aligned vertically.

Bonus Question: How is it possible to have alternating folder structure? Such as

            A
            |-B
          C-|
or even   E-|-D

What I would like to have is something like this.

Desired output

Here is my MWE:

\documentclass[tikz,multi]{standalone}
\usepackage[edges]{forest}
\usetikzlibrary{arrows.meta,shadows}

\begin{document}
    \begin{forest}
      basic/.style = {draw, thin, drop shadow, font=\sffamily},
      my root/.style = {basic, rounded corners=2pt, fill=black!2},
      upper style/.style = {basic, rounded corners=6pt, fill=black!6, text width=10.5em},
      lower style/.style = {basic, rounded corners=0pt,fill=black!10, text width=9em},
      for tree={%
        parent anchor=south,
        child anchor=north,
        edge path={
          \noexpand\path [-{Stealth[]}, \forestoption{edge}, thin]
            (!u.parent anchor) -- +(0,-5pt) -| (.child anchor)\forestoption{edge label};
        },
        /tikz/>=LaTeX,
      },
      where level=0{%
        my root,
        %for 1={%
          for tree={%
            if={level()<3}{%
              upper style,
            }{%
              lower style,
            },
            if={level()<2}{%
              if={isodd(n_children())}{%
                calign=child edge,
                calign primary child/.wrap pgfmath arg={#1}{int((n_children()+1)/2)},
              }{%
                calign=edge midpoint,
              },
            }{%
              folder,
              grow'=0,
            },
          },
      }{},
      [Alphabet
        [First five letters, folder, grow'=0,
          [A, lower style,]
          [B, lower style,]
          [C, lower style,]
          [D, lower style,]
          [E, lower style, text width=12em]
        ]
        [Some header]
        [More letters
          [Two
            [F]
            [G]
          ]
          [Nine
            [H]
            [I]
            [J]
            [K]
            [L]
            [M]
            [N]
            [O]
            [And a longer box, text width=12em]
          ]
          [Some more stuff
            [to fill]
            [this tree]
          ]
        ]
      ]
    \end{forest}
\end{document}

Thanks for your time!

0

The folder style is not really designed with changes of growth direction in mind, I don't think. Hence, it requires some manual adjustments after the fact. At least, I think the easiest way is just to move the relevant subtree before the tree is drawn.

\documentclass[border=10pt]{standalone}
\usepackage[edges]{forest}
\usetikzlibrary{arrows.meta,shadows}
\begin{document}
\begin{forest}
  basic/.style = {draw, thin, drop shadow, font=\sffamily},
  upper style/.style = {basic, rounded corners=6pt, edge+={-Stealth, thin}, fill=black!6, text width=10.5em},
  lower style/.style = {basic, rounded corners=0pt, edge+={-, line width=.4pt}, fill=black!10, text width=9em},
  where level<=2{%
    upper style,
    edge path'={
      (!u.parent anchor) -- +(0,-5pt) -| (.child anchor)
    },
  }{%
    lower style,
  },
  where level<=1{%
    parent anchor=children,
    child anchor=parent,
    if={isodd(n_children())}{%
      calign=child edge,
      calign primary child/.process={
        O+nw+n{n children}{(#1+1)/2}
      },
    }{%
      calign=edge midpoint,
    },
  }{
    folder,
    grow'=0,
  },
  [Alphabet
    [First five letters, folder, grow'=0, for children={lower style},
      before drawing tree={
        tempdima/.option=!r2.max y,
        tempdima-/.option=max y,
        for tree={
          y+/.register=tempdima,
        },
      }
      [A]
      [B]
      [C]
      [D]
      [E, text width=12em]
    ]
    [Some header]
    [More letters
      [Two
        [F]
        [G]
      ]
      [Nine
        [H]
        [I]
        [J]
        [K]
        [L]
        [M]
        [N]
        [O]
        [And a longer box, text width=12em]
      ]
      [Some more stuff
        [to fill]
        [this tree]
      ]
    ]
  ]
\end{forest}
\end{document}

aligned first level

The further desiderata is not, I think, possible with Forest without changing the structure of the tree. That is, you could fake it, but you can't put some children one way and some another, without manually moving one set or t'other, at which point, it is probably easier to abandon Forest and use TikZ to place everything directly.

If you are prepared to change the structure of the tree (which you could even do automatically, although I wouldn't bother unless you have very many with just this pattern), you could use a coordinate node to change the direction of growth i.e. some of the children would become grandchildren of their current parent and you'd have a coordinate as their parent. You'd then need to insert another set of three coordinates, making the original children great-grandchildren of their original parent. I doubt it is worth the additional complexity of the code, but here's an example.

\begin{forest}
  basic/.style = {draw, thin, drop shadow, font=\sffamily},
  upper style/.style = {basic, rounded corners=6pt, edge+={-Stealth, thin}, fill=black!6, text width=10.5em},
  lower style/.style = {basic, rounded corners=0pt, edge+={-, line width=.4pt}, fill=black!10, text width=9em},
  where level<=2{%
    upper style,
    edge path'={
      (!u.parent anchor) -- +(0,-5pt) -| (.child anchor)
    },
  }{%
    lower style,
  },
  where level<=1{%
    parent anchor=children,
    child anchor=parent,
    if={isodd(n_children())}{%
      calign=child edge,
      calign primary child/.process={
        O+nw+n{n children}{(#1+1)/2}
      },
    }{%
      calign=edge midpoint,
    },
  }{
    folder,
    grow'=0,
  },
  [Alphabet
    [First five letters, folder, grow'=0, for children={lower style},
      before drawing tree={
        tempdima/.option=!r2.max y,
        tempdima-/.option=max y,
        for tree={
          y+/.register=tempdima,
        },
      }
      [A]
      [B]
      [C]
      [D]
      [E, text width=12em]
    ]
    [Some header]
    [More letters
      [Two
        [F]
        [G]
      ]
      [Nine
        [H]
        [I]
        [J]
        [K]
        [, coordinate, grow'=-90, for descendants={edge path'={(!u.parent anchor) |- (.child anchor)}}, before packing={calign primary child=2}
          [, coordinate
            [And a longer box, text width=12em]
          ]
          [, coordinate
            [N]
            [O]
          ]
          [, coordinate
            [L]
            [M]
          ]
        ]
      ]
      [Some more stuff
        [to fill]
        [this tree]
      ]
    ]
  ]
\end{forest}

re-structured tree

Why, by the way, do you want some edges to be regular width and some thin? Although I've preserved it here, I think it a weird idea.

| improve this answer | |
  • Thank you for this solution! To be honest, I didn't realized I was mixing line styles. However by looking at this tree I also don't know if I should save the space for the price of awkward layout. However, I think there is a lot to learn here. Can you give some explanation on these parts? if={isodd(n_children())}{% calign=child edge, calign primary child/.process={ O+nw+n{n children}{(#1+1)/2} }, before drawing tree={ tempdima/.option=!r2.max y, tempdima-/.option=max y, for tree={ y+/.register=tempdima, }, – Bernte Apr 19 '17 at 11:53
  • @Bernte if={isodd(n_children())}{% calign=child edge, calign primary child/.process={ O+nw+n{n children}{(#1+1)/2} }, is just equivalent to if={isodd(n_children())}{ calign=child edge, calign primary child/.wrap pgfmath arg={#1}{int((n_children()+1)/2)}, } which is in your original code. .process is a faster alternative to .pgfmath, roughly speaking. before drawing tree={ tempdima/.option=!r2.max y, tempdima-/.option=max y, for tree={ y+/.register=tempdima, }, is just getting the vertical position of the root's second child in order to adjust the first child's tree. – cfr Apr 19 '17 at 15:11

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.