Mathematica还处于早期阶段,所以请原谅可能是一个非常明显的问题。我试图生成一些参数图。我有:
ParametricPlot[{
(a + b) Cos[t] - h Cos[(a + b)/b t],
(a + b) Sin[t] - h Sin[(a + b)/b t]},
{t, 0, 2 \[Pi]}, PlotRange -> All] /. {a -> 2, b -> 1, h -> 1}
没有快乐:未应用替换规则且a
,b
和h
仍未定义。
如果我改为:
Hold@ParametricPlot[{
(a + b) Cos[t] - h Cos[(a + b)/b t],
(a + b) Sin[t] - h Sin[(a + b)/b t]},
{t, 0, 2 \[Pi]}, PlotRange -> All] /. {a -> 2, b -> 1, h -> 1}
看起来规则正在运行,如输出所确认的那样:
Hold[ParametricPlot[{(2 + 1) Cos[t] -
1 Cos[(2 + 1) t], (2 + 1) Sin[t] - 1 Sin[(2 + 1) t]}, {t, 0,
2 \[Pi]}, PlotRange -> All]]
这是我所期待的。但请关闭Hold
,ParametricPlot
不起作用。然而,方程式或ParametricPlot
本身没有任何问题,因为我尝试在单独的表达式(a=2; b=1; h=1
)中设置a,b和h的值,并且我按照预期得到了漂亮的双重心形。
那么,我对ReplaceAll
做错了什么,为什么转换规则不起作用?这是MMA的另一个根本重要的方面,我的OOP毁了大脑不理解。
我尝试阅读ReplaceAll
和ParametricPlot
,我发现最接近的线索是“ParametricPlot
具有属性HoldAll
并仅在分配后评估f
变量的具体数值“没有多大帮助,或者我不会在这里。
感谢。
答案 0 :(得分:4)
Mathematica通过首先评估每个子表达式的头部来评估每个头而不保持属性。由于ReplaceAll没有保留属性,因此ParametricPlot
在替换之前变为Graphics
要查看表达式树,请执行
ParametricPlot[{(a + b) Cos[t] - h Cos[(a + b)/b t], (a + b) Sin[t] -
h Sin[(a + b)/b t]}, {t, 0, 2 \[Pi]},
PlotRange -> All] /. {a -> 2, b -> 1, h -> 1} // Hold // TreeForm
从该树中您可以看到您的命令与执行
相同temp1=ParametricPlot[{(a + b) Cos[t] - h Cos[(a + b)/b t], (a + b) Sin[t] -
h Sin[(a + b)/b t]}, {t, 0, 2 \[Pi]},
PlotRange -> All]
temp2={a -> 2, b -> 1, h -> 1}
temp1/.temp2
查看FullForm[temp1]
以确认该表达式中没有a
或b
。
如果您将ReplaceAll
设置为HoldFirst
,则会阻止在ReplaceAll
之前评估ParametricPlot,并且结果符合您的预期。在这种情况下,ReplaceAll
会使用头部ParametricPlot
评估表达式,并且仅在此时评估ParametricPlot
。确保重新设置属性,因为更改内置命令的行为会产生意外的副作用。
SetAttributes[ReplaceAll, HoldFirst];
ParametricPlot[{(a + b) Cos[t] - h Cos[(a + b)/b t], (a + b) Sin[t] -
h Sin[(a + b)/b t]}, {t, 0, 2 \[Pi]},
PlotRange -> All] /. {a -> 2, b -> 1, h -> 1}
ClearAttributes[ReplaceAll, HoldFirst]
当需要评估通过HoldAll
传递给函数的参数时,一个有用的技巧是对具有List
头的表达式执行操作,并在最后替换ParametricPlot
,例如
ParametricPlot @@ ({{(a + b) Cos[t] -
h Cos[(a + b)/b t], (a + b) Sin[t] - h Sin[(a + b)/b t]}, {t, 0,
2 \[Pi]}, PlotRange -> All} /. {a -> 2, b -> 1, h -> 1})
答案 1 :(得分:3)
在Mathematica中使用局部变量的最佳方法是Module[]
:
Module[{a = 2, b = 1, h = 1},
ParametricPlot[{(a + b) Cos[t] - h Cos[(a + b)/b t], (a + b) Sin[t] - h Sin[(a + b)/b t]},
{t, 0, 2 \[Pi]},
PlotRange -> All]]
这样,a,b和h在全局上下文中不会被赋值,而只能在Module
内。如果您仍想使用替换规则,则在完成替换后只需ReleaseHold
:
ReleaseHold[
Hold@ParametricPlot[{(a + b) Cos[t] - h Cos[(a + b)/b t], (a + b) Sin[t] - h Sin[(a + b)/b t]},
{t, 0, 2 \[Pi]},
PlotRange -> All] /. {a -> 2, b -> 1, h -> 1}]
编辑:至于为什么会这样。我理解它的方式,HoldAll
可以防止函数的参数被任何规则(内部或显式)修改。你的Hold
所做的是将整个函数置于保持状态(而不仅仅是参数),并且在函数经过评估之后应用了替换规则(事实并非如此)还有一些东西要替换)并且HoldAll
不再有效。
In[1] := Hold[a /. a -> 5]
Out[1] := Hold[a /. a -> 5]
In[2] := Hold[a] /. a -> 5
Out[2] := Hold[5]
当然,Hold
也有HoldAll
作为属性,因此这并不能解释为什么ParametricPlot
的{{1}}不同。 : - (
EDIT2:我使用HoldAll
来查看会发生什么,似乎Trace
只在最后才应用ReplaceAll
变成了一个图形对象(并且不再包含a,b或h)。在ParametricPlot
的情况下,保持评估为Hold[a] /. a -> 5
,然后可以成功应用替换规则。
答案 2 :(得分:3)
这就是ReplaceAll始终有效的方式。
参见例如:
In[10]:= (a/a) /. a -> 0
Out[10]= 1
显然,替换是在评估后完成的,因为如果你这样做:
In[11]:= a = 0; a/a
During evaluation of In[11]:= Power::infy: Infinite expression 1/0 encountered. >>
During evaluation of In[11]:= Infinity::indet: Indeterminate expression 0 ComplexInfinity encountered. >>
Out[12]= Indeterminate
现在,需要在您希望它运行的级别插入替换件。由于Plot的结果基本上是数字坐标已经“已解决”的图像,因此您需要在计算绘图之前将这些坐标放在中。在你的情况下:
ParametricPlot[
{(a + b) Cos[t] - h Cos[(a + b)/b t], (a + b) Sin[t] - h Sin[(a + b)/b t]}
/. {a -> 2, b -> 1, h -> 1},
{t, 0, 2 \[Pi]},
PlotRange -> All
]
答案 3 :(得分:1)
这不是一个答案,只是对使用带有绘图的模块的评论。
如果我按以下步骤进行
f[t_] := {(a + b) Cos[t] - h Cos[(a + b)/b t], (a + b) Sin[t] -
h Sin[(a + b)/b t]}
以下内容无效
方法1:
Module[{a = 2, b = 1, h = 1},
ParametricPlot[f[t], {t, 0, 2 \[Pi]}, PlotRange -> All]]
方法2:
Module[{a = 2, b = 1, h = 1},
ParametricPlot[Evaluate[f[t]], {t, 0, 2 \[Pi]}, PlotRange -> All]]
以下工作(方法3)
ParametricPlot[
Module[{a = 2, b = 1, h = 1}, Evaluate[f[t]]], {t, 0, 2 \[Pi]},
PlotRange -> All]
与上述方法(方法4)一样
Module[{a = 2, b = 1, h = 1},
ParametricPlot[{(a + b) Cos[t] - h Cos[(a + b)/b t], (a + b) Sin[t] - h Sin[(a + b)/b t]},
{t, 0, 2 \[Pi]},
PlotRange -> All]]
任何人都可以解释为什么方法4有效但方法2没有? (同样适用于With,我发现对模块更直观)。
为了它的价值,我将使用替换规则生成原始参数图,如下所示:
ParametricPlot[
Evaluate[{(a + b) Cos[t] - h Cos[(a + b)/b t], (a + b) Sin[t] -
h Sin[(a + b)/b t]}] /. {a -> 2, b -> 1, h -> 1}, {t, 0,
2 \[Pi]}, PlotRange -> All]
修改
f[x_] := (a x)/(b + x);
With[{a = 10, b = 100}, Plot[Evaluate[f[x]], {x, 0, 100}]]
With[{a = 10, b = 100}, Plot[(a x)/(b + x), {x, 0, 100}]]
Plot[With[{a = 10, b = 100}, Evaluate[f[x]]], {x, 0, 100}]
Plot[Evaluate[f[x]] /. {a -> 10, b -> 100}, {x, 0, 100}]
方法1(编辑)不起作用(因为'Plot'将变量x视为本地,有效地使用Block'?)
在我看来,对于任何人来说都是绝对清楚的,即使是对Mathematica有基本知识的人,方法2的内容,显示了Mathematica的强大功能和易用性。当方程变得更复杂时,单独定义它们是有利的。现在不太清楚,必须使用方法3而不是方法1.(方法4,当然,可能是最好的。)