当尝试制作一系列阶跃函数图形时,我写了以下代码片段:
\begin{tikzpicture}
\pgfmathsetmacro{\n}{2^3};
\pgfmathsetmacro{\step}{1/\n};
\foreach \i in {0,\step,...,(\n-1)*\step}
{\draw[-,thick,blue] (\i,{\i*2})--({\i+\step},{\i*2});}
\end{tikzpicture}
我的想法是,我想定义变量\n
,\step
这样我所要做的就是调整\n
设置的值,然后它将在很多大小相同的部分中绘制一个阶跃函数,等等等等。我将使用它在同一个文档中制作许多不同的图片。
但是,似乎以这种方式定义变量是不合法的 - 至少,我是这样认为的,因为当我不使用变量编写这个程序时它似乎工作正常。
有没有办法在tikzpicture
环境中“全局”定义变量?
我突然想到......我可以执行以下操作吗?
\begin{tikzpicture}
\foreach \n in {2^3} {
\foreach \step in {1/n} {
\foreach \i in {0,\step,...,(\n-1)*\step}
{\draw[-,thick,blue] (\i,{\i*2})--({\i+\step},{\i*2});}
}}
\end{tikzpicture}
即使它有效,它也确实看起来像一个脆弱的黑客...而且我猜一定有某种原因导致我从未见过有人建议这样做...尽管我实际上无法说出它不好的原因。
有什么原因导致它不起作用或者不好吗?
更新:测试了一下,虽然没有完全损坏,但并没有完全起作用,但仍在试图理解它为什么会这样做。
答案1
循环\foreach
不会自行评估其列表的任何条目。并且在语法之后,...
它需要“看到”一个有效的数字。
在这种情况下,您可以parse = true
强制 PGFFor 评估其列表中的最后一个条目。
在第二种情况下,我使用use float
来自ext.misc
我的tikz-ext
包的库的密钥。请注意,它是在声明变量后使用的,并且没有任何in <list>
部分!此密钥将为您评估所有条目。
在第三和第四种情况下,我使用整数步长,并且只缩放绘图或坐标坐标系。这样我们就可以避免可能出现的浮点数误差。(不过,在我下面使用的例子中,它们并不存在。)
在第五种情况下,我使用了一个绘图来帮我们完成所有计算。当然,这只是本例中的有效解决方案。
代码
\documentclass[tikz]{standalone}
\usetikzlibrary{ext.misc}
\makeatletter
\tikzset{scale xyz/.code=\pgfmathparse{#1}%
\pgf@xx\pgfmathresult\pgf@xx \pgf@xy\pgfmathresult\pgf@xy
\pgf@yx\pgfmathresult\pgf@yx \pgf@yy\pgfmathresult\pgf@yy
\pgf@zx\pgfmathresult\pgf@zx \pgf@zy\pgfmathresult\pgf@zy}
\makeatother
\newcommand*\myRow[1]{
\node[right] at (0,1) {$n = \pgfmathprint{int(#1)}$};
\pgfmatrixnextcell
% Case 1: everything the same but parse the last entry
\pgfmathsetmacro{\n}{#1}
\pgfmathsetmacro{\step}{1/\n}
\foreach[parse=true] \i in {0, \step, ..., (\n-1)*\step}
\draw (\i,\i*2) -- +(right:\step);
\pgfmatrixnextcell
% Case 2: use float = <start> to <end> step <step>
\foreach \i[use float = 0 to (#1-1)/#1 step 1/#1]
\draw (\i,\i*2) -- +(right:1/#1);
\pgfmatrixnextcell
% Case 3: use integer steps (and parsing the last entry)
% and divide by #1 when drawing
\foreach[parse=true] \i in {0,...,#1-1}
\draw (\i/#1,2*\i/#1) -- +(right:1/#1);
\pgfmatrixnextcell
% Case 4: scale xyz coordinate system by 1/#1
% and use integer steps
\tikzset{scale xyz = 1/#1}% i.e. scale = 1/8
\foreach[parse=true] \i in {0,...,#1-1}
\draw (\i,2*\i) -- +(right:1);
\pgfmatrixnextcell
% Case 5: Maybe a plot?
\draw[scale xyz=1/#1] plot[jump mark left, domain=0:#1, samples=#1+1] (\x,2*\x);
\pgfmatrixendrow}
\begin{document}
\tikz[
row sep=5mm, column sep=5mm, thick, blue,
every cell/.style 2 args={
style/.expand twice={\ifnum#2>1 \ifnum#1>1
execute at begin cell={\draw[help lines] (0,0) grid (1,2);}\fi\fi}}]
\matrix[row 5/.style=thin, row 1/.style={shift=(right:.5)}]{
&\node{Case 1}; &\node{Case 2}; &\node{Case 3}; &\node{Case 4}; &\node{Case 5};\\
\myRow{2^3} \myRow{3^3} \myRow{5} \myRow{35} \myRow{73}};
\end{document}
输出
答案2
我会使用更好的浮点系统。
\documentclass{article}
\usepackage{tikz}
\ExplSyntaxOn
\NewDocumentCommand{\fpstep}{mmmm}
{
\fp_step_inline:nnnn { #1 } { #2 } { #3 } { #4 }
}
\NewDocumentCommand{\definefpvar}{mm}
{
\fp_zero_new:c { l_addem_fpvar_#1_fp }
\fp_set:cn { l_addem_fpvar_#1_fp } { #2 }
}
\NewExpandableDocumentCommand{\fpvar}{m}
{
\fp_use:c { l_addem_fpvar_#1_fp }
}
\ExplSyntaxOff
\begin{document}
\begin{tikzpicture}
\definefpvar{n}{2^3}
\definefpvar{step}{1/(\fpvar{n})}
\fpstep{0}{\fpvar{step}}{(\fpvar{n}-1)*\fpvar{step}}
{\draw[-,thick,blue] (#1,{#1*2})--({#1+\fpvar{step}},{#1*2});}
\end{tikzpicture}
\end{document}
而不是\foreach
,因为它对浮点值的表现实际上并不十分准确,而是\fp_step_inline:nnnn
使用 函数。第四个参数#1
代表循环中的当前值。第一个参数是起点,第二个参数是步骤,第三个参数是终点。