# Multilevel hierachical tree/taxonomy with linebreaks and “empty items” in Tikz

I would like to include graphics like the following in my document. Since this is just one example and there will be different models, I can't just include it, but will rather need to be able to build it myself. I figured that TikZ would be a convenient way to do so.

I found a promising basis somewhere else on this site, yet so far I haven't been able to adopt it to my specific needs. Basically I fail to include the multi-line items and also might get errors because sometimes there are no 'families' or something like that as in the case of the Netherlands in this example.

What would be the best way to make this happen? I would definitely appreciate the rectangular structure and would like to always scale it to \textwidth or similar. Is this possible? Thanks

\documentclass{article}
\usepackage{tikz-qtree}
\begin{document}
\tikzset{edge from parent/.style=
{draw, edge from parent path={(\tikzparentnode.south)
-- +(0,-8pt)
-| (\tikzchildnode)}},
blank/.style={draw=none}}
\begin{tikzpicture}
\matrix
{
\node{\Tree
[.Class  \edge[blank];
[.Order  \edge[blank];
[.Family \edge[blank];
[.Genus ]]]]};
&
\node{\Tree
[.{$\gamma$-proteobacteria}
[.Alteromonadaceae  {Glaciecola}  Alteromonas Agarivorans ] ]
[.Vibrionales [.Vibrionacae Vibrio ]]]};\\
};
\end{tikzpicture}

\end{document}


If you don't mind, you could switch to the forest package which makes it neater to build trees, only using square brackets for writing the tree.

The levels are actually a branch of the tree, but the edges are not drawn (using the command no edge). Here's how the tree actually appears:

## Code

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

\usetikzlibrary{positioning}

\forestset{%
my forest/.style={%
for tree={%
node options={text width=5cm, align=center},
l sep=1cm,
parent anchor=south,
child anchor=north,
if n children=0{tier=word}{},
edge path={%
\noexpand\path [\forestoption{edge}] (!u.parent anchor) -- +(0,-15pt) -| (.child anchor)\forestoption{edge label};
},
}
}
}

\begin{document}
\begin{forest} my forest,
[, for tree={s sep=-5mm} % levels are a bit closer, fix depending on nodes
[, no edge,
[Classes\textsuperscript{$b$}, no edge
[Sub-classes\textsuperscript{$b$}, no edge
[Families\textsuperscript{$b$}, no edge]
]
]
]% levels above here <--o--> tree below here
[$\gamma$-proteobacteria, no edge
[another node]
]
]
[Vibrionales
[Vibrionacae Vibrio]
]
]
]
\end{forest}
\end{document}

• I certainly don't mind per se. Still, I would be thankful for hints if/how I can have linebreaks in the nodes and how I proceed if certain nodes are "empty"/left out. I will definitely try this as well, but from a first look the code seems rather more complicated than easier. – Xima Jan 13 '16 at 15:48
• @Xima I was just editing the new improved version. :D Let me know if there's something missing or that you don't understand. – Alenanno Jan 13 '16 at 15:49
• @Xima Did you see the new edit? – Alenanno Jan 13 '16 at 16:13
• Yes, that was especially helpful. Thanks! Line breaking works great and it's starting to look good. I will sort out what I can and probably return tomorrow with some last issues ;) – Xima Jan 13 '16 at 18:00
• @Xima I have simplified it further. The nodes at the side are now actually a branch (more consistent). – Alenanno Jan 13 '16 at 18:16

This solution also uses forest but it uses it via a wrapper provided by the package justtrees. This package is experimental but I'm happy to provide copies on request. (I need guinea pigs!)

The point of justtrees is to make it easy to provide horizontally aligned labels to the left and/or right of the tree. In particular, it does all the calculating and alignment for you. All you do is specify the labels you want for the levels you want them, as part of the main specification of the tree.

