2011-08-31 42 views
3

我有問題,需要使用代碼分配給在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',但我確信它不能解決我的問題。

+1

非常類似的問題:更新操縱圖參數變化時(http://stackoverflow.com/q/7126532/211232 ) – WReach

回答

8

所以問題是,test1在全局變量Global`a, 來定義,但在由DynamicModule創建,因此當地的操縱a定義。這就是acl以他的Hold[a]爲例。

也許解決這個問題的最簡單的方法是使用With插入test1到操作:

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}它然後繼續正確本地化。雖然如果在運行Manipulate之前a,b,c已被賦予一個值,那麼這會遇到問題 - 因此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),所以我不會有一個完美的數學在我的大腦運行(nonstandard評價序列,但我會試着解釋這是怎麼回事。

好吧,所以不像Plot,ListPlot不需要本地化任何變量,所以它沒有AttributeHoldAll

讓我們定義類似的例子東西:

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

這是值得我們思考的以下變化是如何工作的

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

+0

+1與'With'解決方案類似,人們可以使用'Manipulate [Evaluate @ test1,...]'。但是,我同意最好的做法是使用局部變量。 – WReach

+0

@WReach:是的,但是'Evaluate'在問題的'ListPlot'版本中不起作用...(btw +1 to [your answer](http://stackoverflow.com/questions/7126532/update-操縱 - 繪圖 - 當參數改變/ 7126947#7126947)到幾乎相同的問題) – Simon

+0

我想強調,我已經發布了一個最小的例子來解釋問題。實際上,我正在處理更多且變化的參數,所以我不想明確寫下它們。 With解決方案+1(這對清除變量不是問題)。但是,我真的很想理解爲什麼Evaluate不適用於有些嵌套的ListPlot? – phantomas1234

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}; 
[email protected], 
{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 
] 

作品。

+0

+1,但是您的第一個解決方案必須在每次更改時都設置''test1''。在這種情況下,這不算什麼開銷,但最好避免。您的第二個解決方案存在{a,b,c}成爲全局變量的「問題」,這可能會產生不必要的後果。 – Simon

+1

@Simon我同意你的觀點(並且你的回答背後的想法是,「正確的方式」是不使用全局變量,而是用'With'字面注入定義)。這裏的想法是最小化地改變問題中給出的方法,以便它可以工作。 – acl