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.

Since I have multiple plots with error bars, I would like to shift the error bars slightly to make the overall plot more readable. However, when I try to do this using the variable of a \foreach as the amount to shift, I get an "undefined control sequence" error.

\documentclass{article}

\usepackage{tikz}
\usepackage{pgfplots}

\begin{document}

\begin{tikzpicture}
\begin{axis}
\foreach \x/\y in {a/-1cm, b/0cm, c/1cm} {
    \addplot+ [
        %every error bar/.append style={xshift=\y},
        %every node/.style={xshift=\y},
        error bars/y dir=both,
        error bars/y explicit,
    ] coordinates {
        (0, 0) +- (0, 1)
        (1, 0) +- (0, 1)
        (2, 0) +- (0, 1)
    };
}
\end{axis}
\end{tikzpicture}

\end{document}

(The document does not compile when I uncomment either one of the two comments.)

What's wrong here?

EDIT: Added another variable to the \foreach. In my actual use-case it would contain the filename to plot data from or the label to use for the curve.

share|improve this question
1  
Use \pgfplotsforeachungrouped instead of \foreach –  percusse Aug 30 '12 at 13:24
1  
@percusse: I think in this case it's even necessary to use \pgfplotsinvokeforeach, otherwise all the bars are moved by the distance specified last in the list. –  Jake Aug 30 '12 at 13:25
    
@Vegard: I assume with the every node style you're trying to move the plot markers? In that case, you'll have to use every mark/.style. –  Jake Aug 30 '12 at 13:26
    
@Jake Now that I've tested it, I think every error bar is not the way to go for such use. ... Oops didn't see your comment. –  percusse Aug 30 '12 at 13:30
2  
We are just too shy :) As you can see, it's better to be sure about the answer before posting. Can you provide a minimal use case where you have different variables such that we are sure that we are answering a question that you ask rather than what we think? –  percusse Aug 30 '12 at 13:35

1 Answer 1

up vote 4 down vote accepted

The problem is a macro expansion issue: the \y variable is evaluated later - but at that "later" time, the loop has been finished and \y is undefined.

As already mentioned, \pgfplotsinvokeforeach has just one loop argument (note that \pgfplotsforeachungrouped supports two arguments, but it does not help here).

Here is one approach which does always work, no matter how complicated your loops are:

\begin{tikzpicture}
\begin{axis}
\foreach \x/\y in {a/-1cm, b/0cm, c/1cm} {
    \edef\temp{
        \noexpand\addplot+ [
            every error bar/.append style={xshift=\y},
            every node/.style={xshift=\y},
            error bars/y dir=both,
            error bars/y explicit,
        ]
        coordinates {
        (0, 0) +- (0, 1)
        (1, 0) +- (0, 1)
        (2, 0) +- (0, 1)
        };
    }
    \temp
}
\end{axis}
\end{tikzpicture}

I introduced an artifical \edef which covers the complete loop body. This \edef means "expanded definition": it defines \temp to be the fully expanded result of everything inside of the curly braces. This will expand \y to the current loop value. Unfortunately, it will also (try to) expand \addplot - which is impossible. To avoid this expansion, I wrote the TeX primitive \noexpand in front of \addplot.

Finally, \temp contains the loop body without any references to \y or \x. We can simply execute it by writing \temp into the loop body. That does the job.


Just for the curious: you could leave the coordinate list outside of the \edef:

\begin{tikzpicture}
\begin{axis}
\foreach \x/\y in {a/-1cm, b/0cm, c/1cm} {
    \edef\temp{
        \noexpand\addplot+ [
            every error bar/.append style={xshift=\y},
            every node/.style={xshift=\y},
            error bars/y dir=both,
            error bars/y explicit,
        ]
    }
    \temp
        coordinates {
        (0, 0) +- (0, 1)
        (1, 0) +- (0, 1)
        (2, 0) +- (0, 1)
    };
}
\end{axis}
\end{tikzpicture}

this does also work because TeX works by means of expansion - as soon as it "executes" \temp, it does no longer know anything about the fact that it is "inside" of \temp and will simply read ahead.

See http://pgfplots.sourceforge.net/TeX-programming-notes.pdf for details

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.