3

The MWE below is a machine-generated organizational chart. It works almost fine, except for those employees, who report to more than one supervisor. I had to add regular TikZ nodes and draw the arrows. The problem with them is when multiple 2nd bosses overlap above a bunch of vertically aligned employees. Thus the acrobatics with xshift which I cannot find a way to automate yet (for those two who have the pink supervisors). Automating the green supervisor's placement is kind of Okay, but still not 100% reliable: it can be overlapped by the pink ones.

I could not make the pink nodes children of those white nodes where the connecting arrows originated, as I did not know of a way to force them to float up into the 2nd level, thus I added them after the Forest was generated as the regular TikZ nodes. Thus they would not benefit from automatic placement and compaction that Forest offered.

If there was a way to convert those TikZ nodes into the Forest nodes, and tell them to reside in the 1st two levels, preferrably staggering vertically, that would be an ideal solution. If that is not possible, then at least they should try to occupy all space in either 1st or 2nd level.

Is that possible?

Edit: Well, on a 2nd thought, the pink 2nd bosses should float at the 2nd level, while I can keep any green 2nd boss at the 1st level. That would probably be the most consistent way to specify the requirements.

\documentclass[border=10pt]{standalone}
\usepackage{forest}

\begin{document}

\begin{forest} 
for tree={
    draw=black, align=center, l sep=6ex, parent anchor=south, child anchor=north,
    node options={font=\scriptsize, minimum width=14em, minimum height=10ex, rounded corners=1ex},
    edge path={
        \noexpand\path[\forestoption{edge}]
        (!u.parent anchor) -- +(0,-4ex) -| (.child anchor)\forestoption{edge label};
    },
    where n children=0{
        child anchor=west,
        edge path={
            \noexpand\path[\forestoption{edge}]
            ([xshift=-6em]!u.parent anchor) |- (.child anchor)\forestoption{edge label};
        },
        for parent={
            parent anchor=south, l sep=-12em, grow'=east, calign=child edge%, draw=blue         
        } %,draw=red
    }{}, base=b
}
[\textbf{DDDDDDDDDDDD}\\
SSSSSSSSS TTTTTTTTT\\MMMMMMMMMMM 
,name=10005073
    [\textbf{nnnnnnnnnnnnnnn}\\
dddddddddddddddddddd\\oooooooooooooooooooooooooooooooooooooooooo
,name=10005654
        [\textbf{nnnnnnnnnnnn}\\
dddddddddddddddddd\\oooooooooooooooooooooooooooooooooooooooooooooooooo
,name=10005155
[,phantom, minimum height=1ex]
    [\textbf{10003570}\\
ddddddddddddddddd\\oooooooooooooooooooooooooooooooooooooooooooooooooo
,name=10003570]
    [\textbf{10003862}\\
dddddddddddddddddddddd\\oooooooooooooooooooooooooooooooooooooooooooooooooo
,name=10003862]
    [\textbf{nnnnnnnnnnn}\\
ddddddddddddddddddddd\\oooooooooooooooooooooooooooooooooooooooooooooooooo
,name=10005556]
]
    [\textbf{nnnnnnnnnn}\\
dddddddddddddd\\ooooooooooooooooooooooooooooooooooooooooooooo
,name=10003454[,phantom]]
    [\textbf{nnnnnnnnnn}\\
ddddddddddddddd\\oooooooooooooooooooooooooooooooooooooooooooooooooo
,name=10003770[,phantom]]
    [\textbf{nnnnnnnnnnn}\\
ddddddddddddddddd\\oooooooooooooooooooooooooooooooooooooooooooooooooo
,name=10004035[,phantom]]
]]
 %
\tikzset{every node/.style={font=\footnotesize, align=center, draw=black!20, minimum width=14em, minimum height=10ex, rounded corners=1ex}}
\node[anchor=south,draw=black,fill=red!25](80000000) at ([xshift=-8em]10003570 |- 0,-4.5ex) {
\textbf{Boss Of 10003570}\\
VVVVVVV\\MMMMMMMMMMM 
}[];
\draw[->,dashed,thick,black] (10003570) to (80000000);
\node[anchor=south,draw=black,fill=red!25](80000001) at ([xshift=8em]10003862 |- 0,-4.5ex) {
\textbf{Boss Of 10003862}\\
VVVVVVV\\MMMMMMMMMMM 
}[];
\draw[->,dashed,thick,black] (10003862) to (80000001);
 %
