1
$\begingroup$

I am trying to understand Dynamic a bit better for some classroom presentations, so I tried to make a dynamic list plot. As far as I can tell, this still requires repeatedly replotting the entire plot, but I think superceded plots can immediately be garbage collected. (Right?)

Anyway, consider the following simple example, which I believe captures my core considerations. (The Pause just allows enough time to watch the animation.)

traj = Sin@Subdivide[0, 2 Pi, 50]  (* the trajectory to plot *)
Dynamic@tmax
Dynamic[ListPlot[traj[[;; tmax]],
  DataRange -> {0, 2 Pi*tmax/50}, 
  PlotRange -> {{0, 2 Pi}, {-1, 1}}], None]
Do[FinishDynamic[]; Pause[0.01]; tmax = n, {n, 1, 51}]
  1. Is this basically correct as an approach to my problem of dynamic plotting?
  2. Does ListAnimate have advantages over this approach, aside from this approach a. introducing an otherwise unneeded global variable and b. not being able (afaict) to save the animation?
  3. How can I do this inside a DynamicModule, to avoid introducing dynamic global variables?

Edit:

A stated in the question, a key goal here is to better understand Dynamic and relations. For the simple example above, Animate works just fine.

$\endgroup$
7
  • 1
    $\begingroup$ why not just use Manipulate? It makes everything much simpler. $\endgroup$
    – Nasser
    Jul 16, 2021 at 21:37
  • 2
    $\begingroup$ Or Animate[]. $\endgroup$
    – Michael E2
    Jul 16, 2021 at 21:39
  • $\begingroup$ @Nasser A stated in the question, a key goal here is to better understand Dynamic and relations. For the example, Animate works just fine. $\endgroup$
    – Alan
    Jul 16, 2021 at 21:48
  • $\begingroup$ @MichaelE2 Just to elaborate a little bit, the above approach is easily adapted to update a plot after each point-producing iteration. $\endgroup$
    – Alan
    Jul 16, 2021 at 21:55
  • 1
    $\begingroup$ Animate and Animator have the option DisplayAllSteps, which forces an update after each iteration. -- Generally, though, your approach is "correct." You've noted a desire to avoid the use of global variables already, and I would add that driving the animation with a Do[] loop instead of a traditional control (as found in Manipulate[] and Animate[]) is likely to prove inconvenient. $\endgroup$
    – Michael E2
    Jul 16, 2021 at 23:38

1 Answer 1

3
$\begingroup$
  1. Using the OP's Do[] loop inside a button:
    DynamicModule[{tmax = 0, traj, done},
     traj = Sin@Subdivide[0, 2 Pi, 50] ; (*the trajectory to plot*)
     Column[{
       Row[{
         "tmax = ", Dynamic@tmax,
         Button["Start",
          Do[
           tmax = n;
           FinishDynamic[];
           Pause[0.01],
           {n, 1, 51}],
          Method -> "Queued"]}],
       Dynamic[
        ListPlot[traj[[;; tmax]], DataRange -> {0, 2 Pi*tmax/50}, 
         PlotRange -> {{0, 2 Pi}, {-1, 1}}, 
         PlotRangePadding -> Scaled[.05], ImageSize -> 350],
        None,
        TrackedSymbols :> {tmax}]
       }]
     ]
  1. Using the implicit update caused by changing a variable instead of the Do[] loop:
    DynamicModule[{tmax = 0, traj},
     traj = Sin@Subdivide[0, 2 Pi, 50] ; (*the trajectory to plot*)
     Dynamic[
      If[tmax < 51, tmax++];
      ListPlot[traj[[;; tmax]], DataRange -> {0, 2 Pi*tmax/50}, 
       PlotRange -> {{0, 2 Pi}, {-1, 1}}, PlotRangePadding -> Scaled[.05],
        PlotLabel -> Row[{"tmax = ", tmax, Button["Restart", tmax = 0]}]],
       None]
     ]
  1. Using an Animator instead of a Do[] loop:
    DynamicModule[{tmax = 0, traj},
     traj = Sin@Subdivide[0, 2 Pi, 50] ; (*the trajectory to plot*)
     Column[{
       Row[{
         Animator[Dynamic@tmax, {1, 51, 1}, DisplayAllSteps -> True, 
          AnimationRepetitions -> 1, 
          AppearanceElements -> {"ProgressSlider", "PlayPauseButton", 
            "ResetButton", "FasterSlowerButtons"}],
         " tmax = ", Dynamic@tmax}],
       Dynamic[
        ListPlot[traj[[;; tmax]], DataRange -> {0, 2 Pi*tmax/50}, 
         PlotRange -> {{0, 2 Pi}, {-1, 1}}, 
         PlotRangePadding -> Scaled[.05], ImageSize -> 400], None]
       }]
     ]
  1. Using Animate, localizing traj in a DynamicModule:
    DynamicModule[{traj},
     traj = Sin@Subdivide[0, 2 Pi, 50]; (*the trajectory to plot*)
     Animate[
      ListPlot[traj[[;; tmax]], DataRange -> {0, 2 Pi*tmax/50}, 
       PlotRange -> {{0, 2 Pi}, {-1, 1}}, PlotRangePadding -> Scaled[.05],
        ImageSize -> 400],
      {tmax, 1, 51, 1, 
       AppearanceElements -> {"ProgressSlider", "PlayPauseButton", 
         "ResetButton", "FasterSlowerButtons"}},
      DisplayAllSteps -> True, AnimationRepetitions -> 1
      ]
     ]
  1. Using Manipulate and localizing traj inside it:
    Manipulate[
     ListPlot[traj[[;; tmax]], DataRange -> {0, 2 Pi*tmax/50}, 
      PlotRange -> {{0, 2 Pi}, {-1, 1}}, PlotRangePadding -> Scaled[.05], 
      ImageSize -> 400],
     {tmax, 1, 51, 1, ControlType -> Animator, DisplayAllSteps -> True, 
      AnimationRepetitions -> 1, 
      AppearanceElements -> {"ProgressSlider", "PlayPauseButton", 
        "ResetButton", "FasterSlowerButtons"}},
     {{traj, Sin@Subdivide[0, 2 Pi, 50]}, ControlType -> None}
     ]
$\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.