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.

Playing around with pgffor, I'm trying to slightly modify an example from the TikZ/pgf manual:

\path \foreach \x/\content/\style in {%
  0/a/draw,
  1/b/{draw,red},
  2/c/{circle,blue},
  3/d/draw%
} {
  node[\style] at (\x,0) {\content}
} ;

Unfortunately, this does not work for nodes with multiple \style options set. TikZ complains with

! Package pgfkeys Error: I do not know the key '/tikz/draw,red' and I am going
to ignore it. Perhaps you misspelled it.

Now, this works perfectly, when I use a comma separated list for some other variable (e.g. \content). So now, my question is: how can I split \style while executing the loop? Obviosly, pgf tries to find one key named draw,red, when it should be looking for two keys instead, namely draw and red.

Is there some clever LaTeX macro that correctly expands the loop variable or tells pgf to expect multiple keys?

share|improve this question
    
Not an answer to your question, but you can define a new name for your comma-separated styles. For example red drawing/.style={red, draw} and use this style in your loop. –  JLDiaz Jul 20 '12 at 21:22
2  
Is there a certain reason why you don't like to set up a style an use this? You may say \tikzset{somekey/.style={draw, red}} and insert somekey instead of the comma-list. –  bloodworks Jul 20 '12 at 21:25
    
@JLDiaz, bloodworks: Yep, I used that as a workaround after writing this question, but it is just too unflexible, if you have a lot of different combination of styles (some of which you will only use once) –  knittl Jul 20 '12 at 21:29
    
Related: tex.stackexchange.com/q/29048/86 as this is about expansion of macros in keys. –  Andrew Stacey Jul 20 '12 at 21:46
    
And I'm sure we've had similar questions but my searching skills are severely depleted. –  Andrew Stacey Jul 20 '12 at 21:50
add comment

4 Answers

up vote 16 down vote accepted

Here's another version, not all that different from the previously supplied but combines them in a slightly different way. In effect, it is a bit like defining a dynamic style alias that expands to the given list of options. When a style like red drawing/.style={draw,red} is defined, then calling red drawing executes \tikzset{draw,red} (sort of, actually it's pgfkeys). So we simulate this by defining a key that executes \tikzset on whatever it is passed. So apply style={do,something,and,something,else} will execute \tikzset{do,something,and,something,else}. On its own, this isn't all that useful. But when combined with the /.expand once key handler we can pass it a macro, get that macro expanded once, and then execute the style it contains.