It provides a new environment justtree which takes one mandatory argument. (It is fine for the argument to be empty, but it must be there. The content of the environment includes the actual tree specification.

\begin{justtree}
{
<tree preamble, options - may be empty>
}
<tree specification>
\end{justtree}


Since you are planning to do lots of similar trees, it makes sense to define a forest style for the kind of squared look you want. The following sets up this style. (It isn't specific to justtrees - you could use it for a regular forest tree instead.)

\forestset{
squared just tree/.style={
for tree={
edge path={% set up the squared look
\noexpand\path [\forestoption{edge}] (!u.parent anchor) -- +(0,-5pt) -| (.child anchor)\forestoption{edge label};
},


Since you also want multi-lined nodes, we'll add an alignment to the style allowing this. center will centre each line of multi-line nodes.

      align=center,


The next bit is optional. In many trees, this will look better. Basically, if the number of children is odd and greater than 2, then the middle child will be aligned with its parent. So, if there are 3 children, the 2nd one will be aligned. This ensures a straight line from the parent to the middle child.

      if={(isodd(n_children))&&(n_children>2)}
{
for children={
if={equal(n,((n_children("!u"))+1)/2)}
{
calign with current
}{},
}
}{},


I'm not quite sure from the question whether you want this, but the following ensures that the last children in each branch are horizontally aligned, even if there are more levels in some branches than others.

      if n children=0
{
before packing={tier=terminus}
}{},
},
}
}


The nice thing about this is that, once you've got a style you are happy with, you can just use it for all the trees you want to apply it to. In our case, it means we can specify the tree like this.

\begin{justtree}


Recall that this environment takes a mandatory argument which contains the preamble for the tree.

  {%


By default, the horizontal labels (which are called 'justifications' due to the origin of the package) will appear on the right. You can override this for individual labels but, if you only want labels on the left, it makes sense to set the default to left.

    left justifications,


Now we just add the style we've set up for our trees.

    squared just tree,


And that's the preamble done.

  }


Now for the tree specification itself. I wrote an introduction to forest's syntax and some of its options in the second part of this answer to an earlier question.

Here's the root. just=<whatever> sets the label for this level to <whatever>. The label will be automatically placed and aligned when the tree is drawn.

  [$\gamma$-proteobacteria, just=Class


Here's another label for the next level.

    [Alteromonadales, just=Order
[Alteromonas
]
[Glaciecola
]


Here's a label for the next level. Note that it doesn't matter which node on a level you use to specify the label. just will always put it to the far left of the left of the tree.

        [Agarivorans, just=Genus
]
]
]
[Vibrionales


Nor does it matter if the label is specified as part of a different branch. The label will still go to the left of the leftmost branch.

      [Vibrionacae, just=Family
[Vibrio
]
]
]


Just for kicks: a multi-line node and a branch with fewer levels than the others.

    [A longer text\\ split over 2 lines
[Last]
]
]
\end{justtree}


This produces the following tree:

Complete code:

\documentclass[border=5pt, multi, tikz]{standalone}
\usepackage{justtrees}% version 0.05 : available for experimental use on request (just ask!)
\forestset{
squared just tree/.style={
for tree={
edge path={
\noexpand\path [\forestoption{edge}] (!u.parent anchor) -- +(0,-5pt) -| (.child anchor)\forestoption{edge label};
},
align=center,
if={(isodd(n_children))&&(n_children>2)}
{
for children={
if={equal(n,((n_children("!u"))+1)/2)}
{
calign with current
}{},
}
}{},
if n children=0
{
before packing={tier=terminus}
}{},
},
}
}
\begin{document}
\begin{justtree}
{%
left justifications,
squared just tree,
}
[$\gamma$-proteobacteria, just=Class
[Alteromonas
]
[Glaciecola
]
[Agarivorans, just=Genus
]
]
]
[Vibrionales
[Vibrionacae, just=Family
[Vibrio
]
]
]
[A longer text\\ split over 2 lines
[Last]
]
]
\end{justtree}
\end{document}