\end{forest}

\end{document}

enter image description here

7
  • If you write [some node, tier=thisone...] for relevant nodes, those nodes will all be placed on the same level. This is subject to some limitations, of course. (E.g. if you specify the same tier for the parent of a node and that node, forest cannot miraculously put them on the same level and make one a child of the other.) But generally, it should do what you want, I think. (But I'm not entirely sure I've understood what you need here.)
    – cfr
    Nov 12 '14 at 18:05
  • You see two pink nodes side by side, because I manually added xshift after seeing how they would overlap otherwise. They would overlap because they are Tikz nodes, and did not benefit from automatic placement by Forest. I made them regular Tikz nodes as I did not know, how to force them to the 2nd level of the Forest. Does that explain things at all, or am I still confusing you? :(
    – ajeh
    Nov 12 '14 at 18:15
  • Why do you particularly want the pink ones to be children of nodes in level 3? That is, why is it so important that they have that relationship as far as forest is concerned? I suspect what you want can't be done but I keep coming back to this because I don't understand why you want to do it at all, and that makes me suspect I've misunderstood.
    – cfr
    Nov 13 '14 at 23:06
  • @cfr 1) The org charts can be very large and complex and I need those nodes auto-placed without overlapping, no matter whose children they are. 2) They have to be in the level 1. Currently the workaround is to use the regular TikZ nodes positioned "right above" and staggering them up and down. That still does not work in 100% cases. If Forest did the placement, it would have worked for any chart.
    – ajeh
    Nov 14 '14 at 13:37
  • 1
    But why do they have to officially be children of those nodes? If they could simply be added as regular nodes at level 1, you might be able to use forest's dynamic tree stuff to add them in. (That is, you could have the code for the nodes later in the tree but still have them placed in level 1.) But they would not then be children of later nodes and this is not something which I think forest can do. (What you want is not really a tree and forest does trees.) Have you looked at the graph drawing libraries? That may be closer to what you want.
    – cfr
    Nov 14 '14 at 15:09
2

I am still not sure I understand the question. However, I was independently curious about this so here goes.

This solution allows you to specify the pink bosses as the children of whichever nodes you like. All you need do is specify pink boss for the relevant nodes. However, the parent of such a node should be one of those you wish typeset as if it had no children as setting the pink boss as its child will enforce that style. The style of the terminal nodes is repeated in the code for the pink boss style but pushed back to the parent.

You also need to tell forest which is the real, original level 1 node. To get the alignment with the level 0 root, you need to pass

before packing={calign with current},

This is actually getting executed after the pink bosses are moved, which is itself being delayed somewhat by the code you must pass to get the pink bosses moved to level 1:

  before typesetting nodes={
    repeat=\thepinkbosses{TeX={\stepcounter{countbosses}},insert before=pink boss \thecountbosses},
  }

This invokes forest's support for dynamic trees (section 3.3.8 in the current manual), as well as its ability to execute TeX code and run loops.

At least one pink boss should be included. If this might not be the case, you would need to run parts of this code conditionally, I expect.

The connections between the pink bosses and the nodes which were originally their parents are drawn automatically after the tree has been drawn.

The code requires two counters which it uses to keep track of the number of pink bosses and of the relationship between the pink bosses and their parents. If a pink boss has more than one parent, you will need to add the connections to additional parents yourself. If you typeset more than one tree in the same document, you will need to reset the counters between trees. The code leaves your name settings untouched. Rather than changing these, it uses aliases pink boss n and pink n for parent-child pairing n.

I have never done several things in this code before. It is almost certainly fragile, definitely wonky and probably incorrect. Your footspeed may vary.

Caveat emptor...

\documentclass[border=10pt,multi,tikz]{standalone}
\usepackage{forest}
\standaloneenv{forest}

\begin{document}

\newcounter{pinkbosses}
\setcounter{pinkbosses}{0}
\newcounter{countbosses}
\setcounter{countbosses}{0}
\tikzset{
  /forest,
    pink boss/.style={
      for parent={child anchor=north},
      edge path={},
      fill=red!25,
      TeX={\stepcounter{pinkbosses}},
      alias=pink boss \thepinkbosses,
      for parent={
        child anchor=west,
        calign=child edge,
        alias=pink \thepinkbosses,
        edge path={
            \noexpand\path[\forestoption{edge}]
            ([xshift=-6em]!u.parent anchor) |- (.child anchor)\forestoption{edge label};
        },
      },
    },
}

