This is a little related to this question
Define control as variable in Mathematica
But the above question did not answer my problem, as it talks about the full control definition. (I also tried some of the tricks shown there, but they do not work for my problem).
I am now asking about definition for only part of the control. (It is also very hard to follow up on an old question using this forum format. Because using the tiny comment area, it hard to ask and show more like when asking a new question where the space is larger, and one can paste code and images).
All the tries I have made do not work. I'll start by simple example to explain the problem.
Assume one want to write
Clear["Global`*"];
Manipulate[Plot[f*g, {x, -1, 1}],
Grid[{
{Style["f(x)="],
PopupMenu[Dynamic[f], {x, x^2, x^3}, ImageSize -> Tiny]},{Style["g(x)="],
PopupMenu[Dynamic[g], {x, x^2, x^3}, ImageSize -> Tiny]}
}]
]
you can see there is allot of code duplication in each control definition. (things like ImageSize, Spacings-> and many other decoration settings, are repeated over and over for each control.
What will be great, if I can write something like
Manipulate[Plot[f*g, {x, -1, 1}],
Grid[{
{Style["f(x)="], PopupMenu[Dynamic[f], Evaluate@Sequence@v]},
{Style["g(x)="], PopupMenu[Dynamic[g], Evaluate@Sequence@v]}
}],
Initialization :>
(
v = {{x, x^2, x^3}, ImageSize -> Tiny}
)
]
But this does not work. I tries many other things along the above line, and nothing works. Like
{Style["f(x)="], PopupMenu[Dynamic[f], v]},
and
{Style["f(x)="], PopupMenu[Dynamic[f], Evaluate@v]}
and
Manipulate[Plot[f*g, {x, -1, 1}],
{{v, {{x, x^2, x^3}, ImageSize -> Tiny}}, None},
Grid[{
{Style["f(x)="], PopupMenu[Dynamic[f], Evaluate@v]},
{Style["g(x)="], PopupMenu[Dynamic[g], v]}
}]
]
can't get it to work.
But here are the rules of the game: This will be for a demo, hence, code must start with Manipulate. Can't have Module outside Manipulate. Also, can not use Hold and its friends. But can use Unevaluated.
I was hoping the experts here might have a trick to do this. The will reduce the code size if it is possible to do, as many of the control I have, contain many 'options' like the above that are the same, and being able to do the above will make the code easier to read and manage.
thanks,
ps. What I am asking for, is sort of similar to what one does for say Plot options, where one can use SetOptions to set some common default options so they do not have to duplicate them for each Plot command each time. But there is no such thing in this case.
update
Using the method shown by Leonid below, (the Macro trick), I wanted to use it to help me define number of controls, all using one common setting. This is what I tried:
Manipulate[{x, y},
Evaluate@With[
{
control1 = Function[{var, initialValue, str, from, to, incr},
{
{{var, initialValue, str}, from, to, incr, ImageSize -> Tiny}
}
,
HoldAll
]
},
{
First@control1[x, 0, "x=", 0, 1, .1],
First@control1[y, 0, "y=", 0, 2, .1],
First@control1[z, 0, "z=", 0, 10, .1]
},
]
]
The problem is just an extra {} around the whole thing, else it will work. Will keep trying to solve this. But getting close. Tried Sequence[], and Flatten[..,1] and such, but can not do it yet. Making more coffee, should help.
Update 2
This is below an example using Simon method to use to help define common definition across more than one control. This way, one can use it to reduce code duplication for common options on set of separate controls
Notice, had to use Control[]
to get it to control.
Manipulate[{x, y, z},
Dynamic[Grid[{
{control1[x, 0, "x=", 0, 1, .1]},
{control1[y, 0, "y=", 0, 2, .1]},
{control1[z, 0, "z=", 0, 10, .1]}
}]],
{{control1,
Function[{var, initialValue, str, from, to, incr},
Control[{{var, initialValue, str}, from, to, incr,
ImageSize -> Tiny}], HoldFirst]}, None}
]
Update 3
And got Leonid method to work also on more than one control. The trick is to use Control[]
. Can't use plain old {{x,0,"x"},...}
[EDIT, yes, you can, just need the Sequence@@ method as shown below by Leonid update.].
Here it is:
Manipulate[{x, y, z},
Evaluate@With[
{
control1 = Function[{var, initialValue, str, from, to, incr},
Control[{{var, initialValue, str}, from, to, incr,
ImageSize -> Tiny}]
, HoldAll
]
},
Grid[{
{control1[x, 0, "x=", 0, 1, .1]},
{control1[y, 0, "y=", 0, 2, .1]},
{control1[z, 0, "z=", 0, 10, .1]}
}]
]
]
I'll try to integrate one of these methods into my main demo (has over 600 lines of code just for the control layout so far and growing by the minute, hopefully these methods will shrink this by quite a bit)
Update 9/26/11. 7 pm
I thought I post a 'birds eye' view of the code saving by using 'macros' to define controls which contains many common boiler-plate code. Here is a screen shot of before and after.
Thanks again for all the answer and help.
What about this
Manipulate[Plot[f*g, {x, -1, 1}],
Evaluate@
With[{styleAndpopup =
Function[{st, fun},
{
Style[st],
PopupMenu[Dynamic[fun], {x, x^2, x^3}, ImageSize -> Tiny]
},
HoldAll]},
Grid[{styleAndpopup["f(x)=", f], styleAndpopup["g(x)=", g]}]]]
This is actually a tiny example of the code-generation at work, since if you look at the FullForm
of the resulting Manipulate
, you will see the same expression you originally started with. The styleAndpopup
is actually not a function here, but a macro, locally defined using With
.
EDIT
Per request of the OP - generalizing to many controls. The easiest fix is to insert Sequence@@...
as Sequence @@ {First@control1[...
. However, there is some extraneous stuff that can be removed as well:
Manipulate[{x, y},
Evaluate@With[{control1 =
Function[{var, initialValue, str, from, to, incr},
Unevaluated@{{var, initialValue, str}, from, to, incr, ImageSize -> Tiny},
HoldAll]},
Sequence @@ {
control1[x, 0, "x=", 0, 1, .1],
control1[y, 0, "y=", 0, 2, .1],
control1[z, 0, "z=", 0, 10, .1]}]]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With