2

I am drawing a family tree and I would like to label each node with the level and an ID, ideally restarting at each level. I would like to have the following output, but then with automatic numbering. The simple function in this problem gives a way to enumerate the nodes, but I would like to add the level, too (and ideally have the numbering restart per level). Any help would be appreciated.

\usepackage{forest}

\begin{document}
\begin{forest}
for tree={
  child anchor=south,
  parent anchor=north,
  grow'=north,
  draw,
}
[1-1 A 
    [2-1 B
        [3-1 C
        ]
        [3-2 D
            [4-1 E
            ]
            [4-2 F
            ]
        ]
    ]
]
\end{forest}

\end{document}

1 Answer 1

3

First, a note. The question cited by the OP is about TikZ trees, while this question is about Forest trees. The answer is therefore quite different.

We will build the solution slowly, going through several examples. If you are not interested in the explanation, feel free to jump to the last piece of code.

Forest offers information about the level of the node (option level), and the child number (option n), and this information can be inserted into the content in various ways; the simplest way is perhaps using macro \forestoption. Below, we prepend this information to the content using +content (content+ is for appending). Note that we must brace the space intended to separate the identifier and other content; if we didn't do that, it would be "eaten" by pgfkeys key-value parsing mechanism.

\documentclass{standalone}
\usepackage{forest}
\begin{document}

\begin{forest}
  for tree={
    child anchor=south,
    parent anchor=north,
    grow'=north,
    draw,
  },
  % We want to add to the content of the nodes (A, B, etc.), 
  % so we must "delay" the procedure to allow the content 
  % to be read in first.
  delay={
    for tree={
      +content={\forestoption{level}-\forestoption{n}{ }},
      % An alternative way of achieving the same, using the argument
      % processor (.process): 
      % * grab an "O"ption (level)
      % * grab another "O"ption (n), and 
      % * "w"rap the "two" options by macro "#1-#2{ }":
      % 
      % +content/.process={OOw2}{level}{n}{#1-#2{ }},
    },
  },
  [A
    [B
      [C]
      [D
        [E]
        [F]
      ]
    ]
  ]
\end{forest}

\end{document}

enter image description here

Looking at the result, we learn that (a) Forest starts numbering the level at 0 (but we want the root to be on level 1), and that (b) the root child number is 0 (we want 1). Both issues are easy to fix. Regarding (a), we'll simply add 1 to the level, using eTeX's \numexpr: \the\numexpr\forestoption{level}+1\relax (expandably) performs this operation. Regarding the root, it is simplest if we deal with it manually.

\documentclass{standalone}
\usepackage{forest}
\begin{document}

\begin{forest}
  for tree={
    child anchor=south,
    parent anchor=north,
    grow'=north,
    draw,
  },
  delay={
    % Take care of the root manually:
    +content={1-1\space},
    % We use "for descendants" instead of "for tree" now, 
    % so that we avoid visiting the root.
    for descendants={
      +content={\the\numexpr\forestoption{level}+1\relax-\forestoption{n}{ }},
    },
  },
  [A
    [B
      [C]
      [D
        [E]
        [F]
      ]
    ]
  ]
\end{forest}

\end{document}

enter image description here

This produces the tree asked for by the OP, but it won't work in general. If node C had two children (say, G and H) as well, they would receive the same identifiers as nodes E and F: 4-1 G and 4-2 H. Clearly, we can't use the child number n as a part of the ID if the nodes on the same level but belonging to different parents are to receive distinct IDs.

The idea below is to walk through the tree as usual (using for tree, as no special handling of the root will be required), and to remember the ID of the last-visited node for each level separately (we will do this using some low-level TeX constructs). We will store these "level ID"s in control sequences named leveln<level number>. To refer to them, we define an auxiliary macro \leveln expanding to the level ID control sequence name of the current node (leveln\forestoption{level}), and then use either \csname\leveln\endcsname to access the value of the level ID, or (etoolbox's) \csedef{\leveln}{...} to (re)define this value.

\documentclass{standalone}
\usepackage{forest}
\usepackage{etoolbox}
\begin{document}

% This produces the control sequence *name* of the counter for the current
% node's level; the idea is to use it in "\csname\leveln\endcsname" and such.
\def\leveln{leveln\forestoption{level}}

\begin{forest}
  for tree={
    child anchor=south,
    parent anchor=north,
    grow'=north,
    draw,
  },
  delay={
    for tree={
      % Step the level ID counter by one, or set it to 1 if it is not yet
      % defined.  The latter works because when "\csname\leveln\endcsname" is
      % not yet defined, it comes out meaning "\relax" (delimiting the end of
      %   the numeric expression), so we are evaluating "1+0"; and if it is
      % defined, say having value 42, then we are evaluating the numeric
      % expression 1+042, which is again what we want.
      TeX={\csedef{\leveln}{\the\numexpr1+0\csname\leveln\endcsname}},
      % Prepend to the content. We need to expand the prefix right away, 
      % because the value of "\csname\leveln\endcsname" is going to 
      % change way before the node is typeset.
      +content/.expanded={%
        % the level number, plus one
        \the\numexpr\forestoption{level}+1\relax
        % a dash and the level ID
        -\csname\leveln\endcsname
        % the space
        { }%
      },
    },
  },
  [A
    [B
      [C
        [E]
        [F]
      ]
      [D
        [G]
        [H]
      ]
    ]
  ]
\end{forest}

\end{document}

enter image description here

1
  • Thank you very much for the answer and especially for the details - which taught me a lot about the way these expressions work. Thanks!
    – lak20
    Sep 26, 2021 at 18:06

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .