4

I try to follow How to draw a double-color line with tikz and incorporate a node with alternating colors in the forest package. In classic tikzpicture and with node properties it works. However, for the forest package I am getting a weird result with the following MWE:

\documentclass[margin=1mm]{standalone}
\usepackage{tikz}
\usepackage{forest}

\tikzset{%
/forest,
rbcirc/.style={circle,fill=white,draw=black,dash pattern= on 2pt off 2pt,very thick,postaction={draw,red,dash pattern= on 2pt off 2pt,dash phase=2pt,very thick},text width=1.5em}
}


\begin{document}
\begin{forest}
    [A, rbcirc]
  \end{forest}
\end{document}

red-circ

If I comment out the postaction, then the black dashed pattern border is shown.

1
  • 1
    That is certainly an unusual looking tree ;).
    – cfr
    Commented Dec 10, 2023 at 18:53

1 Answer 1

3

Just define the style as a TikZ style and it will work fine. You want these keys to be passed to TikZ.

\documentclass[margin=1mm]{standalone}
\usepackage{tikz}
\usepackage{forest}

\tikzset{%
  rbcirc/.style={circle,fill=white,draw=black,dash pattern= on 2pt off 2pt,very thick,postaction={draw,red,dash pattern= on 2pt off 2pt,dash phase=2pt,very thick},text width=1.5em}
}


\begin{document}
\begin{forest}
    [A, rbcirc
    ]
\end{forest}
\end{document}

red-black bordered node in forest tree

Edit

I don't entirely understand what forest does here. For that, you'll have to ask somebody fluent in forest's internal code. But I can say something about what's happening.

Consider the following sequence:

\documentclass[margin=1mm]{standalone}
\usepackage{tikz}
\usepackage{forest}

\forestset{%
  rbcirc/.style={%
    circle,
    fill=white,
    draw=black,
    dash pattern= on 2pt off 2pt,
    very thick,
    postaction={%
      draw,
      red,
      dash pattern= on 2pt off 2pt,
      dash phase=2pt,
      very thick,
    },
    text width=1.5em
  },
  rbcirc 2/.style={%
    circle,
    fill=white,
    draw=black,
    dash pattern= on 2pt off 2pt,
    very thick,
    postaction={%
      draw=red,
      dash pattern= on 2pt off 2pt,
      dash phase=2pt,
      very thick,
    },
    text width=1.5em
  },
}


\begin{document}
\begin{forest}
  [A, rbcirc
  ]
\end{forest}
\begin{forest}
  [A, rbcirc 2
  ]
\end{forest}
\end{document}

rbcirc and rbcirc 2

In the first case, it's as if we'd passed red to the node; in the second, it's as though we'd not passed it at all.

Now consider

\documentclass[margin=1mm]{standalone}
\usepackage{tikz}
\usepackage{forest}

\forestset{%
  rbcirc 3/.style={%
    circle,
    fill=white,
    draw=black,
    dash pattern= on 2pt off 2pt,
    very thick,
    postaction={%
      dash pattern=on 2pt off 2pt,
      dash phase=2pt,
      very thick,
      draw,
      red,
    },
    text width=1.5em
  },
}


\begin{document}
\begin{forest}
  [A, rbcirc 3
  ]
\end{forest}
\end{document}

This fails with the error

! Package pgfkeys Error: The key '/tikz/dash pattern' requires a value. I am go
ing to ignore this key.

See the pgfkeys package documentation for explanation.
Type  H <return>  for immediate help.
 ...                                              
                                                  
l.729 \end{forest}
                  
? 

When forest encounters an unknown key, it passes it to TikZ via unknown to which is defined as equal to node options. If rbcirc|rbcirc 2|rbcirc 3 is defined as a forest style, rbcirc|rbcirc 2|rbcirc 3 is known to forest, so forest considers the key-value list which makes up the style. What seems to happen is that forest parses this key-value list as a comma-separated list, without regard to internal grouping. I suspect this is not quite right or more things would fail, but this appears to be the effect. So, for rbcirc, TikZ gets the list

anchor=base,circle=,fill=white,draw=black,dash pattern=on 2pt off 2pt,very thick=,postaction=draw, red, dash pattern= on 2pt off 2pt, dash phase=2pt, very thick,,text width=1.5em

which is essentially

anchor=base,circle=,postaction=draw, red, dash pattern= on 2pt off 2pt, dash phase=2pt, very thick,,text width=1.5em

and we get a filled red circle with a dashed red border.

For rbcirc 2, the list of node options is

anchor=base,circle=,fill=white,draw=black,dash pattern=on 2pt off 2pt,very thick=,postaction=draw=red, dash pattern= on 2pt off 2pt, dash phase=2pt, very thick,,text width=1.5em

which is basically

    anchor=base,circle=,fill=white,postaction=draw=red, dash pattern= on 2pt off 2pt, dash phase=2pt, very thick,,text width=1.5em

and we get a white node with a dashed black border.

But for rbcirc 3 we get

anchor=base,circle=,fill=white,draw=black,dash pattern=on 2pt off 2pt,very thick=,postaction=dash pattern=on 2pt off 2pt, dash phase=2pt, very thick, draw, red,,text width=1.5em

So the second dash pattern is interpreted as the value passed to postaction rather than as a key taking the value on 2pt off 2pt.

In contrast, if rbcirc|rbcirc 2|rbcirc 3 are defined as TikZ styles, they are unknown to forest and therefore passed directly as node options to TikZ. In this case, the node options are

