2010 - 09 - 13

Customizing Manipulate´s Autorun

It is in the essence of this kind of notebook that it describes undocumented, or poorly documented features of Mathematica, and such features might be changed in future versions. But if the content of this notebook already was described in the documentation, there was no reason for me to repeat it.

Sometimes we might want to control the Autorun feature of a Manipulate cell. Autorun can be started from the little "+" in a gray circle in the upper right corner of the Manipulate cell. Let us start with a simple Manipulate cell.

Manipulate[
Graphics[{color,Disk[{x,y},0.1]},PlotRange->{{-1.2,1.2},{-1.2,1.2}}],{{color,Black},{Black->"Black",Red->"Red"}},{{x,0},-1,1},{{y,0},-1,1}]

Say, that we want the dot going around a circle instead! We add another control t to fix that, and let that control take over Autorun :

Manipulate[If[t>0,x=Cos[t];y=Sin[t];color=Red,color=Black];Graphics[{color,Disk[{x,y},0.1]},PlotRange->{{-1.2,1.2},{-1.2,1.2}}],{{color,Black},{Black->"Black",Red->"Red"}},{{x,0},-1,1},{{y,0},-1,1},{t,0,4*Pi},AutorunSequencing ->{{4,10}}]

If we test the Autorun, we see a jitter in the other controls, since they are reset to their default whenever they are changed by t. The processor will be occupied by changing the controls back and forth. Moreover, the color control is locked up when Autorun is inactive. Can we fix that? Yes, we might control the other parameters without jitter if we control their default values dynamically. We might check if we are in the Autorun mode by testing the variable Typeset`bookmarkMode$$. The variable t has also been changed to run stepwise. 
One issue with defining variables in the Initialization option is the isolation problem. The Manipulate command puts all controls inside a DynamicModuleBox, isolating them from interaction with other cells. However, variables defined by the Initialization option are defined outside the DynamicModule, and they might interfere with outside code and other Manipulate cells, if the same variable names are reused. One way to avoid this is of course to use strictly different names, maybe containing some special string in such a way that it easily replaced. Another method is used here: there is an option CellContext, which might be set to Cell for the whole notebook. Then, a unique default context is used for every cells in the notebook. That can be practical for creating demonstrations, because in a notebook for the Demonstration Project several copies of the same Manipulate cell should be included as thumbnail and snapshots.
The CellContext option can be set by selecting Format -> Option Inspector -> (Selected Notebook, by Category) -> Cell Options -> Evaluation Options -> CellContext. It might alternatively be set by the command SetOptions[EvaluationNotebook[ ], CellContext->Cell]

Manipulate[If[Typeset`bookmarkMode$$==="Autorun",Which[t<told,color1=Red;told=t,t>told,color1=Black;told=t];x1=Cos[t];y1=Sin[t]];
Graphics[{color,Disk[{x,y},0.1]},PlotRange->{{-1.2,1.2},{-1.2,1.2}}],Control[{{x,Dynamic[x1],"x"},-1,1}],Control[{{y,Dynamic[y1],"y"},-1,1}],Control[{{color,Dynamic[color1],"color"},{Black->"Black",Red->"Red"}}],Control[{{t,0},0,4*Pi,Pi/12}],AutorunSequencing ->{{4,10}},Initialization:>{color1=Black;x1=0.;y1=0.;told=0.}]

Can we have the control for t invisible? I used first the uncommon programming construction "Dynamic[If[False, Control[{{t, 0}, 0, 4*Pi, Pi/12}], Pane[" ", {0, 0}]]]", but John Fultz sugggested me to use the option setting ControlType -> None instead. Not as fun, but a more proper programming solution.. The control for t will never show up, but it is anyway found by the AutorunSequencing as the fourth control.

Manipulate[If[Typeset`bookmarkMode$$==="Autorun",Which[t<told,color1=Red;told=t,t>told,color1=Black;told=t];x1=Cos[t];y1=Sin[t]];
Graphics[{color,Disk[{x,y},0.1]},PlotRange->{{-1.2,1.2},{-1.2,1.2}}],Control[{{x,Dynamic[x1],"x"},-1,1}],Control[{{y,Dynamic[y1],"y"},-1,1}],Control[{{color,Dynamic[color1],"color"},{Black->"Black",Red->"Red"}}],Control[{{t,0.},0.,4*Pi,Pi/12,ControlType->None}],AutorunSequencing ->{{4,10}},Initialization:>{color1=Black;x1=0.;y1=0.;told=0.}]

John Fultz also points out that we can remove the Control[] wrappers around the control definitions.

Manipulate[If[Typeset`bookmarkMode$$==="Autorun",Which[t<told,color1=Red;told=t,t>told,color1=Black;told=t];x1=Cos[t];y1=Sin[t]];
Graphics[{color,Disk[{x,y},0.1]},PlotRange->{{-1.2,1.2},{-1.2,1.2}}],{{x,Dynamic[x1],"x"},-1,1},{{y,Dynamic[y1],"y"},-1,1},{{color,Dynamic[color1],"color"},{Black->"Black",Red->"Red"}},{{t,0.},0.,4*Pi,Pi/12,ControlType->None},AutorunSequencing ->{{4,10}},Initialization:>{color1=Black;x1=0.;y1=0.;told=0.}]

One small detail, that might be important in more complicated cases: when the Manipulate above is initialized the first time, the button for Black is not highlighted. During the first initialization, the variable color is set to Dynamic[color1] instead of "Black", in spite of the initialization of color1. The might cause nuisance. Therefore I have added resetting of the variable color, x, and y to the first If clause, so that this is checked if Autorun is not selected.

