我想为 定义新函数,以便pgf
在 中使用它pgfplots
。我正在尝试创建一个单位脉冲函数 p(x),其值从 x=0 到 x=1 为 1,其他地方为 0。
我读过pgf 手册关于自定义数学引擎(第 65 节,第 541 页),但我可能误解了一些东西 =P
此代码不起作用:
\documentclass{minimal}
\usepackage{pgfplots}
\pgfmathdeclarefunction{p}{1}{%
\pgfmathand{\pgfmathless{#1}{1}} {\pgfmathgreater{#1}{0}}%
}
\begin{document}
\begin{tikzpicture}
\begin{axis}
\addplot {p(x)};
\end{axis}
\end{tikzpicture}
\end{document}
答案1
pgfmathparse
我通过使用内部让它工作pgfmathdeclarefunction
(我不知道这是否是你应该做的,但我现在很满意)
我也可以使用 来在本地定义它declare function
。
\documentclass{letter}
\usepackage{pgfplots}
\usepackage{setspace}
\doublespacing
\pgfmathdeclarefunction{p}{1}{%
\pgfmathparse{and(#1>0, #1<1)}%
}
\begin{document}
My pgf version is: \pgfversion
p(0.2) is \pgfmathparse{p(0.2)}\pgfmathresult
p(2) is \pgfmathparse{p(2)}\pgfmathresult
Plot of p(x):
\begin{tikzpicture}
\begin{axis}
\addplot[domain=-5:5, samples=50]{p(x)};
\end{axis}
\end{tikzpicture}
Using declare function to define localp(x):
\begin{tikzpicture}
[
declare function={
localp(\t) = and(\t > 0, \t < 1);
}
]
\begin{axis}
\addplot[domain=-5:5, samples=50]{localp(x)};
\end{axis}
\end{tikzpicture}
\end{document}
答案2
我想我可以对这里的问题提供更多见解。
首先的好消息是:提供\begin{axis}[use fpu=false]
将使您能够使用所有自定义数学函数(我猜,只要它们在 pgf 中工作)。
现在详细介绍一下:让我总结一下讨论的状态:当我们在 pgfplots 中使用自定义数学函数时,我们有
- 包含 `\pgf@x=#1pt` 的解决方案导致
! Illegal unit of measure (pt inserted). Y l.24 \addplot[domain=-5:5, samples=50]{double(x)};
- 使用 `\pgfmathmultiply{#1}{#1}` 的解决方案有效
- 使用 `\pgfmathparse` 的解决方案同样有效
- 使用 `\pgfmathand{\pgfmathless{#1}{1}}{\pgfmathgreater{#1}{0}}` 的解决方案失败了(在我的例子中,`!Extra else` 出现了一些奇怪的问题
问题是由于 PGFPlots 的初始配置为“use fpu=true”造成的。fpu 是一个 PGF 库;它用单精度浮点之类的东西替换了数学模块。
只要用户贡献的数学函数仅依赖于高级数学函数(如\pgfmathparse
或\pgfmathmultiply
如上所述),代码库就会透明地使用 FPU - 并且一切都是一致的。
但是,一旦使用 TeX 寄存器,情况就会变得不同:写入\pgf@x=#1pt
意味着第一个参数被解释为范围为 -16000...16000(大致)的定点数。使用use fpu=true
,两者本质上都被违反:fpu 既没有定点数,也不限于此数据范围。出现错误消息是因为(在撰写本文时),浮点数的存储方式类似于1Y1.0e1
将Y
“标志”与尾数分开。Y
是第一个字符,其中\pgf@x=#1pt
退出。但是请注意,FPU 足够智能,可以检测自定义函数的返回值是 TeX 寄存器数还是浮点数。但我不知道有任何方法可以询问“该函数是否会处理浮点数?”。
因此,正如前面提到的,use fpu=false
禁用 FPU;然后 pgfplots 将使用 -16000...16000 范围内的定点数进行操作,并且所有数学函数都应该可以工作。
另一个解决方案是使用基本层数学函数,如\pgfmathmultiply
。请注意,除非我弄错了,否则\pgfmathmultiply
也会调用\pgfmathparse
(这很昂贵)。用于\pgfmathmultiply@
抑制参数解析(但是,\makeatletter
在定义自定义函数之前需要)。
不幸的是,我不知道\pgfmathand{} {}
解决方案为什么会失败。它在 PGF 中有效吗?
我希望这对您有帮助。
答案3
我建议使用这个非常简单的代码:
\documentclass{minimal}
\usepackage{tikz}
\makeatletter
\pgfmathdeclarefunction{p}{1}{\edef\pgfmathresult{\ifdim#1pt<\z@0\else\ifdim#1pt>1pt 0\else1\fi\fi}}
\makeatother
\begin{document}
\begin{tikzpicture}
\draw[very thin,color=gray] (-2,-2) grid (2,2);
\draw[color=blue] plot (\x,{p(\x)});
\end{tikzpicture}
\end{document}
答案4
我只用 pgfmanual 中的一个示例(第一个示例)修改了我的答案\pgfmathdeclarefunction
。pgfmanual 中的这个示例适用于 pgf,而不适用于 pgfplots(为什么???)
带有 pgfplots 的部分出现 Latex 错误:./add_func_pgfplots.tex:77 非法测量单位(插入 pt)。
\documentclass{minimal}
\usepackage{pgfplots}
\makeatletter
\pgfmathdeclarefunction{double}{1}{%
\begingroup
\pgf@x=#1pt\relax
\multiply\pgf@x by2\relax
\pgfmathreturn\pgf@x
\endgroup
}
\makeatother
\begin{document}
\pgfmathparse{double(44.3)}\pgfmathresult
\begin{tikzpicture}
\draw plot [domain=0:5, samples=144, smooth] (\x,{double(\x)});
\end{tikzpicture}
\begin{tikzpicture}
\pgfmathdouble{1}
\let\ra\pgfmathresult
\draw (0,0) circle (\ra);% \ra is fine
% \begin{axis}
% \addplot[domain=-5:5, samples=50]{double(x)};
% \end{axis}
\end{tikzpicture}
\end{document}
但是这个代码有效
\documentclass{scrartcl}
\usepackage{pgfplots}
\begin{document}
My pgf version is: \pgfversion
\pgfmathdeclarefunction{double}{1}{
\begingroup
\pgfmathmultiply{#1}{#1} % instead of \pgfmathparse{#1*#1} from kristi
\endgroup
}
\begin{tikzpicture}
\begin{axis}
\addplot[domain=-5:5, samples=50]{double(x)};
\end{axis}
\end{tikzpicture}
\end{document}
主要问题\pgfmathparse
是,如果我们需要做很多循环,代码就会很慢