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.

I like TikZ's capability to traverse multiple variables separated by a slash in the foreach (as in the example below). I am looking for something equivalent in PGFplots? I saw in the documentation that say you can't nest the foreach in PGFplots as you can in TikZ, but that only make this kind of feature more important.

Two other small issues:

I like the \x notation so that is why I am using \pgfplotsforeachungrouped. Is there a reason why I should be using pgfplotsinvokeforeach instead?

Also, what is the correct syntax to be able to use a variable to define the list instead of having the actual list in the code. In the following I'd like to be able to reference \ListWithLabels in the foreach.

\documentclass{minimal}
\usepackage{pgfplots}

\newcommand*{\ListWithLabels}{-2/a, -1/b, 1/c, 2/d}
\newcommand*{\ListWithoutLabels}{-2, -1, 1, 2}

\begin{document}
\begin{tikzpicture}
\draw [->][gray, thin](-3,0) -- (3,0) node[blue, right] {$x$}; 
\draw [->][gray, thin](0,-3) -- (0,3) node[blue, above] {$y$};

%\foreach \x/\l in \ListWithLabels {  % works
\foreach \x/\l in {-2/a, -1/b, 1/c, 2/d} {
    \draw [thick, red]
        (\x,-2pt) -- (\x,2pt)
        node [red, above] {\l};
}
\end{tikzpicture}

\begin{tikzpicture}
\begin{axis}[
    minor tick num=0, axis y line=center, axis x line=middle, 
    xmin=-3, xmax=3, ymin=-3, ymax=3, xlabel=$x$, ylabel=$y$,
    xtick={0},  xticklabels={}
    ]

%\pgfplotsinvokeforeach{-2, -1, 1, 2}{             % works
%   \addplot [mark=none,color=red, thin, samples=2]
%       coordinates{(#1,-0.05) (#1,0.05) };
%}

%\pgfplotsforeachungrouped \x in {\ListWithoutLabels}{  % does not work
\pgfplotsforeachungrouped \x in {-2, -1, 1, 2}{    % works
    \addplot [mark=none,color=red, thick, samples=2]%
        coordinates{ (\x,-0.08) (\x,0.08) };
} 

%\pgfplotsforeachungrouped \x/\l in {-2/a, -1/b, 1/c, 2/d}{ % does not work
%   \addplot [mark=none,color=red, thin, samples=2]%
%       coordinates{ (\x,-0.05) (\x,0.05) }
%        node [red, below] {\l};
%} 
\end{axis}
\end{tikzpicture}
\end{document}

Update: I saw this post which explains that the macro in TikZ needs to be not be sourrouned by {}. But that does not work for the PGF commands.

Here is another related post on pgfplotsinvokeforeach using a paramter

share|improve this question
1  
You got something wrong here. The \foreach macro is provided by pgffor, not by tikz and can be used for pgf code as well. Also keep in mind that pgfplots is not pgf, but a package based on it. However, its author is also a co-author of PGF/TikZ. You might want to change the 'PGF' in the title and text to 'pgfplots' and maybe remove the {pgf-core} tag. –  Martin Scharrer May 8 '11 at 20:19
    
@Martin: Thanks, I have made the changes you suggested. So, are you saying that I should just be able to use pgffor? –  Peter Grill May 8 '11 at 21:04
1  
No, I don't think so. I just liked to point out that \foreach isn't tikz specific, but comes from the underlying pgf. Apparently pgfplots doesn't like the grouped macros used by \foreach, so you can't use it. –  Martin Scharrer May 8 '11 at 21:29

2 Answers 2

up vote 23 down vote accepted

There is exactly one reason why there are pgfplots equivalents to the \foreach command of pgf/tikz: scoping. Occasionally, one wants to aggregrate things, i.e. to compute a value which exists outside of the loop's body -- but which is not global either.

If you do not care about scoping and if you are not aggregrating things, the use of \foreach might be the correct choice.

A solution to you approaches might be to tweak the expansion sequence, i.e. to replace the \x and \l macros by their respective value in a "correct way" (see below).

However, there is one particular thing which makes loops in pgfplots a little bit technical: the fact that an axis first just collects its content (evaluating things like axis limits and the-like) following by a visualization phase which actually draws things. Unfortunately, this leads to problems with expansions. What happens if \l is stored back - and is not actually being evaluated until finally \end{axis} starts the survey phase and tries to recover its meaning? Well - it fails because \l has only a well-defined meaning inside of the loop.

Pgfplots offers the \pgfplotsinvokeforeach thing for basic loops: it does not need expansion and directly inserts the value of the loop variable.

The most flexible way, however, is to tweak the expansion sequence -- it allows to use the full flexibility of TikZ's \foreach statement; and it is not so difficult.

It can be used as follows:


\foreach \x/\l in {-2/a, -1/b, 1/c, 2/d}{
   \edef\temp{\noexpand\addplot [mark=none,color=red, thin, samples=2]%
       coordinates{ (\x,-0.05) (\x,0.05) }
        node [red, below] {\l};
   }
   % \show\temp %-- uncomment this to see what the \temp macro does
   \temp
} 

What happens is that inside of the loop body, a temporary macro \temp is defined. The \edef is a TeX instruction (which is not usually used for LaTeX). It means "expanded definition". It defines \temp to be the fully expanded result of the argument in braces. The \noexpand means "insert the next following token literally rather than expanding it". It expands to \addplot (i.e. it simply keeps it). When using \edef, you need to prefix anything which shall be kept as-is with \noexpand. The occurances \x and \l are both replaced by their respective values. Finally, the call to \temp invokes the result -- and it is unaware of the enclosing loop.

Just a further detail: if you use the loop variable inside of coordinates {...} or inside of anything else which is needed to compute axis limits, it is directly expanded (since pgfplots needs to survey the data). Only visualization instructions like the node are postponed until \end{axis}.

share|improve this answer
    
Thanks Christian. This solves the main thrust of this question. I have posted a detailed follow up question relating to the issue of using macro defined lists in TikZ/PGFplots –  Peter Grill May 9 '11 at 23:11

A different approach to this expansion problem. Using \pgfplotsinvokeforeach and a key defined with .code args (which is basically just a macro with delimited arguments).

If you need the full power of \foreach you will either need to fake it inside the plot as explained in another example

Code

\documentclass[tikz]{standalone}
\usepackage{pgfplots}
\newcommand*{\ListWithLabels}{-2/a, -1/b, 1/c, 2/d}
\newcommand*\pgfplotsinvokeforeachmacro[1]
  {\expandafter\pgfplotsinvokeforeach\expandafter{#1}}
\begin{document}
\begin{tikzpicture}
\begin{axis}
\pgfplotsset{my plot/.code args={#1/#2}{%
  \addplot[mark=none, color=red, thick, samples=2] coordinates {(#1,-.08) (#1,.08)}
    node[red, below] {#2};}}
\pgfplotsinvokeforeachmacro\ListWithLabels{\pgfplotsset{my plot={#1}}}
\end{axis}
\end{tikzpicture}
\end{document}

Code with dependencies

\documentclass[tikz]{standalone}
\usepackage{pgfplots}
\newcommand*{\ListWithLabels}{-2/a, -1/b, 1/c, 2/d}
\newcommand*\pgfplotsinvokeforeachmacro[1]
  {\expandafter\pgfplotsinvokeforeach\expandafter{#1}}
\makeatletter
\pgfplotsset{my color/.code args={#1!#2!#3}{%
  \pgfmathsetmacro\pgfplots@tempa{#2}%
  \pgfkeysalso{color=#1!\pgfplots@tempa!#3}}}
\makeatother
\begin{document}
\begin{tikzpicture}
\begin{axis}
\pgfplotsset{my plot/.code args={#1/#2}{%
  \addplot[mark=none, my color=red!(#1+2)/4*100!green, thick, samples=2]
    coordinates {(#1,-.08) (#1,.08)} node[red, below] {#2};}}
\pgfplotsinvokeforeachmacro\ListWithLabels{\pgfplotsset{my plot={#1}}}
\end{axis}
\end{tikzpicture}
\end{document}
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.