1
$\begingroup$

I have several variables in my DynamicModule and some parts of my computation depend only on subset of them. I am trying to use Refresh to "cache" values but can't make it work.

Example of the problem:

verySlowFunction[x_] := Module[{}, Print["SLOW"]; x * x];

DynamicModule[
 {a = 1, b = 1},
 Dynamic[
  Module[
   { x = Refresh[verySlowFunction[a], TrackedSymbols :> {a}] },
   Column[{
     Slider[Dynamic[a]],
     Slider[Dynamic[b]],
     {a, b , x + x + b} 
     }]]]]

I expect "SLOW" to be printed only when I drag "a" slider, but it is printed when I'm dragging "b" slider as well.

I know that Dynamic clones whole expression tree on its evaluation, that's why x is always different, but this one doesn't work as well:

Module[
 {x},
 DynamicModule[
  {a = 1, b = 1},
  Dynamic[
    x = Refresh[verySlowFunction[a], TrackedSymbols :> {a}] ;
   Column[{
     Slider[Dynamic[a]],
     Slider[Dynamic[b]],
     {a, b , x + x + b} 
     }]]]]
$\endgroup$
3
  • 1
    $\begingroup$ This is so useful: 12000.org/my_notes/event_driven_GUI_with_Manipulate/… $\endgroup$ Sep 14, 2013 at 0:10
  • $\begingroup$ Do you know if this approach is actually used by anybody? I imagine there could be a library of helper functions to make it look simpler. $\endgroup$
    – mikea
    Sep 14, 2013 at 0:39
  • $\begingroup$ Besides the author, I am using it. I don't know who else, but it works beautifully. $\endgroup$ Sep 14, 2013 at 13:58

2 Answers 2

2
$\begingroup$

Try this one

DynamicModule[{a = 1, b = 1, x = 1}, 
 Column@{Slider@Dynamic[a, (a = #; x = verySlowFunction[a]) &], 
   Slider@Dynamic[b], Dynamic@{a, b, x + x + b}}]

The second argument in Dynamic is evaluated when the corresponding variable changes.

Or this one

DynamicModule[{a = 1, b = 1}, 
 Column@{Slider@Dynamic[a], Slider@Dynamic[b], Dynamic@{a, b}, 
   Dynamic[x = verySlowFunction[a]]}]

You can manually insert Refresh with TrackedSymbols in the last Dynamic.

$\endgroup$
3
  • 1
    $\begingroup$ Thanks, this will work. However in my actual case verySlowFunction depends on more than one argument, and there are several temporary calculations to perform. This would require me to duplicate re-evaluation into lots of controls, right? $\endgroup$
    – mikea
    Sep 14, 2013 at 0:43
  • $\begingroup$ @mikea There are more elegant approach if you have several arguments. See update. $\endgroup$
    – ybeltukov
    Sep 14, 2013 at 0:53
  • $\begingroup$ The second version has some serious omission: it does not include calculations based on x. That's what causes me troubles. $\endgroup$
    – mikea
    Sep 14, 2013 at 5:50
1
$\begingroup$

That's tricky question, I have to admit I do not have general solution but I usually do what is good for particular case. Here I'd use DynamicWrapper:

verySlowFunction[x_] := Module[{}, Print["SLOW"]; x*x];

DynamicModule[{a = 1, b = 1},
              DynamicWrapper[
                     Column@{
                             Slider@Dynamic[a],
                             Slider@Dynamic[b],
                             Dynamic@{a, b, x + x + b}},
                     x = verySlowFunction[a];]]

This is not the answer to the question how to use Refresh for your purposes but I think it is not bad approach :). I'm looking forward for more answers how one can deal with this.

About link provided by @Gustavo, imo there is to much acrobatics in there which is not necessary in case of DynamicModule. DynamicModule != Manipulate because the body of DM is not automatically updated when variables are.

I appreciate any comments if I'm mistaken somewhere.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.