我喜欢 TikZ 能够遍历多个变量,这些变量之间用斜线分隔foreach
(如下例所示)。我在 PGFplots 中寻找等效的东西?我在文档中看到,您不能foreach
像在 TikZ 中那样在 PGFplots 中嵌套,但这只会使这种功能变得更加重要。
另外两个小问题:
我喜欢这个\x
符号,所以我使用\pgfplotsforeachungrouped
。有什么理由我应该使用pgfplotsinvokeforeach
吗?
另外,使用变量来定义列表而不是在代码中使用实际列表的正确语法是什么。下面我希望能够\ListWithLabels
在 中引用foreach
。
\documentclass{minimal}
\usepackage{pgfplots}
\newcommand*{\ListWithLabels}{-2/a, -1/b, 1/c, 2/d}
\newcommand*{\ListWithoutLabels}{-2, -1, 1, 2}
\begin{document}
\begin{tikzpicture}
\draw [->][gray, thin](-3,0) -- (3,0) node[blue, right] {$x$};
\draw [->][gray, thin](0,-3) -- (0,3) node[blue, above] {$y$};
%\foreach \x/\l in \ListWithLabels { % works
\foreach \x/\l in {-2/a, -1/b, 1/c, 2/d} {
\draw [thick, red]
(\x,-2pt) -- (\x,2pt)
node [red, above] {\l};
}
\end{tikzpicture}
\begin{tikzpicture}
\begin{axis}[
minor tick num=0, axis y line=center, axis x line=middle,
xmin=-3, xmax=3, ymin=-3, ymax=3, xlabel=$x$, ylabel=$y$,
xtick={0}, xticklabels={}
]
%\pgfplotsinvokeforeach{-2, -1, 1, 2}{ % works
% \addplot [mark=none,color=red, thin, samples=2]
% coordinates{(#1,-0.05) (#1,0.05) };
%}
%\pgfplotsforeachungrouped \x in {\ListWithoutLabels}{ % does not work
\pgfplotsforeachungrouped \x in {-2, -1, 1, 2}{ % works
\addplot [mark=none,color=red, thick, samples=2]%
coordinates{ (\x,-0.08) (\x,0.08) };
}
%\pgfplotsforeachungrouped \x/\l in {-2/a, -1/b, 1/c, 2/d}{ % does not work
% \addplot [mark=none,color=red, thin, samples=2]%
% coordinates{ (\x,-0.05) (\x,0.05) }
% node [red, below] {\l};
%}
\end{axis}
\end{tikzpicture}
\end{document}
更新:我看见了这帖子解释了 TikZ 中的宏需要不是被包围{}
。但是这对 PGF 命令不起作用。
这是另一篇相关文章pgfplotsinvokeforeach 使用参数
答案1
pgfplots 有与\foreach
pgf/tikz 命令等同的命令,原因只有一个:作用域。有时,人们想要聚合事物,即计算循环体之外存在的值 —— 但该值也不是全局的。
如果您不关心范围并且不聚合事物,那么使用\foreach
可能是正确的选择。
您的解决方案可能是调整扩展序列,即以“正确的方式”用各自的值替换\x
和宏(见下文)。\l
但是,有一件事使得 pgfplots 中的循环有点技术性:轴首先只是收集其内容(评估轴限制等内容),然后是实际绘制内容的可视化阶段。不幸的是,这会导致扩展问题。如果\l
存储回来 - 并且直到最终\end{axis}
开始调查阶段并尝试恢复其含义时才进行实际评估,会发生什么?好吧 - 它失败了,因为\l
循环内部只有一个明确定义的含义。
Pgfplots 提供了\pgfplotsinvokeforeach
基本循环的功能:它不需要扩展并直接插入循环变量的值。
然而,最灵活的方法是调整扩展序列 - 它允许充分利用 TikZ\foreach
语句的灵活性;而且它并不是那么困难。
其使用方法如下:
\foreach \x/\l in {-2/a, -1/b, 1/c, 2/d}{
\edef\temp{\noexpand\addplot [mark=none,color=red, thin, samples=2]%
coordinates{ (\x,-0.05) (\x,0.05) }
node [red, below] {\l};
}
% \show\temp %-- uncomment this to see what the \temp macro does
\temp
}
所发生的情况是,在循环体内部\temp
定义了一个临时宏。\edef
是 TeX 指令(通常不用于 LaTeX)。它的意思是“扩展定义”。它定义\temp
为括号中参数的完全扩展结果。 的\noexpand
意思是“逐字插入下一个标记,而不是将其展开”。它扩展为\addplot
(即,它只是保留它)。使用 时\edef
,您需要在任何应保持原样的内容前加上\noexpand
。出现的\x
和\l
都被它们各自的值替换。最后,对 的调用将\temp
调用结果——并且它不知道封闭的循环。
coordinates {...}
还有一个细节:如果您在计算轴限值所需的任何内容内或内使用循环变量,它将直接展开(因为 pgfplots 需要调查数据)。只有像节点这样的可视化指令才会被推迟到\end{axis}
。
答案2
解决此扩展问题的一种不同方法。使用\pgfplotsinvokeforeach
和定义的键.code args
(基本上只是一个带有分隔参数的宏)。
如果你需要全部的力量,\foreach
你要么需要在情节中假装,正如解释的那样在另一个例子中
代码
\documentclass[tikz]{standalone}
\usepackage{pgfplots}
\newcommand*{\ListWithLabels}{-2/a, -1/b, 1/c, 2/d}
\newcommand*\pgfplotsinvokeforeachmacro[1]
{\expandafter\pgfplotsinvokeforeach\expandafter{#1}}
\begin{document}
\begin{tikzpicture}
\begin{axis}
\pgfplotsset{my plot/.code args={#1/#2}{%
\addplot[mark=none, color=red, thick, samples=2] coordinates {(#1,-.08) (#1,.08)}
node[red, below] {#2};}}
\pgfplotsinvokeforeachmacro\ListWithLabels{\pgfplotsset{my plot={#1}}}
\end{axis}
\end{tikzpicture}
\end{document}
具有依赖关系的代码
\documentclass[tikz]{standalone}
\usepackage{pgfplots}
\newcommand*{\ListWithLabels}{-2/a, -1/b, 1/c, 2/d}
\newcommand*\pgfplotsinvokeforeachmacro[1]
{\expandafter\pgfplotsinvokeforeach\expandafter{#1}}
\makeatletter
\pgfplotsset{my color/.code args={#1!#2!#3}{%
\pgfmathsetmacro\pgfplots@tempa{#2}%
\pgfkeysalso{color=#1!\pgfplots@tempa!#3}}}
\makeatother
\begin{document}
\begin{tikzpicture}
\begin{axis}
\pgfplotsset{my plot/.code args={#1/#2}{%
\addplot[mark=none, my color=red!(#1+2)/4*100!green, thick, samples=2]
coordinates {(#1,-.08) (#1,.08)} node[red, below] {#2};}}
\pgfplotsinvokeforeachmacro\ListWithLabels{\pgfplotsset{my plot={#1}}}
\end{axis}
\end{tikzpicture}
\end{document}
答案3
您可以使用不使用范围限制组的循环构造来解决此问题。
\documentclass[tikz]{standalone}
\usepackage{pgfplots}
\newcommand*{\ListWithLabels}{-2/a, -1/b, 1/c, 2/d}
\newcommand*{\ListWithoutLabels}{-2, -1, 1, 2}
\usepackage{xinttools}
\newcommand*{\ListWithLabelsForXintTools}{(-2, a), (-1, b), (1, c), (2, d)}
\begin{document}
\begin{tikzpicture}
\draw [->][gray, thin](-3,0) -- (3,0) node[blue, right] {$x$};
\draw [->][gray, thin](0,-3) -- (0,3) node[blue, above] {$y$};
%\foreach \x/\l in \ListWithLabels { % works
%\foreach \x/\l in {-2/a, -1/b, 1/c, 2/d} {
\xintForpair #1#2 in \ListWithLabelsForXintTools\do{% works too
\draw [thick, red]
(#1,-2pt) -- (#1,2pt)
node [red, above] {#2};
}
\end{tikzpicture}
\begin{tikzpicture}
\begin{axis}[
minor tick num=0, axis y line=center, axis x line=middle,
xmin=-3, xmax=3, ymin=-3, ymax=3, xlabel=$x$, ylabel=$y$,
xtick={0}, xticklabels={}
]
%\pgfplotsforeachungrouped \x in {\ListWithoutLabels}{ % does not work
\xintFor #1 in {\ListWithoutLabels}\do {% does work
\addplot [mark=none,color=red, thick, samples=2]%
coordinates{ (#1,-0.08) (#1,0.08) };
}
%\pgfplotsforeachungrouped \x/\l in {-2/a, -1/b, 1/c, 2/d}{ % does not work
\xintForpair #1#2 in {\ListWithLabelsForXintTools}\do {% does work
\addplot [mark=none,color=red, thin, samples=2]%
coordinates{ (#1,-0.05) (#1,0.05) }
node [red, below] {#2};
}
\end{axis}
\end{tikzpicture}
\end{document}
生成:
和
我希望这是预期的输出(我不是 TikZ 专家;-)
)。