Al utilizar pgfplots, ¿por qué obtengo una "secuencia de control indefinida" cuando intento utilizar una variable foreach como parámetro para addplot?

Al utilizar pgfplots, ¿por qué obtengo una "secuencia de control indefinida" cuando intento utilizar una variable foreach como parámetro para addplot?

Como tengo varios gráficos con barras de error, me gustaría cambiar ligeramente las barras de error para que el gráfico general sea más legible. Sin embargo, cuando intento hacer esto usando la variable a \foreachcomo cantidad a desplazar, aparece un error de "secuencia de control indefinida".

\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}

(El documento no se compila cuando descomento cualquiera de los dos comentarios).

¿Qué pasa aquí?

EDITAR: Se agregó otra variable al archivo \foreach. En mi caso de uso real, contendría el nombre del archivo para trazar los datos o la etiqueta que se usará para la curva.

Respuesta1

El problema es una cuestión de expansión macro: la \yvariable se evalúa más tarde, pero en ese momento "posterior", el ciclo ha finalizado y \yno está definido.

Como ya se mencionó, \pgfplotsinvokeforeachtiene solo un argumento de bucle (tenga en cuenta que \pgfplotsforeachungroupedadmite dos argumentos, pero no ayuda aquí).

He aquí un enfoque quesiemprefunciona, no importa cuán complicados sean tus bucles:

\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}

Introduje un artificial \edefque cubre todo el cuerpo del bucle. Esto \edefsignifica "definición ampliada": define \tempcomo el resultado completamente expandido de todo lo que está dentro de las llaves. Esto se expandirá \yal valor del bucle actual. Desafortunadamente, también (intentará) expandirse \addplot, lo cual es imposible. Para evitar esta expansión, escribí la primitiva TeX \noexpanddelante de \addplot.

Finalmente, \tempcontiene el cuerpo del bucle.sincualquier referencia a \yo \x. Simplemente podemos ejecutarlo escribiendo \tempen el cuerpo del bucle. Eso hace el trabajo.


Sólo para los curiosos: puedes dejar la lista de coordenadas fuera de \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}

Esto también funciona porque TeX funciona mediante expansión: tan pronto como se "ejecuta" \temp, ya no sabe nada sobre el hecho de que está "dentro" \tempy simplemente seguirá leyendo.

Verhttp://pgfplots.sourceforge.net/TeX-programming-notes.pdfpara detalles

información relacionada