\documentclass{article}
\usepackage{tikz}
\tikzset{%
  apply style/.code={%
    \tikzset{#1}%
  }
}
\begin{document}

\begin{tikzpicture}
\path \foreach \x/\content/\style in {%
  0/a/draw,
  1/b/{draw,red},
  2/c/{circle,draw=blue},
  3/d/draw%
} {
  node[apply style/.expand once=\style] at (\x,0) {\content}
} ;
\end{tikzpicture}
\end{document}
share|improve this answer
2  
I really like this solution. It's the least overhead and leaves the loop almost un-modified :) –  knittl Jul 22 '12 at 7:52
    
I've tried almost the same apply style=\style option with ecode and I don't understand why \tikzset{apply style/.ecode={\noexpand\tikzset\noexpand{#1}}} refuses to work. –  percusse Jul 22 '12 at 13:56
    
Ah scratch that. Now I have it with regular /.code and \expandafter's which is still lengthy than your solution. –  percusse Jul 22 '12 at 13:58
    
@percusse: .ecode is effective at key definition time, not when the key is called. Even .estyle won't help you in that case. –  Ahmed Musa Jul 22 '12 at 15:00
add comment

Use indirect styles numbered (perhaps more verbose but flexible):

\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}
  \tikzset{
    s0/.style={draw},
    s1/.style={draw,red},
    s2/.style={circle,draw=blue},
    s3/.style={draw},
  }
  \foreach \x/\content in {%
    0/a,
    1/b,
    2/c,
    3/d%
  } {
    \node[s\x] at (\x,0) {\content};
  };
\end{tikzpicture}
\end{document}

enter image description here

share|improve this answer
add comment

Personally I always use the next method and in a lot of cases I use \protected@edef with LaTeX. With the next method you can use \path node ... node ... ;.

\documentclass{standalone}
\usepackage{tikz}
 % \makeatletter\let\protectededef\protected@edef   not useful here but It' sometimes  
 % interesting
\begin{document}
  \begin{tikzpicture}
    \path 
    \foreach \x/\content/\style in {0/a/draw,
                                    1/b/{draw,red},
                                    2/c/{draw,circle,blue},
                                    3/d/draw}{
  \pgfextra{\edef\tmp{   % or \pgfextra{\protectededef\tmp{
  node[\style] at (\x,0) {\content}}}
  \tmp
  };
  \end{tikzpicture}  
\end{document}

enter image description here

share|improve this answer
    
I think this would also work with only \edef (without protection). –  percusse Jul 21 '12 at 9:43
    
@percusse Yes you are right! in a lot of cases, I need \protected@edef so it's always my first attempt. –  Alain Matthes Jul 21 '12 at 11:00
add comment

You can stick with your method. With a slight modification, it works.

\documentclass{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
  \foreach \x/\content/\style in {%
    0/a/draw,
    1/b/{draw=red},
    2/c/{circle,draw=blue},
    3/d/draw
  }{
    \edef\x{\noexpand\node[\style] at (\x,0) {\content}}\x;
  }
\end{tikzpicture}
\end{document}

enter image description here

And PolGab's solution is:

\documentclass[tikz]{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[0/.style=draw,1/.style={draw=red},
    2/.style={circle,draw=blue},3/.style=draw]
  \foreach \x/\content in {0/a, 1/b, 2/c, 3/d}{
    \node[\x] at (\x,0) {\content};
  }
\end{tikzpicture}
\end{document}

EDIT (2012/07/22)

Expanding on Andrew Stacey's solution, here is another one. Using + to list the keys eliminates the need for braces. The code can be generalized to take any symbol in place of +.

\documentclass{article}
\usepackage{tikz}
\makeatletter
\def\replaceplus#1{\xreplaceplus#1+\@nil}
\def\xreplaceplus#1+#2\@nil{%
  \ifcat$\detokenize{#2}$\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
  {\unexpanded{#1}}{\xreplaceplus#1,#2\@nil}%
}
\newcommand*\tikzexpanded[2]{%
  \begingroup
  \def\reserved@a##1#1##2##3\@nil{%
    \ifx\@nnil##2\def\x{#2}\else\edef\x{##2{#2}}\fi
  }%
  \reserved@a
    xx{\@iden}x0{\unexpanded}x1{\unexpanded\expandafter}%
    x2{\unexpanded\expandafter\expandafter\expandafter}#1{\@nnil}\@nil
  \edef\x{\expandafter\replaceplus\expandafter{\x}}%
  \edef\x{\endgroup\noexpand\tikzset{\unexpanded\expandafter{\x}}}\x
}
\tikzset{%
  use style/.code={\tikzset{#1}},
  use style expanded/.code={\tikzexpanded{xx}{#1}},
  use style expand once/.code={\tikzexpanded{x1}{#1}},
  use style expand twice/.code={\tikzexpanded{x2}{#1}}
}
\makeatother
\begin{document}
\begin{tikzpicture}
\path \foreach \x/\content/\style in{%
  0/a/draw,
  1/b/draw + red,
  2/c/circle + draw=blue,
  3/d/draw
}{
  node[use style expand once=\style] at (\x,0) {\content}
};
\end{tikzpicture}
\end{document}
share|improve this answer
    
Can I use the same for a \path node ... node ... node command? –  knittl Jul 21 '12 at 8:34
    
@knittl with my method you can use ` \path node .. node .. ;` –  Alain Matthes Jul 21 '12 at 11:03
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.