Manipulate[If[Typeset`bookmarkMode$$==="Autorun",Which[t<told,color1=Red;told=t,t>told,color1=Black;told=t];x1=Cos[t];y1=Sin[t],If[Head[color]==Dynamic,color=First[color]];If[Head[x]==Dynamic,x=First[x]];If[Head[y]==Dynamic,y=First[y]]];
Graphics[{color,Disk[{x,y},0.1]},PlotRange->{{-1.2,1.2},{-1.2,1.2}}],{{x,Dynamic[x1],"x"},-1,1},{{y,Dynamic[y1],"y"},-1,1},{{color,Dynamic[color1],"color"},{Black->"Black",Red->"Red"}},{{t,0.},0.,4*Pi,Pi/12,ControlType->None},AutorunSequencing ->{{4,10}},Initialization:>{color1=Black;x1=0.;y1=0.;told=0.}]

We might put the Autorun definitions into the Initialization option

Manipulate[If[Typeset`bookmarkMode$$==="Autorun",autorunstep[t,told];told=t,If[Head[color]==Dynamic,color=First[color]];If[Head[x]==Dynamic,x=First[x]];If[Head[y]==Dynamic,y=First[y]]];
Graphics[{color,Disk[{x,y},0.1]},PlotRange->{{-1.2,1.2},{-1.2,1.2}}],{{x,Dynamic[x1],"x"},-1,1},{{y,Dynamic[y1],"y"},-1,1},{{color,Dynamic[color1],"color"},{Black->"Black",Red->"Red"}},{{t,0.},0.,4*Pi,Pi/12,ControlType->None},AutorunSequencing ->{{4,10}},Initialization:>{color1=Black;x1=0.;y1=0.;told=0.;autorunstep[t_,told_]:=(Which[t<told,color1=Red,t>told,color1=Black];x1=Cos[t];y1=Sin[t])}]

Here I have added annotation to the Autorun mode. The annotation is only visible when Autorun is activated.
So here comes the final version along this path.

Manipulate[If[Typeset`bookmarkMode$$==="Autorun",autorunstep[t,told];told=t,If[Head[color]==Dynamic,color=First[color]];If[Head[x]==Dynamic,x=First[x]];If[Head[y]==Dynamic,y=First[y]];ti=0];
Graphics[{color,Disk[{x,y},0.1]},PlotRange->{{-1.2,1.2},{-1.2,1.2}}],Dynamic[If[ti==0,Pane[0,0],annotation[ti]]],{{x,Dynamic[x1],"x"},-1,1},{{y,Dynamic[y1],"y"},-1,1},{{color,Dynamic[color1],"color"},{Black->"Black",Red->"Red"}},{{t,0.},0.,4*Pi,Pi/12,ControlType->None},AutorunSequencing ->{{4,10}},Initialization:>{color1=Black;x1=0.;y1=0.;told=0.;ti=0;
annotation[ti_]:=Switch[ti,0,"",1,"Red clockwise",2,"Black anticlockwise",_,""];
autorunstep[t_,told_]:=(Which[t<told,color1=Red;ti=1,t>told,color1=Black;ti=2];x1=Cos[t];y1=Sin[t])}]

Here is a variant with manipulators instead of controls for x and y and SetterBar for color. It is possible to control them from t directly. By the If construction, x and y are only recalculated when it is needed.

Manipulate[If[Typeset`bookmarkMode$$==="Autorun",Which[t<told,color=Red,t>told,color=Black];If[t≠told,x=Cos[t];y=Sin[t];told=t]];
Graphics[{color,Disk[{x,y},0.1]},PlotRange->{{-1.2,1.2},{-1.2,1.2}}],Row[{"     x   ",Manipulator[Dynamic[x],{-1,1}]}],Row[{"     y   ",Manipulator[Dynamic[y],{-1,1}]}],Row[{"  color  ",SetterBar[Dynamic[color],{Black->"Black",Red->"Red"}]}],Control[{{t,0.},0.,4*Pi,Pi/12,ControlType->None}],AutorunSequencing ->{{2,10}},Initialization:>{color=Black;told=0.;x=0.;y=0.}]

John Fultz at Wolfram recommends storing bookmarks and animate them using the "Animate bookmarks" feature, and suggested this example:

Manipulate[Graphics[{color,Disk[{x,y},0.1]},PlotRange->{{-1.2,1.2},{-1.2,1.2}}],{{color,Black},{Black->"Black",Red->"Red"}},{{x,0},-1,1},{{y,0},-1,1},Bookmarks->{"frame1":>(x=1;y=0;color=Black),"frame2":>(x=0;y=-1;color=Red),"frame3":>(x=-1;y=0;color=Red),"frame4":>(x=0;y=1;color=Black),"frame5":>(x=1;y=0;color=Black)}]

My comment to this example is that the dot does not move in a circle. If we want to achieve that, we could of course add more bookmarks. As I see it, this bookmark animation is like ready-made clothing: when it fits it fits, and when it works, it works, but sometimes a real tailor is needed.  It is also my opinion that bookmark animation is buggy sometimes, and demands strict adherence to certain conventions how to code Manipulate. For instance, Manipulator or LocatorPane inside Manipulate might cause problems, while Control and the control Locator might work better.
See http://www.familydahl.se/mathematica/CustomizingManipulatesAnimateBookmarks.nb for a notebook about how to customize “Animate Bookmarks”.

Please send comments to ingolf.dahl@telia.com.
This notebook might be available at http://www.familydahl.se/mathematica/CustomizingManipulatesAutorun.nb