I have a plot with interactive controls. I'd like to give the user the option between having the plot automatically update (when the plot's parameters are changed with the slider) and having the update happen only when an 'update' button is pushed. I've been spinning my wheels on this for a long time. Any and all help is appreciated.
1 Answer
Edit
Can you think of another way to accomplish the same thing [...]? It would be nice to have a solution that didn't involve duplicating each slider.
-nibudd
DynamicModule[{a = 1, tempA = 1, auto = True}
,
ifAuto = Dynamic[
If[auto, Identity, Setting]@#,
TrackedSymbols :> {auto}
] &;
Column[{
ifAuto @ Dynamic @ Plot[Sin[a x], {x, 0, 1}],
Slider[Dynamic[a], {1, 10}],
Checkbox[Dynamic[auto]],
Button["Update", auto = True; FinishDynamic[]; auto = False;,
Method -> "Queued", Enabled -> Dynamic@Not@auto]
}]
]
ifAuto
function is meant to be used onDynamic
parts of GUI that you want to be affected by this behaviour.ifAuto's
Dynamic
output is triggered only when variableauto
changesIf
auto === True
then it acts as it wasn't there. E.gDynamic[Plot[...]...]
is shown and the FrontEnd will take care about its updates according to what was set there.If[
fromifauto
is only run whenauto
changes so it does not affect the performance, neat. Read more in tutorial/AdvancedDynamicFunctionality/Nesting DynamicIf
auto === False
thenSetting @ Dynamic @ Plot[...
is shown, effectively strippingDynamics
and leavingPlot[...
which won't be updated bya's
changes (because of the very outerTrackedSymbols:>{auto}
.
Initial approach
The idea is to switch controllers between main a
variable and a temporary one tempA's
.
The Checkbox
toggles that. It also makes both variables synchronized so that the transistion is "smooth".
DynamicModule[{a = 1, tempA = 1, auto = True},
Column[{
Dynamic @ Plot[Sin[a x], {x, 0, 1}],
PaneSelector[
{
True -> Slider[Dynamic[a], {1, 10}],
False -> Slider[Dynamic[tempA], {1, 10}]
},
Dynamic@auto
],
Checkbox[Dynamic[auto, If[auto = #, a = tempA, tempA = a] &]],
Button["Update", a = tempA, Enabled -> Dynamic@Not@auto]
}
]
]
Instead of PaneSelector
you can use
`Slider[Dynamic[tempA, (tempA = #; If[auto, a = tempA]) &], {1, 10}]`
but spamming If
whenever you move a Slider
is not neat.
-
$\begingroup$ This is exactly the kind of thing I was trying to achieve. Now to understand what you've done here - thank you! $\endgroup$– nibuddCommented Jul 20, 2016 at 21:52
-
$\begingroup$ If you'll indulge me, I have some questions about how this works: 1. What is the
If
pure function taking as its argument, the value ofCheckbox
? 2. What is the meaning ofauto = #
in the first argument ofIf
? Is#
being evaluated to determine which expression to execute (a = tempA
ortempA = a
) and then assigning that value toauto
? 2b. If so, why is that necessary? Isn't auto already tied to the Checkbox? 3. What is the meaning of@
here? I can't find any documentation on this kind of usage (Dynamic @ Plot[...
,Dynamic @ auto
, orDynamic @ Not @ auto
) $\endgroup$– nibuddCommented Jul 21, 2016 at 15:45 -
1$\begingroup$ @nibudd 1. take a look at docs for
Dynamic
, the second argument ofDynamic
can be a function which does whatever you want with the state of the controller.#
is a slot which will be filled with that state, so True or False. 2.auto = #
has 2 roles, assignsCheckbox
state toauto
and returns this value so we can synchronizea
withtempA
(whena
ortempA
is active the other isn't though we don't want it's old value to pop up after switching). Hope that was clear. About@
, take a look at What the @#%^&*?! $\endgroup$– KubaCommented Jul 21, 2016 at 16:22 -
$\begingroup$ I did read the documentation on
Dynamic
, but since I'm relatively new to Mathematica, I did not find it terribly helpful. I appreciate you clearing up my confusion. Can you think of another way to accomplish the same thing by using the TrackedSymbols attribute of Plot? I've been trying to do this with something likeTrackedSymbols :> Dynamic[list, If[manualUpdate = #, list = {update}, list = {a, b}] &]' where
update` is tied to my update button, anda, b
are tied to two different sliders. It would be nice to have a solution that didn't involve duplicating each slider. $\endgroup$– nibuddCommented Jul 21, 2016 at 16:52 -
1$\begingroup$ @nibudd I see, take a look at the edit, that should be it. $\endgroup$– KubaCommented Jul 21, 2016 at 17:47
ContinuousAction
if you have not done so already. It is not an answer to your question but it can provide a reasonable in-between in some cases. $\endgroup$ControlActive
is good to know. $\endgroup$