4
$\begingroup$

I have cut down a DynamicModule that was updating unexpectedly and found the following behaviour I don' t understand.

If I do this I get one random value as expected

Dynamic[
 th = RandomReal[{-1, 1}];
 th
]

In this case I also get one value as expected

DynamicModule[{th},
 Dynamic[ RandomReal[{-1, 1}]]
]

However, in this case the value is updating continuously. I did not expect this.

DynamicModule[{th},
 Dynamic[
  th = RandomReal[{-1, 1}];
  th
 ]
]

Why does it do this and how do I make it give me just one value?

Edit

Here is a fuller example to show what I am aiming for. The DynamicModule has two parts that are wrapped in Dynamic and information from the first (set up and calculation) must be shared with the second (graphics).

DynamicModule[{th, ft, rr = 1, f = 0.2345, m, c, x, res},
 Column[{
   Row[{Slider[Dynamic[rr], {0, 10}], " ran amp = ", Dynamic[rr]}],
   Dynamic[
    th = Table[ 
      Cos[2 \[Pi] f (n - 1)] + RandomReal[{-rr, rr}], {n, 400}];
    ft = Fourier[th, FourierParameters -> {-1, -1}];
    res = FindFit[Abs[ft[[1 ;; 200]]], m x + c, {c, m}, x];
    {m, c} /. res
    ],
   Dynamic[
    ListPlot[Abs[ft[[1 ;; 200]]], PlotRange -> All,
     ImageSize -> 5 72, 
     Epilog -> {Line[{{1, c}, {200, m 200 + c}} /. res]}]
    ]
   }]
 ]
$\endgroup$
2
  • 1
    $\begingroup$ Try DynamicModule[{th}, Dynamic[th = RandomReal[{-1, 1}]; th, TrackedSymbols -> {}]] $\endgroup$
    – qwerty
    Mar 14, 2014 at 23:59
  • $\begingroup$ @esprit Thank you for your comment. This works but my problem is more complicated. I have added an example to show what I am trying to do. $\endgroup$
    – Hugh
    Mar 15, 2014 at 10:56

2 Answers 2

5
$\begingroup$

Explanation of the behavior

First, let me dispense with the OP's second example. I assume RandomReal[{-1, 1}] is treated as not depending on any symbol (except possibly RandomReal, although I would not be surprised if Protected symbols were excluded from dynamic tracking). So unlike Clock, RandomReal will not cause an update merely because it will probably return a different answer each time. For this reason, the OP's second example is unproblematic.

This baffled me because at first I expected the first of the OP's examples to update continually. For instance, this seemingly unimportant modification does update continually:

Dynamic[
 th;                       (* a1 *)
 th = RandomReal[{-1, 1}]; (* a2 *)
 th                        (* a3 *)
 ]

The way I explain it to myself is this. I will compare it with the OP's first example, with the lines of code identified for convenient reference.

Dynamic[
 th = RandomReal[{-1, 1}]; (* b1 *)
 th                        (* b2 *)
 ]

