8

In order to teach people how to use forest to draw trees, it's helpful to be able to show the relationship between the tree itself and the bracketing. I've written some code to do this, but I suspect that there is also a more elegant way to do this using forest itself. Is there a simpler/better way to do this?

\documentclass[12pt,border=.5in]{standalone}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[linguistics]{forest}
\forestset{nice nodes/.style={for tree={inner sep=0pt,s sep=.4in}},default preamble=nice nodes}
\usepackage{xstring}
\usepackage{amsmath}
\makeatletter
% This code based on a suggestion from Alenanno
\newcommand\nd[1]{%
\noexpandarg
\IfSubStr{#1}{\\}
{\def\nodetext{\StrBefore{#1}{\\}}}
{\def\nodetext{#1}}
\leavevmode\llap{\color{red}[$_{\text{\nodetext}}$}#1}
\makeatletter
% This code due to David Carlisle
\newcommand*\dnx{\textcolor{red}{]}}
\newcommand\dn{\hbox to \z@\bgroup\let\dn\dnxx\dnxx}
\newcommand\dnxx{\dnx\@ifnextchar\dn{}{\hss\egroup}}
\makeatother
\begin{document}
\begin{forest}
[\nd{TP}
    [\nd{DP} [{\nd{D\\the\dn}} ] [\nd{NP} [\nd{N\\man\dn\dn\dn} ]]]
    [\nd{T’}
       [\nd{T\\will\dn} ]
       [\nd{VP}
          [\nd{V\\eat\dn} ]
          [\nd{DP} [\nd{D\\a\dn\dn} ] [\nd{NP} [\nd{N\\burger\dn\dn\dn\dn\dn\dn} ]]]
       ]
    ]
]
\end{forest}
\end{document}

enter image description here

  • I didn't realise that instr did not work for multi-line content .... (The manual doesn't mention this as far as I can see.) – cfr Sep 18 '16 at 20:47
  • Please see edited answer which provides an all-Forest version with a bit of help from Sažo ... :-). – cfr Sep 21 '16 at 1:03
3

Here's an all-Forest version thanks to Sašo's explaining how to detokenize to test for a string in multi-line content. No xstring or amsmath required!

\documentclass[12pt,border=25pt]{standalone}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[linguistics]{forest}
\forestset{%
  declare toks={dntoks}{},
  declare toks={ndtoks}{},
  nd/.style={%
    delay={%
      % detokenize to test for string in multi-line content: Sašo Živanović: https://tex.stackexchange.com/questions/330228/annotating-a-forest-tree-with-its-corresponding-bracketing/330237?noredirect=1#comment809615_330237
      temptoksa/.expanded=\detokenize{\\},
      temptoksb/.option=content,
      temptoksb/.wrap value=\detokenize{##1},
      temptoksb/.expanded/.register=temptoksb,
      if={instr(temptoksa,temptoksb)}{%
        split register/.wrap pgfmath arg={{temptoksb}{##1}{ndtoks,temptoksc}}{(temptoksa)},
      }{%
        ndtoks/.option=content,
      },
    },
    before typesetting nodes={%
      content/.wrap value={\llap{\textcolor{red}{[\textsubscript{\foresteoption{ndtoks}}}}##1},
    },
  },
  dn/.style={%
    repeat=#1{%
      dntoks+={]},
    },
    before typesetting nodes={%
      content/.wrap value={##1\rlap{\textcolor{red}{\foresteoption{dntoks}}}},
    },
  },
}
\begin{document}
\begin{forest}
  [TP, nd
    [DP, nd
      [D, nd
      ]
      [NP
        [N\\man, dn=2
        ]
      ]
    ]
    [T', nd
       [T\\will, nd, dn=1
       ]
       [VP, nd
         [V\\eat, nd, dn=1
         ]
         [DP, nd
           [D\\a, nd, dn=1
           ]
           [NP, nd
             [N\\burger, nd, dn=6
             ]
           ]
         ]
       ]
    ]
  ]
\end{forest}
\end{document}

all-Forest version

If all nodes should take the nd style (like the example in the question), then this can obviously be simplified further.

\documentclass[12pt,border=25pt]{standalone}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage[linguistics]{forest}
\forestset{%
  declare toks={dntoks}{},
  declare toks={ndtoks}{},
  nd/.style={%
    delay={%
      % detokenize to test for string in multi-line content: Sašo Živanović: https://tex.stackexchange.com/questions/330228/annotating-a-forest-tree-with-its-corresponding-bracketing/330237?noredirect=1#comment809615_330237
      temptoksa/.expanded=\detokenize{\\},
      temptoksb/.option=content,
      temptoksb/.wrap value=\detokenize{##1},
      temptoksb/.expanded/.register=temptoksb,
      if={instr(temptoksa,temptoksb)}{%
        split register/.wrap pgfmath arg={{temptoksb}{##1}{ndtoks,temptoksc}}{(temptoksa)},
      }{%
        ndtoks/.option=content,
      },
    },
    before typesetting nodes={%
      content/.wrap value={\llap{\textcolor{red}{[\textsubscript{\foresteoption{ndtoks}}}}##1},
    },
  },
  dn/.style={%
    repeat=#1{%
      dntoks+={]},
    },
    before typesetting nodes={%
      content/.wrap value={##1\rlap{\textcolor{red}{\foresteoption{dntoks}}}},
    },
  },
  default preamble={%
    for tree={nd},
  },
}
\begin{document}
\begin{forest}
  [TP
    [DP
      [D
      ]
      [NP
        [N\\man, dn=2
        ]
      ]
    ]
    [T'
       [T\\will, dn=1
       ]
       [VP
         [V\\eat, dn=1
         ]
         [DP
           [D\\a, dn=1
           ]
           [NP
             [N\\burger, dn=6
             ]
           ]
         ]
       ]
    ]
  ]
\end{forest}
\end{document}

simpler with default styling

  • 1
    This is because pgfmath (fully) expands all arguments before passing them to a function. – Sašo Živanović Sep 20 '16 at 2:23
  • 1
    A possible workaround is to detokenize before using instr. For example, to check if (multiline) content contains character n: \begin{forest} [NP\\Ana, align=center, temptoksa/.expanded=\detokenize{n}, temptoksb/.option=content, temptoksb/.wrap value=\detokenize{#1}, temptoksb/.expanded/.register=temptoksb, if={instr(temptoksa,temptoksb)}{green}{red}] \end{forest} – Sašo Živanović Sep 20 '16 at 2:25
  • @SašoŽivanović Thank you! Now it is all Forest ... (Well, at least in the sense it doesn't need xstring or amsmath.) – cfr Sep 21 '16 at 1:05

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.