# Repeating preactions

I'm trying to use multiple similar preactions. Since I would prefer to automatise that I tried to use foreach with preactions. But it appears that's not working.

Let's see an example

\documentclass{minimal}
\usepackage{tikz}

\begin{document}

\begin{tikzpicture}
\draw node
[preaction={fill,transform canvas={xscale=1.03,yscale=1.03},red}]
[preaction={fill,transform canvas={xscale=1.02,yscale=1.02},green}]
[preaction={fill,transform canvas={xscale=1.01,yscale=1.01},blue}]
[text width=10em, text height=10em,circle,fill=white] {} ;
\end{tikzpicture}
\end{document}


That will produce a (ugly) node with three coloured borders. Now I know that loops exist, I may want to use ten colours and I'm a lazy guy. So how can I use foreach to avoid copying-pasting ten times the same code?

I tried what seemed the most natural to me:

\draw node
\foreach \scale/\color in {1.03/red, 1.02/green, 1.01/blue} {
[preaction={draw,transform canvas={xscale=\scale,yscale=\scale},\color}]
}
[text width=10em, text height=10em,circle,fill=white] {} ;


And the compilator complains:

ERROR: Package tikz Error: A node must have a (possibly empty) label text.
l.59   \foreach
\scale/\color in {1.03/red, 1.02/green, 1.01/blue} {


Any idea would be welcome.

-
Welcome to TeX.sx! A tip: If you indent lines by 4 spaces, then they are marked as a code sample. As opposed to the <pre> markup, the indent renders the code as LaTeX (colored). You can also highlight the code and click the "code" button (with "{}" on it). Using <pre> for an error message, however, seems sensible, since it's not real LaTeX. –  doncherry Aug 5 '11 at 9:57

This is a "feature" of how TeX parses the TikZ syntax. When TeX finds the keyword node it starts looking for what comes next (up to the end of the node) and it only "knows" about a certain number of things, such as the [optional settings] the (label) and the {text}. It doesn't know how to deal with the \foreach command. It also doesn't seem too keen on the foreach key-word, but I may not have gotten the syntax right for that so someone else might have a solution using that.

However, what you want to do is eminently possible using the power of the \pgfkeys mechanism. This has inbuilt a method for iterating over a list (imaginatively called .list). Here's some code that works for your example.

\documentclass{article}
% \url{http://tex.stackexchange.com/q/24948/86}
\usepackage{tikz}

\tikzset{
repeated preaction/.style={%
repeat preaction/.list={#1}
},
repeat preaction/.code args={#1/#2}{%
\tikzset{
preaction={
fill,
transform canvas={xscale=#1,yscale=#1},
#2
}
}
}
}

\begin{document}

\begin{tikzpicture}
\draw node
[preaction={fill,transform canvas={xscale=1.3,yscale=1.3},red}]
[preaction={fill,transform canvas={xscale=1.2,yscale=1.2},green}]
[preaction={fill,transform canvas={xscale=1.1,yscale=1.1},blue}]
[text width=10em, text height=10em,circle,fill=white] {} ;
\end{tikzpicture}

\begin{tikzpicture}
\draw node
[repeated preaction={1.3/red, 1.2/green, 1.1/blue}]
[text width=10em, text height=10em,circle,fill=white] {} ;
\end{tikzpicture}
\end{document}


What this does is define a few extra keys. I'll take them in the order in which they are called.

repeated preaction : This takes one argument, which is a list. Its sole job is to pass that argument as a list to the next key. If you were prepared to write repeat preaction/.list={...} in the [...] bit then you could skip this part. (Perhaps a better name for this key would be repeat preaction with.)

repeat preaction : This is the code that is iterated over by the list syntax. So it gets passed each element of the list in turn. As the list is in the format scale/colour, we specify the argument syntax accordingly rather than just taking a list of arguments. This executes its code on each iteration, and what it does is simply to set the corresponding key. As we are now in "code" form (necessary to handle the arguments), we have to jump back in to the option-setting mode with the \tikzset command.

With a little more finesse, the actual preaction could also be passed to the initial option (though one would have to be careful about macro parameters).

(I scaled up your scales a bit so that they were easier to see. Also, the sides of picture got cropped by the cropper, that's because of the use of scaling confusing it about bounding boxes. That wouldn't happen in a real document.)

-
Thanks a lot, that was what I was looking for! –  kelux Aug 5 '11 at 13:20