## If you would like to try out justtrees, please let me know.

I would be happy to provide a copy of the package. There are copies around here. However, they are not the latest version, so please ask if you want to try it.

# EDIT & UPDATE

Note that the just= is not required to ensure the levels are aligned. It is only required to specify the content of the label for that level of the tree. If a particular level does not need a label, no label need be specified.

In response to the OP's request for left aligned labels to the left of the tree, I've adapted the code of the package to enable this. I'd forgotten that, in simplifying the code when creating justtrees.sty from prooftrees.sty, I'd abandoned the use of branches for the labels altogether and just use the tikz+ options. This makes it simpler in some ways to vary the alignment of the text in labels, but more complex in others. (Swings and roundabouts. Roundabouts and swings.)

The main issue turned out to be the need to track the width of the node contents so that all labels can be placed in nodes of the same width. The way this now works, basically, is that the code checks for the contents of each label on the left (right) whether its width exceeds a width stored in a macro. If it does, the macro is updated to store the larger width. If not, it is left alone. This macro's stored width is then fed to the label nodes on the left (right) as text width and, in addition, the alignment is set appropriately.

These changes are effective in version 0.06 of the code.

To set the alignment for the labels on the left

left just align=<alignment>


Sensible values are right (default), left or center.

To set the alignment for the labels on the right

right just align=<alignment>


Sensible values are left (default), right or center.

So, to align the labels in the tree above left, we can just change the preamble as follows:

\begin{justtree}
{%
left justifications,
squared just tree,
left just align=left,
}


The following slightly bizarre looking example sets the left labels left and the right labels right, and includes some especially long labels just to check that it still works:

\begin{justtree}
{%
left justifications,
squared just tree,
left just align=left,
right just align=right,
}
[$\gamma$-proteobacteria, left just=Class Membership
[Alteromonas
]
[Glaciecola
]
[Agarivorans, right just={Genus, Kingdom \& Sovereignty}
]
]
]
[Vibrionales, right just={$E=mc^2$}
[Vibrionacae, left just=Family
[Vibrio
]
]
]
[A longer text\\ split over 2 lines
[Last]
]
]
\end{justtree}


Complete code:

\documentclass[border=5pt, multi, tikz]{standalone}
\usepackage{justtrees}% version 0.06 : available for experimental use on request (just ask!)
\forestset{
squared just tree/.style={
for tree={
edge path={
\noexpand\path [\forestoption{edge}] (!u.parent anchor) -- +(0,-5pt) -| (.child anchor)\forestoption{edge label};
},
align=center,
if={(isodd(n_children))&&(n_children>2)}
{
for children={
if={equal(n,((n_children("!u"))+1)/2)}
{
calign with current
}{},
}
}{},
if n children=0
{
before packing={tier=terminus}
}{},
},
}
}
\begin{document}
\begin{justtree}
{%
left justifications,
squared just tree,
left just align=left,
}
[$\gamma$-proteobacteria, just=Class
[Alteromonas
]
[Glaciecola
]
[Agarivorans, just=Genus
]
]
]
[Vibrionales
[Vibrionacae, just=Family
[Vibrio
]
]
]
[A longer text\\ split over 2 lines
[Last]
]
]
\end{justtree}
\begin{justtree}
{%
left justifications,
squared just tree,
left just align=left,
right just align=right,
}
[$\gamma$-proteobacteria, left just=Class Membership
[Alteromonas
]
[Glaciecola
]
[Agarivorans, right just={Genus, Kingdom \& Sovereignty}
]
]
]
[Vibrionales, right just={$E=mc^2$}
[Vibrionacae, left just=Family
[Vibrio
]
]
]
[A longer text\\ split over 2 lines
[Last]
]
]
\end{justtree}
\end{document}


Note that, at present, alignment will not work if the labels are formatted in a different sized font from the nodes in the main tree. I consider this a bug and would like to fix it but couldn't see immediately how, so it is unfixed for now.

