![Usando pgfplots, por que obtenho "sequência de controle indefinida" ao tentar usar uma variável foreach como parâmetro para addplot?](https://rvso.com/image/254718/Usando%20pgfplots%2C%20por%20que%20obtenho%20%22sequ%C3%AAncia%20de%20controle%20indefinida%22%20ao%20tentar%20usar%20uma%20vari%C3%A1vel%20foreach%20como%20par%C3%A2metro%20para%20addplot%3F.png)
Como tenho vários gráficos com barras de erro, gostaria de deslocar ligeiramente as barras de erro para tornar o gráfico geral mais legível. No entanto, quando tento fazer isso usando a variável a \foreach
como a quantidade a ser deslocada, recebo um erro de "sequência de controle 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}
(O documento não é compilado quando eu descomente um dos dois comentários.)
O que há de errado aqui?
EDITAR: Adicionada outra variável ao arquivo \foreach
. No meu caso de uso real, ele conteria o nome do arquivo para plotar os dados ou o rótulo a ser usado para a curva.
Responder1
O problema é uma questão de expansão macro: a \y
variável é avaliada mais tarde - mas naquele momento "mais tarde", o loop foi concluído e \y
está indefinido.
Como já mencionado, \pgfplotsinvokeforeach
possui apenas um argumento de loop (observe que \pgfplotsforeachungrouped
suporta dois argumentos, mas não ajuda aqui).
Aqui está uma abordagem que fazsemprefuncionar, não importa quão complicados sejam seus loops:
\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}
Introduzi um artificial \edef
que cobre todo o corpo do loop. Isso \edef
significa "definição expandida": define \temp
ser o resultado totalmente expandido de tudo dentro das chaves. Isso se expandirá \y
para o valor do loop atual. Infelizmente, também irá (tentar) expandir-se \addplot
– o que é impossível. Para evitar essa expansão, escrevi a primitiva TeX \noexpand
na frente de \addplot
.
Finalmente, \temp
contém o corpo do loopsemquaisquer referências a \y
ou \x
. Podemos simplesmente executá-lo escrevendo \temp
no corpo do loop. Isso faz o trabalho.
Só para os curiosos: você poderia deixar a lista de coordenadas fora 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}
isso também funciona porque o TeX funciona por meio de expansão - assim que ele "executa" \temp
, ele não sabe mais nada sobre o fato de estar "dentro" \temp
e simplesmente lerá adiante.
Verhttp://pgfplots.sourceforge.net/TeX-programming-notes.pdfpara detalhes