anchor=base,rbcirc=

anchor=base,rbcirc 2=

and

anchor=base,rbcirc 3=

so TikZ parses the definition of the styles as expected.

Edit 2

In forest.sty we find

\pgfqkeys{/forest}{%
  .unknown/.code={%
    \expandafter\pgfutil@in@\expandafter.\expandafter{\pgfkeyscurrentname}%
    \ifpgfutil@in@
      \expandafter\forest@relatednode@option@setter\pgfkeyscurrentname=#1\forest@END
    \else
      \edef\forest@marshal{%
        \noexpand\pgfkeysalso{\forest@unknownto={\pgfkeyscurrentname=\unexpanded{#1}}}%
      }\forest@marshal
    \fi
  },
}

\pgfkeyscurrentname=\unexpanded{#1} is problematic because it basically passes the value back to the key without outer braces. If we double the braces in the input, we end up with a trailing = at the end i.e. {<key>=<value>}= which works, but presumably isn't officially sanctioned TikZ syntax.

Adding the following to the preamble fixes the issue but I do NOT know if it is safe and do NOT recommend using it.

\makeatletter
\pgfqkeys{/forest}{% DO NOT TRY THIS AT HOME!
  .unknown/.code={%
    \expandafter\pgfutil@in@\expandafter.\expandafter{\pgfkeyscurrentname}%
    \ifpgfutil@in@
      \expandafter\forest@relatednode@option@setter\pgfkeyscurrentname=#1\forest@END
    \else
      \edef\forest@marshal{%
        \noexpand\pgfkeysalso{\forest@unknownto={\pgfkeyscurrentname={\unexpanded{#1}}}}%
      }\forest@marshal
    \fi
  },
}
\makeatother

For example,

\documentclass[margin=1mm]{standalone}
\usepackage{tikz}
\usepackage{forest}
\makeatletter
\pgfqkeys{/forest}{% DO NOT TRY THIS AT HOME!
  .unknown/.code={%
    \expandafter\pgfutil@in@\expandafter.\expandafter{\pgfkeyscurrentname}%
    \ifpgfutil@in@
      \expandafter\forest@relatednode@option@setter\pgfkeyscurrentname=#1\forest@END
    \else
      \edef\forest@marshal{%
        \noexpand\pgfkeysalso{\forest@unknownto={\pgfkeyscurrentname={\unexpanded{#1}}}}%
      }\forest@marshal
    \fi
  },
}
\makeatother
\forestset{%
  rbcirc/.style={%
    circle,
    fill=white,
    draw=black,
    dash pattern= on 2pt off 2pt,
    very thick,
    postaction={%
      draw,
      red,
      dash pattern= on 2pt off 2pt,
      dash phase=2pt,
      very thick,
    },
    text width=1.5em
  },
  rbcirc 2/.style={%
    circle,
    fill=white,
    draw=black,
    dash pattern= on 2pt off 2pt,
    very thick,
    postaction={%
      draw=red,
      dash pattern= on 2pt off 2pt,
      dash phase=2pt,
      very thick,
    },
    text width=1.5em
  },
  rbcirc 3/.style={%
    circle,
    fill=white,
    draw=black,
    dash pattern=on 2pt off 2pt,
    very thick,
    postaction={%
      dash pattern= on 2pt off 2pt,
      dash phase=2pt,
      very thick,
      draw,
      red,
    },
    text width=1.5em
  },
  rbcirc 4/.style={%
    circle,
    fill=white,
    draw=black,
    dash pattern=on 2pt off 2pt,
    very thick,
    {%
      postaction={%
        dash pattern= on 2pt off 2pt,
        dash phase=2pt,
        very thick,
        draw,
        red,
      }%
    },
    text width=1.5em
  },
}


\begin{document}
\begin{forest}
  [A, rbcirc
  ]
\end{forest}
\begin{forest}
  [A, rbcirc 2
  ]
\end{forest}
\begin{forest}
  [A, rbcirc 3
  ]
\end{forest}
\begin{forest}
  [A, rbcirc 4
  ]
\end{forest}
\end{document}

alternating coloured border for forest node using forest style and perilously modified code

13
  • 1
    Do you know why this doesn't work as a forest style?
    – Alan Munn
    Commented Dec 10, 2023 at 19:05
  • I am curious as well. Let us say, that you need to use a command, e.g., child anchor=north that is a command for the forest package. Then you cannot define it directly as a TikZ style, right?
    – Arne
    Commented Dec 10, 2023 at 19:29
  • @AlanMunn Not really. See above for my non-explanation.
    – cfr
    Commented Dec 10, 2023 at 20:59
  • 1
    @Arne Right, but then you define it as a forest style and it's fine. And many TikZ keys will work even in the definitions of forest styles. But some won't work there. In general, if a style is 'pure' TikZ, it is safer to make it a TikZ style. If it is a mix of forest and simple TikZ, a forest style is fine. If the TikZ is more complex, it's best to split the TikZ part off into its own style and just call that style within the definition of the forest style.
    – cfr
    Commented Dec 10, 2023 at 21:04
  • 1
    @cfr Maybe. It's definitely misparsing the keys in a way. But that gave me an idea that works: if you simply put braces around the whole postaction={...}, i.e. use {postaction={...}} then the problem disappears!
    – Alan Munn
    Commented Dec 10, 2023 at 21:39

You must log in to answer this question.

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