\begin{forest}
  for tree={
      draw=black,
      align=center,
      l sep=6ex,
      node options={font=\scriptsize, minimum width=14em, minimum height=10ex, rounded corners=1ex},
      where n children=0{}{
        parent anchor=south,
        child anchor=north,
        edge path={
            \noexpand\path[\forestoption{edge}]
            (!u.parent anchor) -- +(0,-4ex) -| (.child anchor)\forestoption{edge label};
        },
      },
      where level=2{
        for descendants={
          where n children=0{
              child anchor=west,
              calign=child edge,
              edge path={
                  \noexpand\path[\forestoption{edge}]
                  ([xshift=-6em]!u.parent anchor) |- (.child anchor)\forestoption{edge label};
              },
              for parent={
                parent anchor=south, l sep=-12em, grow'=east, calign=child edge,
              },
            }{},
        },
      }{},
      base=b
  }
  [\textbf{DDDDDDDDDDDD}\\SSSSSSSSS TTTTTTTTT\\MMMMMMMMMMM, name=10005073
    [\textbf{DUD}\\thing 2 here\\something here, name=10005654,
      before packing={calign with current},
      before typesetting nodes={
        repeat=\thepinkbosses{TeX={\stepcounter{countbosses}},insert before=pink boss \thecountbosses},
      }
      [\textbf{thing 1 here}\\thing 2 here\\something here, name=10005155
        [,phantom, minimum height=1ex
        ]
        [\textbf{BOB}\\thing 2 here\\something  here, name=10003570
          [\textbf{BAB}\\VVVVVVV\\MMMMMMMMMMM, pink boss, alias=80000000
          ]
        ]
        [\textbf{GOG}\\thing 2 here\\something  here, name=10003862
          [\textbf{GAG}\\VVVVVVV\\MMMMMMMMMMM, name=80000001, pink boss
          ]
        ]
        [\textbf{BUB}\\thing 2 here\\something  here, name=10005556
        ]
      ]
      [\textbf{thing 1 here}\\thing 2 here\\something here, name=10003454
        [,phantom
        ]
      ]
      [\textbf{thing 1 here}\\thing 2 here\\something  here, name=10003770
        [,phantom
        ]
      ]
      [\textbf{thing 1 here}\\thing 2 here\\something  here, name=10004035
        [,phantom
        ]
      ]
    ]
  ]
  \foreach \i in {1,...,\thepinkbosses}
    \draw[<-, dashed, black!30] (pink boss \i) -- (pink \i);
\end{forest}

\end{document}

dynamic pink bosses

EDIT

Here is the result of a little more experimentation with dynamic trees. This includes provision for green bosses as well as pink ones. A kind of 'half-level' is created between the root node and its primary child. This houses an empty node which ends up with a phantom and the green bosses as siblings.

Most of the coding is moved to the style settings in this version, so less manual intervention is required in the tree itself. The only manual intervention now required in the tree itself is the following:

  • the main child of the root must have the style important node;
  • the pink bosses must have the style pink boss;
  • the green bosses must have the style green boss.

In addition, all counters should be reset between trees if more than one tree is to be typeset.

\documentclass[border=10pt,multi,tikz]{standalone}
\usepackage{forest}
\standaloneenv{forest}

\begin{document}

\newcounter{pinkbosses}
\setcounter{pinkbosses}{0}
\newcounter{countpinkbosses}
\setcounter{countpinkbosses}{0}
\newcounter{greenbosses}
\setcounter{greenbosses}{0}
\newcounter{countgreenbosses}
\setcounter{countgreenbosses}{0}
\tikzset{
  /forest,
    pink boss/.style={
      edge path={},
      fill=red!25,
      TeX={\stepcounter{pinkbosses}},
      alias=pink boss \thepinkbosses,
      for parent={
        child anchor=west,
        calign=child edge,
        alias=pink \thepinkbosses,
        edge path={
            \noexpand\path[\forestoption{edge}]
            ([xshift=-6em]!u.parent anchor) |- (.child anchor)\forestoption{edge label};
        },
      },
    },
    green boss/.style={
      edge path={},
      fill=green!25,
      TeX={\stepcounter{greenbosses}},
      alias=green boss \thegreenbosses,
      for parent={
        alias=green \thegreenbosses,
      },
    },
    important/.style={
      parent anchor=center,
      child anchor=center,
    },
    important node/.style={
      alias=important node,
      before packing={calign with current},
      before typesetting nodes={
        repeat=\thepinkbosses{TeX={\stepcounter{countpinkbosses}}, insert before=pink boss \thecountpinkbosses},
      },
    },
}

