5

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.

Kuba
  • 136,707
  • 13
  • 279
  • 740
nibudd
  • 53
  • 4

1 Answers1

10

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 on Dynamic parts of GUI that you want to be affected by this behaviour.

  • ifAuto's Dynamic output is triggered only when variable auto changes

  • If auto === True then it acts as it wasn't there. E.g Dynamic[Plot[...]...] is shown and the FrontEnd will take care about its updates according to what was set there.

    If[ from ifauto is only run when auto changes so it does not affect the performance, neat. Read more in tutorial/AdvancedDynamicFunctionality/Nesting Dynamic

  • If auto === False then Setting @ Dynamic @ Plot[... is shown, effectively stripping Dynamics and leaving Plot[... which won't be updated by a's changes (because of the very outer TrackedSymbols:>{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]
   }
  ]
 ]

enter image description here

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.

Kuba
  • 136,707
  • 13
  • 279
  • 740
  • This is exactly the kind of thing I was trying to achieve. Now to understand what you've done here - thank you! – nibudd Jul 20 '16 at 21:52
  • 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 of Checkbox?

    2. What is the meaning of auto = # in the first argument of If? Is # being evaluated to determine which expression to execute (a = tempA or tempA = a) and then assigning that value to auto?

    2b. If so, why is that necessary? Isn't auto already tied to the Checkbox?

    1. What is the meaning of @ here? I can't find any documentation on this kind of usage (Dynamic @ Plot[..., Dynamic @ auto, or Dynamic @ Not @ auto)
    – nibudd Jul 21 '16 at 15:45
  • 1
    @nibudd 1. take a look at docs for Dynamic, the second argument of Dynamic 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, assigns Checkbox state to auto and returns this value so we can synchronize a with tempA (when a or tempA 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 @#%^&*?! – Kuba Jul 21 '16 at 16:22
  • 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 like TrackedSymbols :> Dynamic[list, If[manualUpdate = #, list = {update}, list = {a, b}] &]' whereupdateis 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. – nibudd Jul 21 '16 at 16:52
  • 1
    @nibudd I see, take a look at the edit, that should be it. – Kuba Jul 21 '16 at 17:47
  • So Setting causes TrackedSymbolx:>{auto} to be applied to Dynamic@Plot[... but Identity does not? Why is that? – nibudd Jul 22 '16 at 18:23
  • @nibudd I don't understand, I said what Setting does and documentation also says so, it strips Dynamic inner to Setting. That is all. – Kuba Jul 25 '16 at 13:52