# How to “demux” several aspects from a \foreach variable with \ifstrequal?

How can I "demux" several features from a mode specification given in a \foreach?

I would like to use a \foreach to draw several nodes in a TikZ picture. The loop will specify a mode for each node, and, in turn, the mode will be used to set several features of the style and position of the node. Since the mode specifies a group of features, I want to "demux" those features from the mode specification, rather than having to list each feature in the \foreach. A minimal not-working example is

\documentclass{standalone}
\usepackage{tikz}
\usepackage{etoolbox}

\begin{document}
\begin{tikzpicture}
\foreach \mode/\loc in {small/{(0,0)}, large/{(2,0)}}
{
\edef\myscale{\ifstrequal{\mode}{large}{1}{0.25}}
\edef\mycolor{\ifstrequal{\mode}{large}{black}{gray}}

\typeout{\meaning\myscale}
\typeout{\meaning\mycolor}
\node [scale=\myscale, color=\mycolor, draw] at \loc {\myscale\mycolor};
}
\end{tikzpicture}
\end{document}


If I try to compile this, I get the error ! Package xcolor Error: Undefined color \ifstrequal{small}{large}{black}{gray}.

It seems that the conditional needs to be expanded before being passed to the style, but I do not know how to do this. Surprisingly (at least to me), if I remove scale=\myscale, color=\mycolor from the style, then I get the following output.

So, for some reason, the node text expands the conditional, but the style does not.

(Aside question: Why do my images in posts always turn out so small?)

Edit: It appears that the \foreach is somewhat of a red herring for the above error message. Specifically, the following simpler code produces the same error:

\documentclass{standalone}
\usepackage{tikz}
\usepackage{etoolbox}

\begin{document}
\def\mode{small}%
\begin{tikzpicture}
\node [scale=\ifstrequal{\mode}{large}{1}{0.25}, draw]
{\ifstrequal{\mode}{large}{1}{0.25}};
\end{tikzpicture}
\end{document}


Although @percusse's answer is best for my particular use, I'm still interested to know why this error occurs. Also, is it possible to force expansion of \ifstrequal?

-
Your image is small to begin with. I have replaced it. –  Peter Grill Jun 26 '12 at 18:46
@PeterGrill How should I make the image bigger to begin with? What I did was to compile the code and upload the resulting pdf. I guess what I'm asking is what workflow you used for the above image. –  Henry DeYoung Jun 26 '12 at 20:44
I upload a PNG from a screen capture on a mac, and zoom in on the image until it is of a reasonable size prior to the capturing the image. –  Peter Grill Jun 26 '12 at 21:13
@PeterGrill @HenryDeYoung The standalone class provides a useful option: convert. –  Paul Gaborit Jun 26 '12 at 21:21
Not to address your question at all, but why can't you just use a pgfkeys style rather than your "mode"? I mean, that's exactly how it turns out. –  Ryan Reich Jun 27 '12 at 4:21

Expanding in the foreach list is often problematic and needs to be performed just at the right spot. Few examples are

Nested foreach inside a TikZ matrix for both rows and columns

Tikz foreach inside matrix

The style definition keys are recommended also to avoid such problems.

\documentclass{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\tikzset{l/.style={scale=1,black},s/.style={scale=0.25,gray}}
\foreach \mode/\loc in {s/{(0,0)}, l/{(2,0)}}{
\node [\mode] at \loc {\mode};
}
\end{tikzpicture}
\end{document}


I would also stay away from the literal words to define styles and variables since any other package can also define the same ones and it would lead to unnecessary debugging effort.

-
IMHO, It's a perfect solution: concise, effective and legible. –  Paul Gaborit Jun 26 '12 at 19:40
@PolGab Thanks for the uplifting comment :) –  percusse Jun 26 '12 at 20:15
@percusse I agree with @PolGab; this is a nifty solution! –  Henry DeYoung Jun 26 '12 at 20:42

Not sure what is going on with \ifstrequal, but you can use the \IfStrEq from the xstring package

\IfStrEq{\mode}{large}{%
\gdef\myscale{1}%
\gdef\mycolor{black}%
}{%
\gdef\myscale{0.25}%
\gdef\mycolor{gray}%
}%


which produces:

## Code:

\documentclass{standalone}
\usepackage{tikz}
\usepackage{etoolbox}
\usepackage{xstring}

\begin{document}
\begin{tikzpicture}
\foreach \mode/\loc in {small/{(0,0)}, large/{(2,0)}}
{
\IfStrEq{\mode}{large}{%
\gdef\myscale{1}%
\gdef\mycolor{black}%
}{%
\gdef\myscale{0.25}%
\gdef\mycolor{gray}%
}%

\node [scale=\myscale, color=\mycolor, draw] at \loc {\myscale\mycolor};
}
\end{tikzpicture}
\end{document}


I would actually recommend you use \tikzset to define styles:

\IfStrEq{\mode}{large}{%
\tikzset{MyStyle/.style={scale=1, color=black}}
}{%
\tikzset{MyStyle/.style={scale=0.25, color=gray}}
}%


which produces identical results as above.

## Code:

\documentclass{standalone}
\usepackage{tikz}
\usepackage{etoolbox}
\usepackage{xstring}

\begin{document}
\begin{tikzpicture}
\foreach \mode/\loc in {small/{(0,0)}, large/{(2,0)}}
{
\IfStrEq{\mode}{large}{%
\tikzset{MyStyle/.style={scale=1, color=black}}
}{%
\tikzset{MyStyle/.style={scale=0.25, color=gray}}
}%

\node [MyStyle, draw] at \loc {\myscale\mycolor};
}
\end{tikzpicture}
\end{document}

-

Perhaps this does not technically answer your question in terms of \ifstrequal, but provides a work-around. You can use a different - more primitive - approach to conditioning via \ifx...\else...\fi:

\def\mystring{large}%
\ifx\mode\mystring
\def\myscale{1}%
\def\mycolor{black}%
\else% \mode is not large
\def\myscale{0.25}%
\def\mycolor{gray}%
\fi%


-