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 use something akin to the following in tikz?

foreach (\x, \y, \colour) in {(0, 0, blue), (1, 1, green)} {
      \node[fill=\colour] at (\x,\y) {};
}
share|improve this question
3  
Do you want to have exactly this input syntax or could you live with \foreach \x/\y/\colour in {0/0/blue, 1/1/green}? (And I assume that MyColor stands for \colour?) –  Qrrbrbirlbel Jun 16 '13 at 13:55
    
@Qrrbrbirlbel Yes, a slightly different syntax is just a good. –  Unapiedra Jun 16 '13 at 14:16

2 Answers 2

up vote 9 down vote accepted

TikZ itself has a very powerful foreach loop: \foreach. (→ ; PGF manual (v2.10), section 2.20 “Repeating Things: For-Loops” and chapter 56 “Repeating Things: The Foreach Statement”)

It uses the syntax

\foreach \varA/\varB/…/\var<N>[<options>] in {val1A/val1B/…/val1<N>,
                                              val2A/val2B/…/val2<N>,
                                               …,
                                              val<m>A/val<m>B/…/val<m><N>}

What follows after this is either an argument in braces { } that gets loops over and should use the commands \varA, \varB, …, \varN.
If, as in your example, you only want to loop over one TikZ path you can omit the braces:

\tikz
  \foreach \x/\y/\colour in {0/0/blue, 1/1/green}
    \node[fill=\colour] at (\x,\y) {};

The optional <options> can contain various additional, for example

  • count=\cVar from <C>: introduces the macro \cVar that simply increments from <C> through <C> + <m>. The from <C> part is optional, without it the counter starts at <C> = 1.

  • remember=\var as \previousVar (initially <value>): can be used to remember a value from the previous iteration under a different name. The (initially <value>) is optional.

  • evaluate: can be used to evaluate a value based on the input variables.


If you insist on not using / as a delimiter you can create a PGF key with a .code args handler where you can specify the exact input syntax and use it then with the .list handler. This way any arbitrary delimiters are possible, even mixed ones.

As you use also , as a separator in the tuples, you must enbrace those in { } again. You can avoid this by using for examples ; as the inner separator.

Changing the most outer separator involved a major re-definition of macros. There already exists many other implementation and improvement of such foreach loops.

Code

\documentclass[tikz,convert=false]{standalone}

\begin{document}
\tikz
  \foreach \x/\y/\colour in {0/0/blue, 1/1/green}
    \node[fill=\colour] at (\x,\y) {};

\tikz[my Foreach/.code args={(#1,#2,#3)}{\node[fill=#3] at (#1,#2) {};}] {
  \tikzset{my Foreach/.list={{(0, 0, blue)}, {(1, 1, green)}}}
}

\tikz[my Foreach/.code args={#1,#2,#3}{\node[fill=#3] at (#1,#2) {};}] {% same as above
                                                          % but without the parentheses
  \tikzset{my Foreach/.list={{0, 0, blue}, {1, 1, green}}}
}

\tikz[my Foreach/.code args={#1;#2;#3}{\node[fill=#3] at (#1,#2) {};}] {% same as above
                                                              % but with ; instead of ,
  \tikzset{my Foreach/.list={0; 0; blue, 1; 1; green}}
}
\end{document}

Outputs

enter image description here

share|improve this answer

The TikZ/PGF kernel has macros for this. I propose a more general \xforeach macro written in expl3; the syntax is a bit different, but I guess you can live with it.

\documentclass{article}
\usepackage{xparse,tikz}

\ExplSyntaxOn
\NewDocumentCommand{\xforeach}{mmm}
 {
  \group_begin:
  \unapiedra_xforeach:nnn {#1} {#2} {#3}
  \group_end:
 }
\cs_new_protected:Npn \unapiedra_xforeach:nnn #1 #2 #3
 {
  % store the variables in a sequence
  \seq_set_split:Nnn \l_unapiedra_variables_seq { , } { #1 }
  % store the data in a sequence
  \seq_set_split:Nnn \l_unapiedra_data_seq { ; } { #2 }
  % cycle through the data items
  \seq_map_inline:Nn \l_unapiedra_data_seq
   {
    % separate the items in a sequence
    \seq_set_split:Nnn \l_unapiedra_instance_seq { , } { ##1 }
    % assign the value to each variable
    \seq_mapthread_function:NNN
      \l_unapiedra_variables_seq
      \l_unapiedra_instance_seq
      \unapiedra_set:Nn
    % execute the code
    #3
   }
 }
% the helper function that does the (temporary) assignments
\cs_new_protected:Npn \unapiedra_set:Nn #1 #2
 {
  \cs_set:Npn #1 { #2 }
 }
\seq_new:N \l_unapiedra_variables_seq
\seq_new:N \l_unapiedra_data_seq
\seq_new:N \l_unapiedra_instance_seq
\ExplSyntaxOff

\begin{document}
\begin{tikzpicture}
  \xforeach {\x, \y, \colour} { 0, 0, blue ; 1, 1, green} {
      \node[fill=\colour] at (\x,\y) {};
}
\end{tikzpicture}
\end{document}

enter image description here

share|improve this answer

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.