Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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.

enter image description here

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?

share|improve this question
    
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
show 1 more comment

3 Answers

up vote 7 down vote accepted

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}

enter image description here

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.

share|improve this answer
    
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
add comment

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:

enter image description here

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}
share|improve this answer
add comment

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%

enter image description here

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.