tikz.dev / forest Manual

Forest

Tutorial

2.5 Advanced option setting

We have already seen that the value of options can be manipulated: in (11), we have converted numeric content from arabic into roman numerals using the wrapping mechanism content=\romannumeral#1; in (25), we have tripled the value of l by saying l*=3. In this section, we will learn more about the mechanisms for setting options and referring to their values.

One other way to access an option value is using macro \ forestoption. The macro takes a single argument: an option name. In the following example, the node’s child sequence number is appended to the existing content. (This is therefore also an example of wrapping.)

(35)

Compiled output

\begin{forest}
[,phantom,delay={for descendants={
content=#1$_{~\forestoption~{n}}$}}
[c][o][u][n][t]]
\end{forest}

However, only options of the current node can be accessed using \ forestoption. Possibly the simplest way to access option values of other nodes is to use Forest’s extensions to the PGF’s mathematical library pgfmath, documented in [Tantau 2007, part VI]. To see pgfmath in action, first take a look at the crazy tree on the title page, and observe how the nodes are rotated: the value given to option rotate is a full-fledged pgfmath expression yielding an integer in the range from \(-30\) to \(30\). Similiarly, l+ adds a random float in the \([-5,5]\) range to the current value of l.

Example (27) demonstrated that information about the node, like the node’s level, can be accessed within pgfmath expressions. All options are accessible in this way, i.e. every option has a corresponding pgfmath function. For example, we could rotate the node based on its content:

(36)

Compiled output

\begin{forest}
delay={for tree={~rotate=content~}}
[30[-10[5][0]][-90[180]][90[-60][90]]]
\end{forest}

All numeric, dimensional and boolean options of Forest automatically pass the given value through pgfmath. If you need pass the value through pgfmath for a string option, use the .pgfmath handler. The following example sets the node’s content to its child sequence number (the root has child sequence number 0).

(37)

Compiled output

\begin{forest}
delay={for tree={content/~.pgfmath~=int(n)}}
[[[][][]][[][]]]
\end{forest}

As mentioned above, using pgfmath it is possible to access options of non-current nodes. This is achieved by providing the option function with a ⟨relative node name⟩ (see §3.15) argument.1 In the next example, we rotate the node based on the content of its parent (u means ‘up’).

(38)

Compiled output

\begin{forest}
delay={for descendants={rotate=content~("!u")~}}
[30[-10[5][0]][-90[180]][90[-60][90]]]
\end{forest}

Note that the argument of the option function is surrounded by double quotation marks: this is to prevent evaluation of the relative node name as a pgfmath function — which it is not.

For further ways to access option values, see §2.6. Here, we continue by introducing relative node setting: write ⟨relative node name⟩.⟨option⟩=⟨value⟩ to set the value of ⟨option⟩ of the specified relative node. Important: computation of the value is done in the context of the original node. The following example defines style move which not only draws an arrow from the source (the current node) to the target, but also moves the content of the source to the target (leaving a trace). Note the difference between #1 and ##1: #1 is the argument of the style move (a node walk determining the target), while ##1 is the original option (in this case, content) value.

(39)

Compiled output

\begin{forest}
for tree={calign=fixed edge angles},
move/.style={
tikz={\draw[->] () to[out=south west,in=south] (#1);},
delay={~#1.content~={##1},content=$t$}},
[CP[][C'[C][\dots[,phantom][VP[DP][V'[V][DP,move=!r1]]]]]]
\end{forest}

Compiled output

\begin{forest}
calc/.style={if n children={0}{}{content=0,for children={calc,~!u.content~/.pgfmath=int(content("!u")+content())}}},
delay=calc,
[[[3][4][5]][[3][9]][8][[[1][2][3]]]]
\end{forest}

In the following example, the content of the branching nodes is computed by Forest: a branching node is a sum of its children. The algorithm visits each node (but the root node) and adds its content to the content of the parent. Note that as the computation must proceed bottom-up, for descendants children-first propagator is used to walk through the tree.2

(40)

Compiled output

\begin{forest}
delay={
where n children={0}{}{content=0},
for descendants children-first={
~!u.content~/.pgfmath=int(content("!u")+content())}
}
[[[3][4][5]][[3][9]][8][[[1][2][3]]]]
\end{forest}

Actually, for common computations such as summing things up, Forest provides an easier way to do it: aggregate functions (§3.14). Below, aggregate function .sum, defined as pgfkeys handler, walks through the children (second argument) of the current node, summing up their content (first argument) and stores the result as the content of the current node (because content is the handled key).

(41)

Compiled output

\begin{forest}
delay={
aggregate postparse=int,
for tree children-first={
if n children={0}{}{
content/~.sum~={content}{children}
}
}
}
[[[3][4][5]][[3][9]][8][[[1][2][3]]]]
\end{forest}

1 The form without parentheses option_name that we have been using until now to refer to an option of the current node is just a short-hand notation for option_name() — note that in some contexts, like preceding + or -, the short form does not work! (The same seems to be true for all pgfmath functions with “optional” arguments.)

2 It would be possible to emulate for descendants children-first by defining a recursive style, as was done in this manual for versions of the package prior to introduction of the bottom-up propagator. The following code produces identical result as the code in the main text.