使用 pgfplots,为什么在尝试使用 foreach 变量作为 addplot 的参数时会出现“未定义的控制序列”?

使用 pgfplots,为什么在尝试使用 foreach 变量作为 addplot 的参数时会出现“未定义的控制序列”?

由于我有多个带有误差线的图,我想稍微移动误差线以使整个图更具可读性。但是,当我尝试使用变量 a\foreach作为移动量来执行此操作时,我收到“未定义的控制序列”错误。

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

(当我取消注释两条注释中的任意一条时,文档无法编译。)

这里有什么问题?

编辑:向 添加了另一个变量\foreach。在我的实际用例中,它将包含要绘制数据的文件名或用于曲线的标签。

答案1

该问题是一个宏扩展问题:\y变量稍后被评估 - 但在那个“稍后”的时间,循环已经完成并且\y未定义。

如前所述,\pgfplotsinvokeforeach只有一个循环参数(请注意,\pgfplotsforeachungrouped支持两个参数,但在这里没有帮助)。

这里有一种方法可以总是不管你的循环有多复杂,它都可以工作:

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

\edef我引入了一个覆盖整个循环体的人工方法。这\edef意味着“扩展定义”:它定义\temp为花括号内所有内容的完全扩展结果。这将扩展\y到当前循环值。不幸的是,它也会(试图)扩展- 这是不可能的。为了避免这种扩展,我在前面\addplot写了 TeX 原语。\noexpand\addplot

最后,\temp包含循环体没有任何对\y或 的引用\x。我们可以简单地通过写入\temp循环体来执行它。这样就完成了工作。


只是出于好奇:你可以将坐标列表留在\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}

这也确实有效,因为 TeX 通过扩展来工作 - 一旦它“执行” \temp,它就不再知道它在“内部”的事实,\temp并且只会提前读取。

http://pgfplots.sourceforge.net/TeX-programming-notes.pdf了解详情

相关内容