2

I am putting up some syntax/semantics trees with explanations and things. At first I created a node tree with tikz which meant I could easily point at chosen nodes to clarify those nodes. However, I thought I might save myself some typing of nodes if I put a forest node tree in a separate tikz node and then using further tikz nodes to point to parts of the forest tree. But this is proving trickier than it seemed to me at first. Every time the location is off and I would need to resort to absolute positioning (which I can avoid if the syntax tree is a tikz node tree).

I have tried putting a node at NP (\node (np) at (NP) {};), I tried , tikz={\node[right=20pt of .west,inner sep=0pt] (NP) {x}; within the forest node (NP) as per this post, I have tried \tikzset{treen/.node=inner sep=2pt} and for tree=treen as per this post, and \subnode{NP}{} as per this post, but to no avail. So, am I missing something that I could do to make one of these (or something else) work? Or should I just go back to tikz trees?

MWE:

% !TEX program = lualatex
\documentclass[12pt,b5paper,openany]{book}
\usepackage{fontspec}
\setlength\parskip{0pt}

\usepackage{polyglossia} \setdefaultlanguage{english}

\usepackage[margin=2cm]{geometry}

\usepackage[skins,breakable]{tcolorbox} \newtcolorbox{primary}[1][]{size=title,halign=center,valign=center,colback=black!10,#1}

\usepackage{tikz} \tikzset{noddies/.style={draw=black,rectangle,fill=pink,align=left}} \usetikzlibrary{positioning,tikzmark}

\usepackage{forest}

\begin{document}

The argument impacted by the verb gets fed in first:

\begin{figure}[ht!] \begin{primary} \begin{tikzpicture}[rounded corners] \node[noddies] (tree) at (0,) { \begin{forest}[S [NP,name=NP [argument [John]]][VP,name=VP [V [$\lambda x.cough(x)$ [coughed]]]]]\end{forest} }; \node[noddies] (argument) at (-5,2.5) {argument}; \node[noddies] (lambda) at (5,2.5) {verb function};

\draw[-latex] (argument.east) -- (NP);
\draw[-latex] (lambda.west) -- (tree);

\end{tikzpicture} \end{primary} \label{fig:lambtree} \caption{1-place predicate \textit{cough} with tree} \end{figure}

\end{document}

Plergux
  • 874

1 Answers1

2

By default, a forest tree introduces a tikzpicture, so putting a forest tree inside a tikz node creates a nested tikzpicture. This is not very advisable, see e.g. this post.

There are ways around this, though. First, Forest can be instructed to not introduce a tikzpicture environment. This is controlled by Forest's keys begin draw and end draw, which default to \begin{tikzpicture} and \begin{tikzpicture}. Setting them both to {}, as in the first and the second solution below, typesets the tree "directly" into the tikzpicture.

The second way (and in fact the more common way) of addressing the problem is to simply add some tikz commands at the end of the Forest tree specification, i.e. after the final closing bracket of the tree. This is the method used in the third solution below.

Now OP's example introduces an extra problem: we want to put a filled rectangle around the tree, but this is difficult to do once the tree is already drawn. The problem is easily seen in the first solution below. If we remove the opacity key on the rectangle, the tree is not visible. Perhaps there's a layer-based solution to this, but below, I have addressed it by first drawing the rectangle and then the tree. Forest computes the location of each tree node before the tree is drawn, so if we use this information at just the right time (before drawing tree), we can draw the rectangle before the tree.

The fit node style computes (using Forest aggregate functions .min and .max) the north west and south east point point of the rectangle, and then typesets the rectangle node using TikZ's fit. (There's a bit of .process black magic in there to forward the computed information to fit.) How exactly the typesetting is triggered depends on whether Forest introduces its own tikzpicture or not (as discussed above).

In the second solution, it is the user rather than Forest that provides the tikzpicture environment. We are therefore already inside a tikzpicture while the Forest tree specification is being processed, so we can plop in the rectangle node using the TeX key (inside the definition of fit node).

In the third solution, we must delay the typesetting of the rectangle node until Forest opens up its own tikzpicture. But we have to take care to draw it before the tree nodes, so using Forest's tikz key would not produce the desired result. We resort to modifying Forest's draw picture method style; see the definition of fit node in the third solution.

The first solution

% !TEX program = lualatex
\documentclass[12pt,b5paper,openany]{book}
\usepackage{fontspec}
\setlength\parskip{0pt}

\usepackage{polyglossia} \setdefaultlanguage{english}

\usepackage[margin=2cm]{geometry}

\usepackage[skins,breakable]{tcolorbox} \newtcolorbox{primary}[1][]{size=title,halign=center,valign=center,colback=black!10,#1}

\usepackage{tikz} \tikzset{noddies/.style={draw=black,rectangle,fill=pink,align=left}} \usetikzlibrary{positioning,tikzmark}

\usepackage{forest}

\begin{document}

The argument impacted by the verb gets fed in first:

\begin{figure}[ht!] \begin{primary} \begin{tikzpicture}[rounded corners] \begin{forest} begin draw/.code={},end draw/.code={}, tikz={\nodenoddies,fit to=tree,opacity=0.5{};} [S [NP,name=NP [argument [John]]][VP,name=VP [V [$\lambda x.cough(x)$ [coughed]]]]] \end{forest} \node[noddies] (argument) at (-5,-0.5) {argument}; \node[noddies] (lambda) at (5,-0.5) {verb function};

\draw[-latex] (argument.east) -- (NP); \draw[-latex] (lambda.west) -- (tree); \end{tikzpicture} \end{primary} \label{fig:lambtree} \caption{1-place predicate \textit{cough} with tree} \end{figure}

\end{document}

The first solution

The second solution

% !TEX program = lualatex
\documentclass[12pt,b5paper,openany]{book}
\usepackage{fontspec}
\setlength\parskip{0pt}

\usepackage{polyglossia} \setdefaultlanguage{english}

\usepackage[margin=2cm]{geometry}

\usepackage[skins,breakable]{tcolorbox} \newtcolorbox{primary}[1][]{size=title,halign=center,valign=center,colback=black!10,#1}

\usepackage{tikz} \tikzset{noddies/.style={draw=black,rectangle,fill=pink,align=left}} \usetikzlibrary{positioning,tikzmark}

\usepackage{forest}

\forestset{ fit node/.style n args=3{ tempdimxa/.min={x()+min_x()}{#1}, tempdimxb/.max={x()+max_x()}{#1}, tempdimya/.min={y()+min_y()}{#1}, tempdimyb/.max={y()+max_y()}{#1}, TeX/.process=R4w4 {tempdimxa}{tempdimya}{tempdimxb}{tempdimyb} {\node[fit={(##1,##2)(##3,##4)},#2]{#3};}, }, }

\begin{document}

The argument impacted by the verb gets fed in first:

\begin{figure}[ht!] \begin{primary} \begin{tikzpicture}[rounded corners] \begin{forest} begin draw/.code={},end draw/.code={}, before drawing tree={fit node={tree}{noddies,name=tree}{}}, [S [NP,name=NP [argument [John]]][VP,name=VP [V [$\lambda x.cough(x)$ [coughed]]]]] \end{forest} \node[noddies] (argument) at (-5,-0.5) {argument}; \node[noddies] (lambda) at (5,-0.5) {verb function};

  \draw[-latex] (argument.east) -- (NP);
  \draw[-latex] (lambda.west) -- (tree);
\end{tikzpicture}

\end{primary} \label{fig:lambtree} \caption{1-place predicate \textit{cough} with tree} \end{figure}

\end{document}

Note that this tree does not come out exactly right: there is no separation between John and the lambda node, as if s sep was 0. I'm not sure how this comes about; most probably, it has something to do with the fact that the forest environment is embedded inside the tikzpicture environment. The third solution does not suffer this defect.

The second solution

The third solution

% !TEX program = lualatex
\documentclass[12pt,b5paper,openany]{book}
\usepackage{fontspec}
\setlength\parskip{0pt}

\usepackage{polyglossia} \setdefaultlanguage{english}

\usepackage[margin=2cm]{geometry}

\usepackage[skins,breakable]{tcolorbox} \newtcolorbox{primary}[1][]{size=title,halign=center,valign=center,colback=black!10,#1}

\usepackage{tikz} \tikzset{noddies/.style={draw=black,rectangle,fill=pink,align=left}} \usetikzlibrary{positioning,tikzmark}

\usepackage{forest}

\forestset{ fit node/.style n args=3{ tempdimxa/.min={x()+min_x()}{#1}, tempdimxb/.max={x()+max_x()}{#1}, tempdimya/.min={y()+min_y()}{#1}, tempdimyb/.max={y()+max_y()}{#1}, draw tree method/.prefix code/.process=R4w4 {tempdimxa}{tempdimya}{tempdimxb}{tempdimyb} {\node[fit={(##1,##2)(##3,##4)},#2]{#3};}, }, }

\begin{document}

The argument impacted by the verb gets fed in first:

\begin{figure}[ht!] \begin{primary} \begin{forest} begin draw/.append code={[rounded corners]}, before drawing tree={fit node={tree}{noddies,name=tree}{}}, [S [NP,name=NP [argument [John]]][VP,name=VP [V [$\lambda x.cough(x)$ [coughed]]]]] % \node[noddies] (argument) at (-5,-0.5) {argument}; \node[noddies] (lambda) at (5,-0.5) {verb function}; % \draw[-latex] (argument.east) -- (NP); \draw[-latex] (lambda.west) -- (tree); \end{forest} \end{primary} \label{fig:lambtree} \caption{1-place predicate \textit{cough} with tree} \end{figure}

\end{document}

The third solution

  • Talk about going above and beyond! :D These all work wonderfully. I was not aware that forest used tikz, so that explains quite a bit! Thank you for pointing that out too. :) – Plergux Mar 08 '21 at 15:59