在回应这个帖子我想知道是否可以编写循环里面 addplot
调用。我实际上指的是循环内部addplot
,而不是循环addplot
内部for
(只是为了让自己清楚)。
我对这篇文章的回答涉及绘制多个函数,这些函数是给定频率的谐波的总和,这会产生多个addplot
仅在总和的一个项上不同的调用。
\addplot {sin(4*0.5*\x r)/0.5};
\addplot {sin(4*0.5*\x r)/0.5 + sin(4*1.5*\x r)/1.5};
\addplot {sin(4*0.5*\x r)/0.5 + sin(4*1.5*\x r)/1.5 + sin(4*2.5*\x r)/2.5};
\addplot {sin(4*0.5*\x r)/0.5 + sin(4*1.5*\x r)/1.5 + sin(4*2.5*\x r)/2.5 + sin(4*3.5*\x r)/3.5};
\addplot {sin(4*0.5*\x r)/0.5 + sin(4*1.5*\x r)/1.5 + sin(4*2.5*\x r)/2.5 + sin(4*3.5*\x r)/3.5 + sin(4*4.5*\x r)/4.5};
\addplot {sin(4*0.5*\x r)/0.5 + sin(4*1.5*\x r)/1.5 + sin(4*2.5*\x r)/2.5 + sin(4*3.5*\x r)/3.5 + sin(4*4.5*\x r)/4.5 + sin(4*5.5*\x r)/5.5};
我觉得这不是很优雅,我想知道是否有办法避免这种情况,使用类似
\addplot {sum[nmin,nmax,n](sin(\n*0.5*\x r)/0.5)};
其中nmin
/nmax
是总和的起始/终止索引。这个问题可以推广到乘积或其他 for 循环。
以下是测试此问题的 MWE
\documentclass[tikz,border=10pt]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.5}
\usepgfplotslibrary{colorbrewer}
\pgfplotsset{cycle list/Reds-6}
\begin{document}
\begin{tikzpicture}
\begin{axis}[%
width=\textwidth,
axis x line=bottom,
axis y line=left,cycle multi list={Reds-6}]
\addplot+[samples=300,smooth] {sin(4*0.5*\x r)/0.5};
\addplot+[samples=300,smooth] {sin(4*0.5*\x r)/0.5 + sin(4*1.5*\x r)/1.5};
\addplot+[samples=300,smooth] {sin(4*0.5*\x r)/0.5 + sin(4*1.5*\x r)/1.5 + sin(4*2.5*\x r)/2.5};
\addplot+[samples=300,smooth] {sin(4*0.5*\x r)/0.5 + sin(4*1.5*\x r)/1.5 + sin(4*2.5*\x r)/2.5 + sin(4*3.5*\x r)/3.5};
\addplot+[samples=300,smooth] {sin(4*0.5*\x r)/0.5 + sin(4*1.5*\x r)/1.5 + sin(4*2.5*\x r)/2.5 + sin(4*3.5*\x r)/3.5 + sin(4*4.5*\x r)/4.5};
\addplot+[samples=300,smooth] {sin(4*0.5*\x r)/0.5 + sin(4*1.5*\x r)/1.5 + sin(4*2.5*\x r)/2.5 + sin(4*3.5*\x r)/3.5 + sin(4*4.5*\x r)/4.5 + sin(4*5.5*\x r)/5.5};
\end{axis}
\end{tikzpicture}
\end{document}
答案1
我设置了一个模板,并用它来listofitems
解析它?
\readlist\termstencil{sin(4*?.5*\x r)/?.5}
?
然后,在每次循环中用替换的值0
,然后1
,...,5
。必须进行一些检查以确保不在+
第一个术语之前添加 ,等等。将生成的标记收集到宏 中\myeqn
,然后将其传递给\addplot
。
\documentclass[tikz,border=10pt]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.5}
\usepgfplotslibrary{colorbrewer}
\pgfplotsset{cycle list/Reds-6}
\usepackage{listofitems}
\makeatletter
\newcommand\loopthroughterm[1]{%
\def\myeqn{}%
\foreach\z in{0,...,#1}{%
\ifnum\z=0\relax\else\g@addto@macro\myeqn{+}\fi%
\foreachitem\zz\in\termstencil[]{%
\ifnum\zzcnt=1\else%
\expandafter\g@addto@macro\expandafter\myeqn\expandafter{\z}\fi%
\expandafter\g@addto@macro\expandafter\myeqn\expandafter{\zz}%
}%
}%
}
\makeatother
\begin{document}
\begin{tikzpicture}
\begin{axis}[%
width=\textwidth,
axis x line=bottom,
axis y line=left,cycle multi list={Reds-6}]
\setsepchar{?}
\readlist\termstencil{sin(4*?.5*\x r)/?.5}
\foreach\k in{0,...,5}{
\loopthroughterm{\k}
\addplot+[samples=300,smooth] {\myeqn};
}
\end{axis}
\end{tikzpicture}
\end{document}
退出后tikzpicture
,可以\detokenize\expandafter{\myeqn}
确认用于最终循环索引的令牌本身:
附录
看到 jbfu 使用了辅助宏,我意识到我可以使用相同的概念来省去这种listofitems
方法,而不是使用另一个包来代替它。
基本上,我让\loopthroughterm
宏创建一系列形式为 的标记\termstencil{0}+\termstencil{1}+\termstencil{2}...
。然后,只要\termstencil
用户正确定义 ,在本例中为
\def\termstencil#1{sin(4*#1.5*\x r)/#1.5}
那么最终一切都会顺利。
\documentclass[tikz,border=10pt]{standalone}
\usepackage{pgfplots}
\usepackage[T1]{fontenc}
\pgfplotsset{compat=1.5}
\usepgfplotslibrary{colorbrewer}
\pgfplotsset{cycle list/Reds-6}
\makeatletter
\newcommand\loopthroughterm[1]{%
\def\myeqn{}%
\foreach\z in{0,...,#1}{%
\ifnum\z=0\relax\else\g@addto@macro\myeqn{+}\fi%
\expandafter\g@addto@macro\expandafter\myeqn\expandafter{%
\expandafter\termstencil\expandafter{\z}}%
}%
}
\makeatother
\begin{document}
\begin{tikzpicture}
\begin{axis}[%
width=\textwidth,
axis x line=bottom,
axis y line=left,cycle multi list={Reds-6}]
\def\termstencil#1{sin(4*#1.5*\x r)/#1.5}
\foreach\k in{0,...,5}{
\loopthroughterm{\k}
\addplot+[samples=300,smooth] {\myeqn};
}
\end{axis}
\end{tikzpicture}
\end{document}
情节与之前的代码相同,但是去标记化的形式\myeqn
现在是这样的:
此外,使用几个额外的\expandafter
s,形式为
\newcommand\loopthroughterm[1]{%
\def\myeqn{}%
\foreach\z in{0,...,#1}{%
\ifnum\z=0\relax\else\g@addto@macro\myeqn{+}\fi%
\expandafter\expandafter\expandafter\g@addto@macro\expandafter%
\expandafter\expandafter\myeqn\expandafter\expandafter\expandafter{%
\expandafter\termstencil\expandafter{\z}}%
}%
}
最终版本\myeqn
包含实际需要的 token:
答案2
这里是带有的xinttools
。我怀疑(但没有检查)不可扩展循环不能在\addplot
参数内部使用,因此我定义了初步宏\myterm
以与可扩展实用程序\xintApply
和一起使用\xintListWithSep
。
外部\xintFor
是不可扩展的,并且免除了我们任何初步的宏定义。
\documentclass[tikz,border=10pt]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.5}
\usepgfplotslibrary{colorbrewer}
\pgfplotsset{cycle list/Reds-6}
\usepackage{xinttools}
\begin{document}
\begin{tikzpicture}
\def\myterm#1{sin(4*#1.5*\x r)/#1.5}
\begin{axis}[%
width=\textwidth,
axis x line=bottom,
axis y line=left,cycle multi list={Reds-6}]
\xintFor #1 in {0, 1, 2, 3, 4, 5} \do
{%
\addplot+[samples=300,smooth]
{\xintListWithSep{+}{\xintApply\myterm{\xintSeq{0}{#1}}}};
}
\end{axis}
\end{tikzpicture}
\end{document}