Почему при использовании 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}

Я ввел artifical \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для подробностей

Связанный контент