8
$\begingroup$

I've just started playing around with dynamic elements and I am confused over where exactly I should be placing Dynamic[] in an expression. My reading of the related help is it should be around the part which is changing. However I find inconsistent behaviour.

For example:

DynamicModule[{r = 1}, {Slider[Dynamic[r]], Graphics[Circle[{0, 0}, Dynamic[r]], Axes -> True, PlotRange -> {{-1, 1}, {-1, 1}}]}]

works while

DynamicModule[{x = 1}, {Slider[Dynamic[x]], Plot[Sin[10 y Dynamic[x]], {y, 0, 2 Pi}]}]

doesn't and dynamic must be placed further out like this

DynamicModule[{x = 1}, {Slider[Dynamic[x]], Dynamic[Plot[Sin[10 y x], {y, 0, 2 Pi}]]}]

to work properly.

So my question is how do I determine where to place the Dynamic part in my expression? My thinking was with less inside the expression then it is less computationally expensive. Or if it doesn't make any difference should I just do

DynamicModule[{initial stuff},Dynamic[{everything}]]
$\endgroup$
2
  • $\begingroup$ Try this: DynamicModule[{r = 1}, {Slider[Dynamic[r]], Dynamic@NumberForm[r, {3, 2}], Dynamic@Graphics[Circle[{0, 0}, r], Axes -> True, PlotRange -> {{-1, 1}, {-1, 1}}]}] $\endgroup$
    – Syed
    Jun 21, 2022 at 5:44
  • 1
    $\begingroup$ I think I explained it here Avoiding slow evaluations in Manipulate to some extent: $\endgroup$
    – Kuba
    Jun 21, 2022 at 7:22

1 Answer 1

9
$\begingroup$

The Q&A linked by @Kuba in the comments has some details. Here, I'll give a brief summary of how I think about Dynamic:

TL;DR

Move Dynamic inwards as much as possible: You can move it into inert wrappers, but not into anything that evaluates.

A bit more explicit

The are two distinct uses:

  • Marking something as interactively editable: This is what you are doing with Slider[Dynamic[x,…],…] and similar. Essentially, Dynamic here is just a way to prevent x from being evaluated, and to tell Slider (or whatever else) that you'd like x to be assigned the value of the slider. You can use the other arguments of Dynamic to specify how exactly you want the modification to happen.

  • Making things update dynamically: This is what you are doing with Dynamic[Plot[…]]. Here, you can in principle nest Dynamic and other expressions as you want. Whenever a variable changes, any Dynamic expression that depends on the changed variable will be updated. Stuff that is localized to a nested Dynamic localizes the dependency:

    If you have for example Dynamic[{a, Dynamic[b]}], changing b will only update the inner Dynamic, while a will update the outer one. This means that ideally the Dynamic wrappers are as localized as possible. There are of course limits to this, for example Dynamic[{a,a}] seems more reasonable than {Dynamic[a],Dynamic[a]}, since you would just create twice the updates without any real reduction in amount of stuff that is updated.

    As for where you can actually place Dynamic: As you have noticed, moving Dynamic into an expression does not always work. As a rule of thumb, there are two cases:

    • A normal function that does something to its arguments: this includes everything like Plot, Sort, Map, …. Unless specifically stated in the documentation, you cannot move Dynamic into these functions (since the result of the function depends on the actual value of the arguments, the entire thing would anyway need to be reevaluated, so moving Dynamic inside doesn't make any sense).
    • An inert wrapper that affects display: This includes Graphics, List, Grid, Style, most graphics primitives, …. Here you can move Dynamic into the expression (the structure of the expression does not depend on the contents, so updating only parts of the displayed structure makes sense). Some examples:
      • Graphics[{Dynamic[Disk[pt]]}] - individual primitives
      • Graphics[{Dynamic[{Disk[pt],Line[{pt,pt2}]}]}] - subtrees of primitives
      • Graphics[{Line[Dynamic[pts]]}] - coordinates in primitives
      • Style["a",Background->Dynamic[color]] - option values
      • Row[{Dynamic[expr1],Dynamic[expr2]}] - different parts of a row/grid

    To check whether a function is just an inert wrapper, a good first test is whether InputForm[expr] is the same thing as expr: If it is, expr is likely an inert wrapper.

$\endgroup$
1
  • $\begingroup$ Thanks for such a detailed explanation, it does such a better job of spelling it out that the documentation. Also the idea of using InputForm as a way to check for inert wrappers is very practically helpful. $\endgroup$
    – Ian Miller
    Jun 22, 2022 at 6:37

Your Answer

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

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