\begin{forest}
  for tree={
      draw=black,
      align=center,
      l sep=6ex,
      node options={font=\scriptsize, minimum width=14em, minimum height=10ex, rounded corners=1ex},
      where n children=0{}{
        parent anchor=south,
        child anchor=north,
        edge path={
            \noexpand\path[\forestoption{edge}]
            (!u.parent anchor) -- +(0,-4ex) -| (.child anchor)\forestoption{edge label};
        },
      },
      where level=0{
        l sep=0pt,
        append={
          [, important, append=important node,
            before packing={calign with current},
          ]
        },
        append={
          [, phantom, xshift=20ex,
          ]
        },
        before typesetting nodes={
          repeat=\thegreenbosses{TeX={\stepcounter{countgreenbosses}},append=green boss \thecountgreenbosses},
        }
      }{},
      where level=2{
        for descendants={
          where n children=0{
              child anchor=west,
              calign=child edge,
              edge path={
                  \noexpand\path[\forestoption{edge}]
                  ([xshift=-6em]!u.parent anchor) |- (.child anchor)\forestoption{edge label};
              },
              for parent={
                parent anchor=south, l sep=-12em, grow'=east, calign=child edge,
              },
            }{},
        },
      }{},
      base=b
  }
  [\textbf{DDDDDDDDDDDD}\\SSSSSSSSS TTTTTTTTT\\MMMMMMMMMMM, name=10005073
    [\textbf{DUD}\\thing 2 here\\something here, name=10005654, important node
      [\textbf{DAD}\\VVVVVVV\\MMMMMMMMMMM, name=80011942, green boss
      ]
      [\textbf{thing 1 here}\\thing 2 here\\something here, name=10005155
        [,phantom, minimum height=1ex
        ]
        [\textbf{BOB}\\thing 2 here\\something  here, name=10003570
          [\textbf{BAB}\\VVVVVVV\\MMMMMMMMMMM, pink boss, alias=80000000
          ]
        ]
        [\textbf{GOG}\\thing 2 here\\something  here, name=10003862
          [\textbf{GAG}\\VVVVVVV\\MMMMMMMMMMM, name=80000001, pink boss
          ]
        ]
        [\textbf{BUB}\\thing 2 here\\something  here, name=10005556
        ]
      ]
      [\textbf{thing 1 here}\\thing 2 here\\something here, name=10003454
        [,phantom
        ]
      ]
      [\textbf{thing 1 here}\\thing 2 here\\something  here, name=10003770
        [,phantom
        ]
      ]
      [\textbf{thing 1 here}\\thing 2 here\\something  here, name=10004035
      [\textbf{POP}\\thing 2 here\\something  here, green boss
        ]
      ]
    ]
  ]
  \foreach \i in {1,...,\thepinkbosses}
    \draw[<-, dashed, black!30] (pink boss \i) -- (pink \i);
  \foreach \i in {1,...,\thegreenbosses}
    \draw[<-, dashed, black!30] (green boss \i) -- (green \i);
\end{forest}
\end{document}

pink and green bosses

YET ANOTHER EDIT

This version uses a phantom root node. This means that the apparent root is in level 1 although the real root is, of course, in level 0. Thus, the apparent root can have a sibling because the real root is the actual root of the tree:

\documentclass[border=10pt,multi,tikz]{standalone}
\usepackage{forest}
\standaloneenv{forest}

\begin{document}

