1

I am trying to use foreach to simplify the 1st env. code in my MN(ot)WE below.

There is an expansion problem regarding the optional argument in the 2nd code. Here is the output.

enter image description here

How can I fix this ?

\documentclass[12pt]{article}

\RequirePackage{forest}
\usetikzlibrary{calc}
\useforestlibrary{linguistics}

\newcommand\ptreeComment[3][black]{
    \node [anchor=mid west] at (#2.mid -| ptreecomment coord) {%
        \textcolor{#1}{#3}%
    };
}

\begin{document}

\begin{forest}
    for tree = {%
        sn edges,
        grow'  = 0,
        l      = 2.5cm,
        s sep  = 1.2cm,
        anchor = parent,
    },
    tikz+={
        \coordinate (ptreecomment coord) at (current bounding box.east);
    },
    [
        [$A$
            [$B$, name = nB]
            [$C$, name = nC]
        ]
        [$D$
            [$E$, name = nE]
            [$F$, name = nF]
        ]
    ]
    %
     \ptreeComment{nB}{$X = 1$}
     \ptreeComment[red]{nC}{$X = 3$}
     \ptreeComment[orange]{nE}{$X = 3$}
     \ptreeComment[black!60!green]{nF}{$X = 5$}
\end{forest}

\begin{forest}
    for tree = {%
        sn edges,
        grow'  = 0,
        l      = 2.5cm,
        s sep  = 1.2cm,
        anchor = parent,
    },
    tikz+={
        \coordinate (ptreecomment coord) at (current bounding box.east);
    },
    [
        [$A$
            [$B$, name = nB]
            [$C$, name = nC]
        ]
        [$D$
            [$E$, name = nE]
            [$F$, name = nF]
        ]
    ]
    % 
    \foreach \color/\name/\text in {black/nB/$X = 1$,
                                    red/nC/$X = 3$,
                                    orange/nE/$X = 3$,
                                    black!60!green/nF/$X = 5$}
    {
        \ptreeComment[\color]{\name}{\text}
    }
\end{forest}

\end{document}

On the other hand, the following code works without problem.

\documentclass[12pt]{article}

\RequirePackage{tikz}

\newcommand\test[2][black]{
    Option: #1 et Arg: #2\par
}

\newcommand\colorize[2][black]{
    \textcolor{#1}{#2}\par
}

\begin{document}

\foreach \opt/\arg in {black/nB,red/nC,orange/nE,green/nF}{
    \test[\opt]{\arg}
}

\bigskip

\foreach \opt/\arg in {black/nB,red/nC,orange/nE,green/nF}{
    \colorize[\opt]{\arg}
}

\end{document}
  • If I copy the code and try to compile it, I get ! File ended while scanning use of \forest. Anyway, using \color is obviously a bad choice, since \textcolor is defined in terms of \color. – egreg Aug 9 at 13:43
  • @egreg I have updated the MN(ot)WE. – projetmbc Aug 9 at 13:53
5

You should be more careful when choosing names for local variables in \foreach:

% xcolor.sty, line 756:
\def\textcolor#1#{\@textcolor{#1}}

% xcolor.sty, line 757:
\def\@textcolor#1#2#3{\protect\leavevmode{\color#1{#2}#3}}

You're using \textcolor, which internally uses \color: if you redefine \color you can't expect that `\textcolor works; actually you clearly see why the color name is printed.

There is a different way to cope with the problem, without using local variables.

\documentclass[12pt]{article}

\usepackage{forest}
\usetikzlibrary{calc}
\useforestlibrary{linguistics}

\usepackage{xparse}
\ExplSyntaxOn

\NewDocumentCommand{\lforeach}{ s O{} m +m }
 {
  \IfBooleanTF{#1}
   {
    \manual_lforeach:non { #2 } { #3 } { #4 }
   }
   {
    \manual_lforeach:nnn { #2 } { #3 } { #4 }
   }
 }

\int_new:N \g__manual_foreach_map_int

\cs_new_protected:Nn \manual_lforeach:nnn
 {
  \keys_set:nn { manual/lforeach } { single }
  \keys_set:nn { manual/lforeach } { #1 }
  \clist_set:Nn \l__manual_lforeach_list_clist { #2 }
  \int_gincr:N \g__manual_foreach_map_int
  \__manual_lforeach_define:n { #3 }
  \clist_map_inline:Nn \l__manual_lforeach_list_clist
   {
    \use:c { __manual_lforeach_ \int_use:N \g__manual_foreach_map_int _action:w } ##1 \q_stop
   }
  \int_gdecr:N \g__manual_foreach_map_int
 }
\cs_generate_variant:Nn \manual_lforeach:nnn { no }

\cs_new_protected:Nn \__manual_lforeach_define:n
 {
  \exp_last_unbraced:NcV
   \cs_set:Npn
   { __manual_lforeach_ \int_use:N \g__manual_foreach_map_int _action:w }
   \l__manual_lforeach_format_tl
   \q_stop
   {#1}
 }

\keys_define:nn { manual/lforeach }
 {
  format .tl_set:N = \l__manual_lforeach_format_tl,
  single .code:n = \tl_set:Nn \l__manual_lforeach_format_tl { ##1 },
  double .code:n = \tl_set:Nn \l__manual_lforeach_format_tl { ##1/##2 },
  triple .code:n = \tl_set:Nn \l__manual_lforeach_format_tl { ##1/##2/##3 },
 }
\ExplSyntaxOff

\newcommand\ptreeComment[3][black]{%
    \node [anchor=mid west] at (#2.mid -| ptreecomment coord) {%
        \textcolor{#1}{#3}%
    };
}

\begin{document}

\begin{forest}
    for tree = {%
        sn edges,
        grow'  = 0,
        l      = 2.5cm,
        s sep  = 1.2cm,
        anchor = parent,
    },
    tikz+={
        \coordinate (ptreecomment coord) at (current bounding box.east);
    },
    [
        [$A$
            [$B$, name = nB]
            [$C$, name = nC]
        ]
        [$D$
            [$E$, name = nE]
            [$F$, name = nF]
        ]
    ]
    % 
    \lforeach[triple]% triple means #1/#2/#3
     {
      black/nB/$X = 1$,
      red/nC/$X = 3$,
      orange/nE/$X = 3$,
      black!60!green/nF/$X = 5$
     }
     {\ptreeComment[#1]{#2}{#3}}
\end{forest}

\end{document}

The macro \lforeach has an optional argument for stating options; the possible ones are

  • single (default), when you only want to cycle over a standard comma separated list;
  • double if the list is of the form 1/a,2/b,... and the items before and after the / are referred to with #1 and #2;
  • triple if the list is of the form `1/a/i,2/b/ii,... (used in the example);
  • format to choose whatever delimiters you wish, with any number of arguments (up to nine, of course); for instance, triple is the same as format=#1/#2/#3.

The *-variant expands once the first mandatory argument (if the list is stored in a macro). The first mandatory argument has the list, the second one has the code to be executed, where instead of “variables” you use #1, #2 and so on.

For instance, you get the same output with

    \lforeach[format=C(#1)N(#2)T(#3)]
     {
      C(black)N(nB)T($X = 1$),
      C(red)N(nC)T($X = 3$),
      C(orange)N(nE)T($X = 3$),
      C(black!60!green)N(nF)T($X = 5$)
     }
     {\ptreeComment[#1]{#2}{#3}}

(this is just for showing the possibilities).

enter image description here

| improve this answer | |
2

I don't know why you define a function to change nodes when all you have to do is create a style.

Here, I created the my note style which has 3 arguments : color, name, and text.

my note/.style n args={3}{text=#1,name=#2,label={[#1]right:#3}},
my note/.default={black}{}{},

screenshot

\documentclass[12pt]{article}

\RequirePackage{forest}
\usetikzlibrary{calc}
\useforestlibrary{linguistics}

%\newcommand\ptreeComment[3][black]{
%    \node [anchor=mid west] at (#2.mid -| ptreecomment coord) {%
%        \textcolor{#1}{#3}%
%    };
%}

\begin{document}

\begin{forest}
my note/.style n args={3}{text=#1,name=#2,label={[#1]right:#3}},
my note/.default={black}{}{},
    for tree = {%
        sn edges,
        grow'  = 0,
        l      = 2.5cm,
        s sep  = 1.2cm,
        anchor = parent,
    },
    tikz+={
        \coordinate (ptreecomment coord) at (current bounding box.east);
    },
    [
        [$A$
            [$B$,my note]
            [$C$,my note ={red}{nC}{$X=3$}]
        ]
        [$D$
            [$E$,my note ={blue}{nE}{$X=3$}]
            [$F$,my note ={black!60!green}{nF}{$X=5$}]
        ]
    ]
    %
%     \ptreeComment{nB}{$X = 1$}
%     \ptreeComment[red]{nC}{$X = 3$}
%     \ptreeComment[orange]{nE}{$X = 3$}
%     \ptreeComment[black!60!green]{nF}{$X = 5$}
\end{forest}

\end{document}
| improve this answer | |
  • Thanks a lot. I know that I can do that. This is a choice of API to work with macros after the tree. I really think that we should always define abstract objects at a place and decorate them at another. This is the same point of view as the one for HTML/CSS. One last thing : I can add several comments for the same node to indicate values of different random variables. – projetmbc Aug 9 at 13:28
  • HTML and CSS are interpreted languages, LaTeX is a compiled language. Why do you want to handle a compiled language as an interpreted language? – AndréC Aug 9 at 13:39
  • My point of view is from the user's one. In practice my choice works and I don't think that real use cases will break the macro. – projetmbc Aug 9 at 14:23
1

The problem comes indeed from the use of the name \color. The use of \col makes all things work... :-)

| improve this answer | |

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.