■
Refresh
に関するメモ
Mathematica
内蔵関数Refresh
の引数である,UpdateInterval
は更新を制御できたりできなかったりして,いまいち仕組みが分からない.そこでいろいろと実験してみた.
Manipulate[ Refresh[Random[], UpdateInterval -> If[go, 0.105, Infinity]], {{go, False}, {True, False}}]
このようなコードなら,UpdateInterval
によって更新頻度が制御できる.一方で
x = 1; Manipulate[ Refresh[x = x + 0.01; x, UpdateInterval -> If[go, 0.02, Infinity]], {{go, False}, {True, False}}]
これはUpdateInterval
がInfinity
にもかかわらず暴走してしまう
そこでRefresh
の中にIf
を挟んで代入を制御する.
x = 1; Manipulate[ Refresh[ If[go, x = x + 0.01], UpdateInterval -> If[go, 1, Infinity]], {{go, False}, {True, False}}]
これならオンオフだけ制御できる.しかしインターバルの時間は指定通りにならない.
TrackedSymbols -> {}
で制御しようとしてもうまくいかない.
結局,即時割り当てをManipulate
の中に入れると,Dynamic
に更新されるので,その場合はUpdateInterval
で制御できる範疇を超えてしまうらしい.
オブジェクトを再帰的代入すると,refreshしてもうまくいかないらしい
次のような命令なら代入でも問題ないし,UpdateIntervalによる制御もうまくいく
Manipulate[ Refresh[ If[go, x = Random[]], UpdateInterval -> If[go, 0.8, Infinity]], {{go, False}, {True, False}}, Button["reset", go = False; x = 100] ]
しかし再帰的に代入すると,Dynamicオブジェクトが自分自身を連続的に更新するので UpdateIntervalを指定しても,機能しない (のではないかと推測する)
Manipulate[ Refresh[ If[go, x = x + Random[]], UpdateInterval -> If[go, 0.8, Infinity]], {{go, False}, {True, False}}, Button["reset", go = False; x = 100] ]
グラフィックオブジェクトの動的更新
例えばつぎのようなDynamic
オブジェクトはRefresh
によって動的に更新される
(ただし止まらない)
Dynamic[Refresh[Histogram[RandomReal[10, 100]], UpdateInterval -> 0.1]]
制御したければManipulate
内に入れて,チェックボックスでUpdateInterval
の値を指定する方法がある.
Manipulate[ Refresh[Histogram[RandomReal[10, 1000]], UpdateInterval -> If[x, 0, Infinity]], {{x, False}, {True, False}}]
今まで,ピコピコ系アウトプットはこの方法で作ってきた.
以下のようなアホなコード(めっちゃ計算しているようにみえるが,実は無意味なコード)も簡単に書ける.
Manipulate[Refresh[ Histogram[ {RandomVariate[NormalDistribution[0, 1], n], RandomVariate[NormalDistribution[a, 1/2], n], RandomVariate[NormalDistribution[10, 1], n], RandomVariate[LogNormalDistribution[1, 0.3], n], RandomVariate[NormalDistribution[8, 0.5], n]}, {.25}, PlotRange -> {{-3, 15}, {0, 100}}], UpdateInterval -> If[x, 0, Infinity]], {{x, False, "Run MCMC"}, {True, False}}, {{n, 300}, 1, 500, 1}, {{a, 3, "\[Mu]"}, 1, 10}]
いろいろ実験して分かったことは,ListPlot
みたいな即時実行命令をRefresh
するとうまくいかない,ということだ.
冗長なユーザ定義関数を割り当て(実際にはクロージャを含まないダミーでよい),遅延割り当てにすると,ちゃんとRefresh
が機能する.
だからvisualize
みたいなユーザ関数を使うとうまくいくわけだ.
以上をふまえて作ったコード
(* 関数の定義 *) initialdata[n_, m1_, m2_] := {RandomVariate[NormalDistribution[m1, 5], n], RandomVariate[NormalDistribution[m2, 5], n]}; fightonce[group_] := Module[{power1, power2}, power1 = group[[1]]; power2 = group[[2]]; If[Length[power1] > 0 && Length[power2] > 0, power1 = RandomSample[power1]; power2 = RandomSample[power2]; If[(* 戦闘力を比較して勝者を残す*) RandomChoice[ {power1[[1]]/(power1[[1]] + power2[[1]]), power2[[1]]/(power1[[1]] + power2[[1]])} -> {True, False}], (* True -> 1が勝つ*) power2 = Drop[power2, 1], power1 = Drop[power1, 1]];(* If end*) ];(* If end*) {power1, power2} ]; (* update関数のほうに停止条件を書いておく. dataがなくなったらNullを返す*) visualize[data_, hight_] := Histogram[data, {1}, PlotRange -> {{0, 100}, {0, hight}}]; (* histogram を遅延評価させるために,関数化する*) (*n=50;ylim=25;sample=initialdata[n];*) Manipulate[Refresh[ If[x, sample = fightonce[sample]]; (* If文で実行する動作:UpdateInterval\[Rule]0 のときだけ,update関数を再帰的代入する*) visualize[sample, ylim], UpdateInterval -> If[x, 0, Infinity]], {{x, False}, {True, False}}, {{n, 100}, 50, 1000, 1}, {{m1, 40}, 10, 70}, {{m2, 50}, 10, 70}, Button["reset", x = False; sample = initialdata[n, m1, m2]; ylim = n/5]]
少しだけRefresh
の理解が深まった(Dynamic
は,まだ謎が多い).