Determining when an update is triggered comes down (it seems) to whether an assignment would alter the result of executing the code again. (Keep in mind that I'm assuming RandomReal is treated as if it gave the same value for the same input.) In my example, line a2 changes th, which means the previous line a1 would have a different result. This triggers an update. In the OP's example, the assignment in line b1 has no such effect. The symbol th appears only after the assignment, so no update is necessary.

In the interest of efficiency, there may be a limit to how precisely Mathematica can determine the dependency of a code segment on a symbol. In such cases, I would expect Mathematica to be conservative and assume that a update should be done.

This analyis has a bearing on the main question, which for me is, Why does wrapping the first of the OP's examples inside a DynamicModule makes a difference?

Strictly speaking it is not merely DynamicModule. The following does not update continually:

DynamicModule[{},
 Dynamic[
  th = RandomReal[{-1, 1}];
  th
 ]]

It has to do with th being a DynamicModule variable. As such, it is owned by the Front End. If we look at the cell expressions of the two examples, we will see something important:

(* No DynamicModule example (OP's 1st) *)

Cell[BoxData[
 DynamicBox[ToBoxes[$CellContext`th = RandomReal[{-1, 1}]; $CellContext`th, StandardForm],
  ImageSizeCache->{95., {1., 13.}}]], "Output",
 CellChangeTimes->{3.603873092328042*^9}]

(* DynamicModule example (OP's 3rd) *)

Cell[BoxData[
 DynamicModuleBox[{$CellContext`th$$ = -0.014046062447770069`}, 
  DynamicBox[
   ToBoxes[$CellContext`th$$ = RandomReal[{-1, 1}]; $CellContext`th$$, 
    StandardForm],
   ImageSizeCache->{118., {1., 13.}}],
  DynamicModuleValues:>{}]], "Output",
 CellChangeTimes->{3.6038735203232813`*^9}]

Note that the current value of th is stored in the DynamicModule expression maintained by the Front End. The initialization (in the second line) is like line a1 above; it is evaluated first. At first, the line is simply

 DynamicModuleBox[{$CellContext`th$$}, 

in which case it is just like the line a1. The value of th will be changed when the Front End sends the body of the DynamicModule to Kernel for evaluation. This change will trigger another update, just as in my first "a" example above. That's why, I think, that the OP's third example updates continually.

Fix of the OP's last example

Personally, I would probably use esprit's TrackedSymbols solution, perhaps with Refresh. For the sake of offering a complete answer, here's another way:

DynamicModule[{th, ft, rr, f, m, c, x, res, updateRR},
 Column[{
   Row[{Slider[Dynamic[rr, updateRR], {0, 10}], " ran amp = ", Dynamic[rr]}],
   Dynamic[{m, c} /. res],
   Dynamic[
    ListPlot[Abs[ft[[1 ;; 200]]], PlotRange -> All, ImageSize -> 5 * 72,
      Epilog -> {Line[{{1, c}, {200, m 200 + c}} /. res]}]
    ]
   }],
 Initialization :> (
   rr = 1;
   f = 0.2345;
   updateRR = (rr = #;
      th = Table[Cos[2 π f (n - 1)] + RandomReal[{-rr, rr}], {n, 400}];
      ft = Fourier[th, FourierParameters -> {-1, -1}];
      res = FindFit[Abs[ft[[1 ;; 200]]], m x + c, {c, m}, x]) &;
   updateRR[rr])
 ]

The trick is to update the symbols that depend only on rr at the time rr is updated, using the second argument of Dynamic.

$\endgroup$
2
  • $\begingroup$ Many thanks for this I understand much more now. The key statement for me was "...whether an assignment would alter the result of executing the code again." This is an important rule that I had not spotted elsewhere. Your alternative solution using Initialization is also a construct I have not used before. Thanks $\endgroup$
    – Hugh
    Mar 16, 2014 at 8:50
  • $\begingroup$ You're welcome and thanks for a great question. Dynamic is complicated and subtle, but it's not often these days that such a clear and straightforward question about Dynamic makes me have to think, explore, and figure it out. $\endgroup$
    – Michael E2
    Mar 16, 2014 at 12:21
2
$\begingroup$

Ok, is this what you need ?

DynamicModule[{th, ft, rr = 1, f = 0.2345, m, c, x, res}, 
  Column[{Row[{Slider[Dynamic[rr], {0, 10}], " ran amp = ", Dynamic[rr]}], 
    Dynamic[th = Table[Cos[2 \[Pi] f (n - 1)] + RandomReal[{-rr, rr}], {n, 400}];
     ft = Fourier[th, FourierParameters -> {-1, -1}];
      res = FindFit[Abs[ft[[1 ;; 200]]], m x + c, {c, m}, x];
        {m, c} /. res, 

    TrackedSymbols :> {rr}

    ], 
    Dynamic[ListPlot[Abs[ft[[1 ;; 200]]], PlotRange -> All, ImageSize -> 5 72, 
      Epilog -> {Line[{{1, c}, {200, m 200 + c}} /. res]}]]}]]
$\endgroup$
1
  • $\begingroup$ Many thanks. Your solution works well. I have a new understanding. $\endgroup$
    – Hugh
    Mar 16, 2014 at 8:52

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.