Reputation: 13141
I have a really big problem on my hands.
I spend a week rewriting a Manipulate demo to use indexed objects (to use them as emulation of a struct)
However, when I started I did not know how to define them as None control
type (so that the state is saved between each Manipulate update), so, I moved them to the Initialization section for now, so that I can test the idea.
Everything works well except for one problem:
In the Initialization section, they become GLOBAL. Which means, when making a demo, and making a snap-shot of the Manipulate, which one must do, then the 2 Manipulates now will interact with each others in an undesired way. They share these global variables (the indexed objects). Which means if I change something in one Manipulate, the other Manipulate is affected.
The WRI demonstration editor do not recommend using global variables inside the Manipulate section either.
I'll explain the problem with simple examples, and hope an expert here might know a work around. Currently I have something like this, which works:
Manipulate[
p@x = 0; (*I'd like to use here *)
p@y = 99; (*etc...*)
foo,
{{foo, 0, "foo"}, 0, 10, 1},
Initialization :>
{
p[x] = 99; (*my data live here *)
p[y] = 0; (*my data live here *)
}
]
But in the above p[x] and p[y] are global. I tried the control None trick, but this does not work:
Manipulate[
p[x] = 0;
foo,
{{foo, 0, "foo"}, 0, 10, 1},
{{p[x], 99}, None} (* syntax error, what is the correct syntax? *)
]
I can't put a Module around Manipulate in order to use it to save state. Not allowed.
So, I need a way to have these indexed object preserve the state between each Manipulate update, just like a control variable, but not be global.
But the problem I do not know how to do this. The only way I knew to do this, was using the Control None trick.
I know that Manipulate is basically a DynamicModule[]
itself. That is why its own variables (control variables) keep state. I need these indexed object to be like them as well. Can I use a DynamicModule[] inside Manipulate somehow to do this or is there a simple solution to this?
Btw, I found I can do the following
Manipulate[
z,
{{foo, 0, "foo"}, 0, 10, 1},
{{z, p[x]}, None}
]
But I am not sure what to make of the above. I need to use p@x and not z.
The strange thing, one can define an array of indexed objects, but not a single one?
Manipulate[
z,
{{foo, 0, "foo"}, 0, 10, 1},
{{z, Table[p[i], {i, 5}]}, None}
]
Thanks for any hints.
Update:
I am not able to get Mike answer below to work as I needed it to. For example, suppose I want to have p[x] initialized to 0, and then in each Manipulate update, I want to add one to it. How to do that? This is what I tried:
Manipulate[
DynamicModule[{p, x}, (*not working *)
p@x = p@x + 1;
p@x,
Initialization :>
{
p@x = 0;
}
],
{{n, 0, "n"}, 0, 10, 1},
TrackedSymbols :> n
]
Will keep trying things...
Update 2:30 AM
This below is more clear example of the problem in case the above is not clear
Manipulate[
p@x = p@x + 1;(*I'd like to use here*)
n;
Row[{"p@x=", p@x}],
Button["click to update p@x", n++],
{{n, 0}, None},
TrackedSymbols :> {n},
Initialization :> {
p@x = 0;
}
]
In this example, an indexed object, p[x] is global variable, hence its state is preserved. I need to do the same, but without having p[x] defined as global, but move it to be part of the Manipulate so that it becomes localized, but also have its state saved.
The problem again, is that the control None
syntax does not allow me to type
{{p@x,0},None}
Hope this example makes things more clear.
Upvotes: 4
Views: 340
Reputation: 1683
With the caveat that I mostly only use DynamicModule, rarely Manipulate, so I'm not familiar with how you torture it into submission, I'm thinking this may work:
Manipulate[
DynamicModule[{p, x, y},
p@x = 0;
p@y = 99;
p[y]*foo (* or Dynamic[p[x]*foo] *)],
{{foo, 0, "foo"}, 0, 10, 1}]
If it doesn't work the way you require you may need to provide more information or wait for a Manipulate guy to respond.
Edit
Just added an alternative with a Dynamic. So in your real code if e.g. p or x or y are to be updated then you need to use Dynamic. (The example above assume x is dynamic)
FURTHER EDIT
Your most recent edit implies that you want p@x to change when the value of n changes, e.g. when the slider moves.
Manipulate[
DynamicModule[{p, x, tmp},
p@x = 0;
{Dynamic[p@x += 1; n, TrackedSymbols :> {n}], Dynamic[p@x]}],
{{n, 0, "n"}, 0, 10, 1}]
That is it for me tonight. Maybe someone else can offer some suggestions.
Upvotes: 2