• Thank you for your contribution! Although I'm kind of pleased with the results of forest so far, I would gladly serve as a guinea pig and give your package a try... especially for future trees and challenges. If you came up with a way to left-align the text of labels that would definitely be a big plus! – Xima Jan 14 '16 at 14:44
• @Xima That shouldn't be a problem. I'll try to take a look when I get home tonight. – cfr Jan 14 '16 at 19:26
• @Xima I've posted a copy of justtrees.sty version 0.06 here. Does that work for you? (I'm never sure about chat rooms. They seem to have wills of their own and to obey some arcane set of rules obscured by the mists of SE.) – cfr Jan 15 '16 at 0:52
• @Xima See above for an example with left aligned labels. This requires version 0.06 of the package (mentioned above) because I added the code to enable this feature per your request. (It seemed it might be generally useful, so I thought a proper solution was in order. However, do note the comment at the end of my update above re. font size. I'm working on this but the alignment only works for now if the labels have the same size font as the nodes of the tree. A smaller size would probably be OK, but bigger doesn't work and I'm not certain why.) – cfr Jan 15 '16 at 0:55

Here is what I came up with so far. I tried to cram it using s sep although some there might be room for improvement.

This is still not completely flawless from my point of view, but it should be ok to start with.

• Concerning the labels, the text should rather be left aligned than the actual text boxes (or whatever is the right notion here)
• The "branching" is not perfect. It's dependent on the number of lines of the parent node or even if a lower case letter like q or g is included. In general it would be neater if the "branching" would happen at the same height and closer to the child nodes than the parent nodes. (That's btw why I added some blank lines in some nodes, which isn't an ideal solution either.)

\begin{spacing}{1}
\footnotesize
\begin{forest} my forest,
[, name=1, for tree={s sep=-20mm+(1-level)*2mm}, s sep=-14mm
[, no edge,
[\textbf{Classes}\textsuperscript{$b$}, no edge, tier=class
[\textbf{Sub-classes}\textsuperscript{$b$}, no edge, tier=sclass
[\textbf{Families}\textsuperscript{$b$}, no edge, tier=family]
]
]
]
[Accounting~systems, no edge, for tree={s sep=-23mm+(0-level)*2mm}, s sep=-23mm
[Micro-fair-judgmental\\Commercially-driven, tier=class, s sep=-25mm
[Netherlands, tier=country]
]
[U.K.~influence\\Professional~regulation, tier=family, s sep=-32mm
[Australia, tier=country]
[N.Z., tier=country]
[U.K., tier=country]
[Ireland, tier=country]
]
[U.S.~influence\\SEC~enforcement, tier=family
[U.S.A., tier=country]
]
]
]
[Macro-uniform\\Government-driven\\Tax~dominated, tier=class, s sep=-31mm
[Code-based\\international\\influences, tier=family,
[Italy, tier=country]
]
[Plan-based\\~, tier=family, s sep=-30mm
[France, tier=country]
[Belgium, tier=country]
[Spain, tier=country]
]
[Statute-based\\~, tier=family
[Germany, tier=country]
[Japan, tier=country]
]
[Economic\\control, tier=family
[Sweden, tier=country]
]
]
]
]
%
\end{forest}
\end{spacing}


Edit

After adding edge path={% \noexpand\path [\forestoption{edge}] (!u.parent anchor) -- +(0,-30pt) -| (.child anchor)\forestoption{edge label}; } or something similar to some nodes I came out with the following tree:

So, that's it!

• You can add this code to your preamble \tikzset{labels/.style={font=\bfseries, align=left}}, then add labels to the nodes that are the labels. You can remove the \textbf{} from the nodes text because that style already makes them bold. – Alenanno Jan 14 '16 at 17:19
• Perfect, then it's all settled. I will edit above – Xima Jan 14 '16 at 18:01