Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom controllers for Manipulate[] in Mathematica

I've created a function test[], which could also be a symbol test, if need be, and I'm trying to implement it in a manipulate. test[] looks like this:

test[]:=Button["Label",Functionality[]];

This will return an error if used directly in a Manipulate[], but works if it is wrapped in a Dynamic or an Evaluate.

Manipulate[content,test[]];

Manipulate::vsform: Manipulate argument test[] does not have the correct form for a variable specification.

Manipulate[content,Dynamic[test[]]]

This one works

Manipulate[content,Evaluate[test]]

Note that while this works, test is not a function

Manipulate[content,Evaluate[test[]]]

This works on my mac, but not my PC at work...

I think the issue is something to do with Manipulate being HoldAll, but don't understand why Dynamic[] should fix this. Also, Evaluate[] will only work some of the time.

So, why is the Dynamic[] or Evaluate[] necessary? Looking under the custom controllers section of the advanced manipulate tutorial, I see no references to this issue, and could not find any elsewhere.

like image 913
insect Avatar asked Jan 13 '12 05:01

insect


1 Answers

You can inline the Button instead of using a separate test[] function. Otherwise you last example, Manipulate[content,Evaluate[test[]]], does show the button on my machine in Mathematica 8. There should be no difference between platforms (Windows or Mac).

If you're doing something sufficiently different from what Manipulate provides by default, you may find it more convenient to build it from scratch using Dynamic (this is what I usually do).


Here's an example of how to include some buttons as controllers.

First, set up something to show inside the Manipulate:

rotate90[{x_, y_}] := {-y, x}

koch[p1_, p2_, n_] := {koch[p1, p1 + (p2 - p1)/3, n - 1], 
  koch[p1 + (p2 - p1)/3, (p1 + p2)/2 + Sqrt[3]/6 rotate90[p2 - p1], 
   n - 1], koch[(p1 + p2)/2 + Sqrt[3]/6 rotate90[p2 - p1], 
   p2 - (p2 - p1)/3, n - 1], koch[p2 - (p2 - p1)/3, p2, n - 1]}

koch[p1_, p2_, 0] := Line[{p1, p2}]

snowflake[n_] := 
 Graphics[{koch[{0, 0}, {1, 0}, n], 
   koch[{1, 0}, {1/2, -Sqrt[3]/2}, n], 
   koch[{1/2, -Sqrt[3]/2}, {0, 0}, n]}]

Then set up the Manipulate itself:

Manipulate[snowflake[n], {{n, 2}, ControlType -> None}, 
 Style["A Koch snowflake", Bold], Delimiter, 
 Row[{Button["+", n++], Button["-", n = Max[n - 1, 0]]}]]

Mathematica graphics


Here's an example showing that this works even if the Button is defined in a separate function:

SetAttributes[paletteButton, HoldRest]
paletteButton[name_, func_] := 
 Button[name, func, Appearance -> "Palette"]

Manipulate[snowflake[n], {{n, 2}, ControlType -> None}, 
 Style["A Koch snowflake", Bold], Delimiter, 
 Evaluate@paletteButton["+", n++]]

As you mentioned in your question, here it is necessary to wrap the function in Evaluate to obtain an inlined Button. Otherwise Manipulate will not be able to notice that what we have here is a control and not a variable.

like image 121
Szabolcs Avatar answered Sep 29 '22 13:09

Szabolcs