操纵语句中的表达式评估

时间:2011-08-31 21:00:28

标签: wolfram-mathematica

我在使用Manipulate处理分配给应在Manipulate语句中评估的变量的代码时遇到问题。这是怎么回事......

test1={a,b,c};
Manipulate[test1,{a,0,10,.1},{b,0,10,.1},{c,0,10,.1}]

Manipulate output 1

因此{a, b, c}未更新。好吧,无论如何,让我们强制执行test1的评估

Manipulate[Evaluate[test1],{a,0,10,.1},{b,0,10,.1},{c,0,10,.1}]

enter image description here

现在它有效。但是如果我想绘制被操纵元素的列表,比如这个

Manipulate[ListPlot[Evaluate[test1]],{a,0,10,.1},{b,0,10,.1},{c,0,10,.1}]
Manipulate[Evaluate[ListPlot[test1]],{a,0,10,.1},{b,0,10,.1},{c,0,10,.1}]

我最终得到了

enter image description here

两个追逐。

我在Mathematica的文档中知道'Evaluate Expressions inside Dynamic or Manipulate',但我很确定它不能解决我的问题。

2 个答案:

答案 0 :(得分:8)

所以问题是test1是根据全局变量Global`a定义的, 但是操纵中定义的a是由DynamicModule创建的,因此是本地的。这是aclHold[a]示例中显示的内容。

也许解决此问题的最简单方法是使用Withtest1插入操作中:

Clear[a, b, c]
test1 = {a, b, c};
With[{test1 = test1}, 
     Manipulate[test1, {a, 0, 10, .1}, {b, 0, 10, .1}, {c, 0, 10, .1}]]

这样Manipulate实际上看不到test1,它看到的只是{a,b,c}然后继续正确本地化。但是,如果a,b,cManipulate运行之前被赋予了值,那么这将遇到问题 - 因此Clear[a,b,c]命令。

我认为最佳实践是在操作中使所有局部变量完全显式。所以你应该做类似

的事情
Clear[a, b, c, test1]
test1[a_, b_, c_] := {a, b, c};
Manipulate[test1[a, b, c], {a, 0, 10, .1}, {b, 0, 10, .1}, {c, 0, 10, .1}]

这可以避免您遇到的全局变量和局部变量的问题。当您必须回来再次阅读自己的代码时,它也会让您更轻松。


编辑以回答评论中的问题“我真的想了解为什么评估不适用于有点嵌套的ListPlot?”。 IANLS(我不是Leonid Shifrin)所以我的大脑中没有完美的Mathematica(nonstandard评估序列,但我会尝试解释发生了什么

好的,与Plot不同,ListPlot不需要本地化任何变量,因此它没有Attribute HoldAll

让我们定义类似于你的例子:

ClearAll[a, test]
test = {a, a + 1};

您提供的最后一个例子就像

Manipulate[Evaluate[ListPlot[test]], {a, 0, 1}]

通过查看Trace,您会看到这首先评估第一个参数ListPlot[test] ~> ListPlot[{a,a+1}] 由于a尚未本地化,因此会生成一个空列表图。要看到这一点,只需运行

ListPlot[{a, a + 1}]//InputForm

获取空图形对象

Graphics[{}, {AspectRatio -> GoldenRatio^(-1), Axes -> True, AxesOrigin -> {0, 0}, PlotRange -> {{0., 0.}, {0., 0.}}, PlotRangeClipping -> True, PlotRangePadding -> {Scaled[0.02], Scaled[0.02]}}]

由于符号值a已被抛弃,它们无法通过Manipulate进行本地化,因此不会发生其他情况。

这可以通过仍然评估第一个参数来修复,但是在ListPlot已经定位变量之后才调用Manipulate。例如,以下两项工作

Manipulate[Evaluate[listPlot[test]], {a, 0, 1}] /. listPlot -> ListPlot
Manipulate[Evaluate[Hold[ListPlot][test]], {a, 0, 1}] // ReleaseHold

ListPlot在没有任何投诉的情况下丢弃非数字值的事实可能是一个特征,但可能会导致一些烦人的难以追踪错误(就像这个问题所涉及的那个)。如果绘图值是非数字的,那么更一致(但不太有用?)的行为可能会返回未评估的ListPlot ...或者至少发出警告,表明某些非数字点已被丢弃。

你给出的倒数第二个例子是(更多?)有趣,看起来像

Manipulate[ListPlot[Evaluate[test]], {a, 0, 1}]

既然Manipulate具有属性HoldAll,那么它所做的第一件事就是将参数包装在Hold中,所以如果你看一下Trace,你就会见Hold[ListPlot[Evaluate[test]]]随身携带。未见Evaluate ,因为如Possible Issues部分所述,“评估仅适用于第一级,直接在保留的函数内”。这意味着,在变量本地化之后才会对test进行评估,因此它们将被视为全局a,而不是本地(DynamicModulea。< / p>

值得思考以下变体如何运作

ClearAll[a, test, f, g]
SetAttributes[g, HoldAll];
test = {a, a + 1};

Grid[{
  {Manipulate[test, {a, 0, 1}], Manipulate[Evaluate[test], {a, 0, 1}]},
  {Manipulate[f[test], {a, 0, 1}], 
   Manipulate[f[Evaluate[test]], {a, 0, 1}]},
  {Manipulate[g[test], {a, 0, 1}], 
   Manipulate[g[Evaluate[test]], {a, 0, 1}]}
  }]

brainpain

答案 1 :(得分:3)

这就是它不起作用的原因:

Manipulate[
 {
  Hold[a]
  },
 {a, 0, 10, .1},
 {b, 0, 10, .1},
 {c, 0, 10, .1}
 ]

enter image description here

有人可以通过各种方式解决这个问题。一种是简单地用局部变量定义test1,如下所示:

ClearAll[test1, a, b, c];
Manipulate[
 test1 = {a, b, c};
 {
  test1
  },
 {a, 0, 10, .1},
 {b, 0, 10, .1},
 {c, 0, 10, .1}
 ]

然后例如

ClearAll[test1, a, b, c];
Manipulate[
 test1 = {a, b, c};
 ListPlot@test1, 
 {a, 0, 10, .1},
 {b, 0, 10, .1},
 {c, 0, 10, .1}
 ]

作品。

如果您希望全局定义test1,则

ClearAll[test1, a, b, c];
test1 = {a, b, c};
Manipulate[
 test1,
 {a, 0, 10, .1},
 {b, 0, 10, .1},
 {c, 0, 10, .1},
 LocalizeVariables -> False,
 TrackedSymbols -> test1
 ]

作品。