\newcounter{pinkbosses}
\setcounter{pinkbosses}{0}
\newcounter{countpinkbosses}
\setcounter{countpinkbosses}{0}
\tikzset{
  /forest,
    pink boss/.style={
      edge path={},
      fill=red!25,
      TeX={\stepcounter{pinkbosses}},
      alias=pink boss \thepinkbosses,
      for parent={
        child anchor=west,
        calign=child edge,
        alias=pink \thepinkbosses,
        edge path={
            \noexpand\path[\forestoption{edge}]
            ([xshift=-6em]!u.parent anchor) |- (.child anchor)\forestoption{edge label};
        },
      },
    },
    green boss/.style={
      edge path={},
      fill=green!25,
      alias=green boss,
      for parent={
        alias=green parent,
      },
    },
    important/.style={
      parent anchor=center,
      child anchor=center,
    },
    important node/.style={
      alias=important node,
      before packing={calign with current},
      before typesetting nodes={
        repeat=\thepinkbosses{TeX={\stepcounter{countpinkbosses}}, insert before=pink boss \thecountpinkbosses},
      },
    },
}

\begin{forest}
  for tree={
      draw=black,
      align=center,
      l sep=6ex,
      node options={font=\scriptsize, minimum width=14em, minimum height=10ex, rounded corners=1ex},
      where n children=0{}{
        parent anchor=south,
        child anchor=north,
        edge path={
            \noexpand\path[\forestoption{edge}]
            (!u.parent anchor) -- +(0,-4ex) -| (.child anchor)\forestoption{edge label};
        },
      },
      where level=1{
        before typesetting nodes={
          insert after=green boss,
        },
      }{},
      where level=3{
        for descendants={
          where n children=0{
              child anchor=west,
              calign=child edge,
              edge path={
                  \noexpand\path[\forestoption{edge}]
                  ([xshift=-6em]!u.parent anchor) |- (.child anchor)\forestoption{edge label};
              },
              for parent={
                parent anchor=south, l sep=-12em, grow'=east, calign=child edge,
              },
            }{},
        },
      }{},
      base=b
  }
  [,phantom
  [\textbf{LEVEL 1}
      [\textbf{Thing 1}, important node
        [\textbf{Green Thing}, green boss
        ]
        [\textbf{Thing 2}
          [,phantom, minimum height=1ex
          ]
          [\textbf{Thing 3}
            [\textbf{Pink Thing 1}, pink boss
            ]
          ]
          [\textbf{Thing 4}
            [\textbf{Pink Thing 2}, pink boss
            ]
          ]
          [\textbf{Thing 5}
          ]
        ]
        [\textbf{Thing 6}
          [,phantom
          ]
        ]
        [\textbf{Thing 7}
          [,phantom
          ]
        ]
        [\textbf{Thing 8}
          [,phantom
          ]
        ]
      ]
    ]
  ]
  \foreach \i in {1,...,\thepinkbosses}
    \draw[<-, dashed, black!30] (pink boss \i) -- (pink \i);
  \draw[<-, dashed, black!30] (green boss) -- (green parent);
\end{forest}
\end{document}

tree with phantom root

16
  • @ajeh It would be somewhat less confusing if you put something meaningful in the nodes and named them accordingly. It is difficult to understand what is going on with these meaningless strings. (Obviously you don't need real data but just something meaningful.)
    – cfr
    Nov 12 '14 at 21:37
  • I want them above, because they are the 2nd bosses. Let's forget about the green one completely for now. Geometrically you put the pink ones where they shold be. All I need is to be able to generate that chart automatically from a database. That would mean that their location would have to be specified only in terms of level where they need to be - 2nd level - and the rest (horizontal posisioning) should be handled by Forest automatically no matter how many pink nodes would be there.
    – ajeh
    Nov 12 '14 at 22:45
  • 1
    @ajeh You just need to replace the phantom node in that case. I replaced it with a green boss just to show that the code worked as expected. If you just remove the green boss, the code treats 10004035 as it does other terminal nodes. (You will see the same thing if you remove the phantom children of 10004035's siblings.)
    – cfr
    Nov 17 '14 at 19:02
  • 1
    @ajeh It is in the code for level 0. In before typesetting nodes, the append instruction places the node as a new child of the root node. You cannot make it a sibling of the root node because the root node cannot have siblings but only children. You could try setting the anchors of level 1 children to south, or setting a negative l sep to fake it. Or you could use a phantom node as the root of the tree i.e. make level n actually level n+1.
    – cfr
    Nov 18 '14 at 15:31
  • 1
    @ajeh Did that help?
    – cfr
    Nov 19 '14 at 23:30

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.