受到另一个问题的评论的启发,我尝试概括一些代码以在函数图上绘制彩色矩形。
该例程\findmax
给定一个 x 值和一个函数,计算 [x, x+1] 上的最大函数值,并且输出显示它有效,即使在循环内也是如此。
另一个例程\maxboxes
,给定两个区间边界 a 和 b,以及一个函数,用于在区间 [a, b] 上放置图形上最大高度的彩色框,每个框宽度为一个单位。
我将其设置\xbridge
为半个单位,这样即使不使用\findmax
它也可以打印出中点框。这个例程也有效。但是,如果您取消\findmax
注释该调用,则会收到一个需要数字的错误,我已将其缩小到传入函数的使用。
那些传入的函数调用在该代码的其他情况下起作用,这件事让我抓狂。
注意:这两个函数都是初始设计,仅限于单位宽度的框,以便专注于基本思想。稍后我将考虑改变框宽度、最小框和平均框等。
请不要推荐已经可以使用的软件包,因为已经有几个问题可以这样做了。这只是我正在尝试的一个例子。
我意识到我的标题需要改进,但我真的不确定如何在 LaTeX 的上下文中表达它,因为它不像第三代编程语言。在输出中,左侧的数据列是最大值,后面是间隔的左侧加上最大值的水平边距。
MWE 输出
MWE 代码
\documentclass[12pt]{article}
\usepackage[a5paper,margin=14mm]{geometry}
\usepackage{pgfplots}
\pgfplotsset{compat=1.9}
\pgfplotsset{
maxbox/.style={draw=red, fill=red!10},
/pgf/declare function={F(\x)=((sqrt(3)*\x/2.5)^3-9*(sqrt(3)*\x/2.5);}
}
\newcounter{colstep}
\newlength{\xval}
\newlength{\xbridge}
\newlength{\currentval}
\newlength{\maxbar}
\newcommand{\findmax}[2]
{%#1=left side of interval #2=function to be evaluated
\pgfmathsetlength{\maxbar}{#2(#1)}
\setlength{\xbridge}{0pt}%
\foreach \i in {1,...,100}
{%
\pgfmathsetlength{\currentval}{#2(#1+\i/100)}
\ifdim\currentval>\maxbar
\setlength{\global\maxbar}{\currentval}%
\pgfmathsetlength{\global\xbridge}{\i/100}
\fi
}%
}
\newcommand{\maxboxes}[4]
{
%#1,#2=left and right boundaries of interval
%#3=style for drawing boxes
%#4=function to be evaluated
\setlength{\xbridge}{0.5pt}
\pgfmathsetcounter{colstep}{#2-1}
\foreach \i in {#1,...,\value{colstep}}
{
% \findmax{\i}%{#4}
\setlength{\xval}{\i pt}
\pgfmathsetlength{\xval}{\i+\xbridge}
\addplot [domain=\i:\i+1,#3,const plot]
{#4(\xval)}\closedcycle;
}
}
\begin{document}
%
\foreach \k in {-4,...,3}
{
\par \findmax{\k}{F}\the\maxbar\quad\k+\the\xbridge
}
%
\par\begin{tikzpicture}
\begin{axis}[
xlabel={$x$},ylabel={$y$},
xtick={-4,-2,2,4},ytick={-10,-5,5,10},
y=0.30cm, xmax=4.4,ymax=12,ymin=-12,xmin=-4.4,
enlargelimits=true,
axis lines=middle,
clip=false,
axis on top
]
\maxboxes{-4}{4}{maxbox}{F}
% Function graph
\addplot[smooth, thick,domain=-4:4]{F(\x)};
%
\end{axis}
%
\end{tikzpicture}
%
\end{document}
答案1
(此更新纳入了更好的做法,并避免对同一变量进行本地和全局分配,所以现在\setlength{\dimen@}{\currentval}\global\maxbar\dimen@
,嗯,不,简单地说\global\maxbar\currentval
,不知道为什么前者使用\setlength
其附带的补丁程序问题tikz
。两者都是变量,所以只有一个<glue>
不会出现任何问题。)\currentval
<dimen>
编辑:(根据 OP 的要求进行解释)
我要直接指出的是,我没有研究过pgf
源代码,也没有任何一般性的实践经验tikz
,所以只有花时间先做前两件事才能提供可靠的解释。
但是,通过在合适的位置添加\tracingmacros1
(而不是任何地方,否则会产生非常巨大的日志)我了解到,在tikzpicture
宏内部\setlength
重新定义了:
\setlength #1#2->\begingroup \pgfutil@selectfont \pgf@setlengthorig #1{#2}\expa
ndafter \endgroup \expandafter #1\expandafter =\the #1\relax
这与\global
in不兼容#1
,因为我们最终得到
\pgf@setlengthorig #1#2->#1#2\relax
#1<-\global
#2<-\maxbar
! Missing number, treated as zero.
<to be read again>
\relax
l.101 \maxboxes{-4}{4}{maxbox}{F}
如果新的\setlength
在#1
\setlength #1#2->\begingroup \pgfutil@selectfont \pgf@setlengthorig {#1}{#2}\expa
ndafter \endgroup \expandafter #1\expandafter =\the #1\relax
这仍然不起作用,因为#1
作为两个标记, \expandafter 不会按预期工作,而且该\the #1
部分清楚地表明#1
除了 dimen 或 skip 变量之外不能是任何其他东西。
另一方面,似乎\pgfmathsetlength
允许使用\global
。无论如何,似乎您在一个环境中工作而在另一个环境中不工作的原因之一就是环境对完成工作\findmax
的重新定义。\setlength
tikzpicture
\maxboxes
第二个问题似乎与的原始用法有关\i
。只需将所有出现的 替换\i
为\k
,它就可以正常工作。或者,\expandafter\findmax\expandafter{\i}{#4}
先将\i
展开。
请注意,您\k
在循环中使用了有效的方法:如果您在循环中执行相同操作,它\maxboses
也会起作用。但这似乎意味着需要知道\foreach
宏中循环使用的变量的名称,才能在另一个\foreach
循环中无冲突地使用此宏,因此最安全的方法是\expandafter
允许您使用同事的宏而无需检查其中迭代变量的调用方式。
关于使用 构建表格的困难\foreach
,正如我所说,我事先不了解源代码,但看起来\\
表格中的 的扩展会插入}
和诸如 之类的东西,{\begingroup}\endgroup
这些ERROR: Extra }, or forgotten \endgroup.
可能是您从 的试用中获得的\foreach
。实际上,很可能 将\foreach
迭代命令括在 中,\begingroup ... \endgroup
因此最终会出现这种{\begingroup}\endgroup
情况,{
位于表格单元格的开头,而}
的扩展则来自\\
。
在创建表格内部工作的循环时必须考虑到这些限制。在各种可能性中,我显然倾向于宣传使用我的包中完全可扩展\xintApplyUnbraced
或不完全可扩展但支持表格的宏:\xintFor
xint
\begin{tabular}{|rr@{}l|}
\hline\xintFor* #1 in {\xintSeq {-4}{+3}} \do
{\findmax{#1}{F}\the\maxbar&\quad #1+&\the\xbridge \\ }
\hline
\end{tabular}
或者:
\def\OneRow #1{\findmax {#1}{F}\the\maxbar & \quad #1+ &\the\xbridge \\ }
\begin{tabular}{|rr@{}l|}
\hline
\xintApplyUnbraced \OneRow {\xintSeq {-4}{+3}}
\hline
\end{tabular}
这让我意识到需要再修复一次,因为它忘记了对和的初始值\findmax
进行操作。与另一个表格单元格一样,使用的值是错误的。\global
\xbridge
\maxbar
\xbridge
\documentclass[12pt]{article}
\usepackage[a5paper,margin=14mm]{geometry}
\usepackage{pgfplots}
\pgfplotsset{compat=1.9}
\pgfplotsset{
maxbox/.style={draw=red, fill=red!10},
/pgf/declare function={F(\x)=((sqrt(3)*\x/2.5)^3-9*(sqrt(3)*\x/2.5);}
}
\newcounter{colstep}
\newlength{\xval}
\newlength{\xbridge}
\newlength{\currentval}
\newlength{\maxbar}
\newcommand{\findmax}[2]
{%#1=left side of interval #2=function to be evaluated
\pgfmathsetlength{\global\maxbar}{#2(#1)}%
\global\xbridge 0pt \relax
\foreach \i in {1,...,100}%
{%
\pgfmathsetlength{\currentval}{#2(#1+\i/100)}%
\ifdim\currentval>\maxbar
\global\maxbar\currentval
\pgfmathsetlength{\global\xbridge}{\i/100}%
% \global in \pgfmathsetlength is OK
\fi%
}%
}
\newcommand{\maxboxes}[4]
{%#1,#2=left and right boundaries of interval
%#3=style for drawing boxes
%#4=function to be evaluated
\setlength{\xbridge}{0.5pt}
\pgfmathsetcounter{colstep}{#2-1}
\foreach \i in {#1,...,\value{colstep}}
{
\expandafter\findmax\expandafter{\i}{#4}%
\setlength{\xval}{\i pt}
\pgfmathsetlength{\xval}{\i+\xbridge}
\addplot [domain=\i:\i+1,#3,const plot]
{#4(\xval)}\closedcycle;
}
}
\begin{document}
%
\foreach \k in {-4,...,3}
{
\par \findmax{\k}{F}\the\maxbar\quad\k+\the\xbridge
}
%
\par\begin{tikzpicture}
\begin{axis}[
xlabel={$x$},ylabel={$y$},
xtick={-4,-2,2,4},ytick={-10,-5,5,10},
y=0.30cm, xmax=4.4,ymax=12,ymin=-12,xmin=-4.4,
enlargelimits=true,
axis lines=middle,
clip=false,
axis on top
]
\maxboxes{-4}{4}{maxbox}{F}
% Function graph
\addplot[smooth, thick,domain=-4:4]{F(\x)};
%
\end{axis}
%
\end{tikzpicture}
%
\end{document}