3
$\begingroup$

I have an animation coded like this:

plt[t_] := ParametricPlot[{Cos[s] + t, Sin[s] + t (t + 2 Cos[s])}, {s, 0, 2 Pi}]; 
spp = StreamPlot[{1, 2 x}, {x, -1.2, 2.0}, {y, -1.2, 2.0}, StreamStyle -> {"Line"}]; 
Animate[Show[plt[u], spp, PlotRange -> All], {u, 0, 0.5}]

Which works fine and runs smoothly. However, if I want a more fancy StreamPlot, dropping the "Line" directive so I now have

plt[t_] := ParametricPlot[{Cos[s] + t, Sin[s] + t (t + 2 Cos[s])}, {s, 0, 2 Pi}]; 
spp = StreamPlot[{1, 2 x}, {x, -1.2, 2.0}, {y, -1.2, 2.0}]; 
Animate[Show[plt[u], spp, PlotRange -> All], {u, 0, 0.5}]

The animation slows down significantly and becomes really choppy. I'm fairly sure this is because the StreamPlot spp takes a lot more work to compute now. However, spp is fixed and does not change during the animation, and one would hope that Mathematica can take advantage of that fact.

I tried a few things I could think of, but I'd rather not embarrass myself even more by showing those; suffice it to say that none of them worked. The advanced documentation on Manipulate talks about using Dynamic inside the body of Manipulate to prevent Mathematica from updating parts that do not need to be updated, but I couldn't get that to work.

Is there a way to tell Mathematica to plot spp, and then animate plt[t]"on top of it", without reevaluating either?

Extended Comment:

Following J.M.'s suggestion, I just tried

plt[t_] := ParametricPlot[{Cos[s] + t, Sin[s] + t (t + 2 Cos[s])}, {s, 0, 2 Pi}]; 
    spp = Graphics[StreamPlot[{1, 2 x}, {x, -1.2, 2.0}, {y, -1.2, 2.0}][[1]]]; 
    Animate[Show[plt[u], spp, PlotRange -> All], {u, 0, 0.5}]

but the animation is just as choppy. However, if I do

Timing[Show[spp]]

I get 0.. I take that to mean that showing the streamplot should not slow things down that much, but perhaps I am missing something.

$\endgroup$
  • $\begingroup$ It may be more effective to pre-calculate a list of the objects to animate, then use ListAnimate on the list. For instance, ListAnimate@ Table[Show[plt1, plt2[u], spp, PlotRange -> All], {u, 0, 0.5, 0.005}] is pretty smooth. Alternatively, you could try and play with the step size in independent variable within Animate together with DisplayAllSteps -> True, and perhaps with AnimationRate. $\endgroup$ – MarcoB Oct 2 '16 at 0:41
  • $\begingroup$ Thanks, but I know about the workaround of using ListAnimate. The issue with that is that it may take a long time to initialize the animation, and/or it makes the size of the notebook (and later the CDF) balloon enormously. The advanced documentation on Manipulate talks about using Dynamic inside the body of Manipulate to prevent Mathematica from updating parts that do not need to be updated, but I couldn't get that to work. I'm certain that it's possible to speed things up, I just seem to be unable to figure this out. $\endgroup$ – Pirx Oct 2 '16 at 0:57
  • $\begingroup$ The main issue here is that Animate insists on redoing the streamplot for every frame, even though that plot never changes. If I could find a way to keep Mathematica from updating this plot, things would be perfect. $\endgroup$ – Pirx Oct 2 '16 at 0:59
  • $\begingroup$ What version and OS are you on? Version 11 on Xubuntu Trusty gives a relatively smooth animation. If need be, you could extract just the first part of spp (it is a Graphics[] object after all) and put that instead in the animation. $\endgroup$ – J. M. will be back soon Oct 2 '16 at 13:45
  • $\begingroup$ This is version 11.0.1 on Win7 x64. You mean like Animate[Show[plt[u], Graphics[spp[[1]]], PlotRange -> All], {u, 0, 0.5}]? That's just as slow as the first. P.S.: Are you saying you're not seeing a big difference between the two versions I have given? $\endgroup$ – Pirx Oct 2 '16 at 13:50
2
$\begingroup$

I believe it is simply that rendering many arrows is slower than rendering fewer lines. Wrapping the ParametricPlot[] in Dynamic to isolate the dynamic updates will mean that only part of the graphics will be updated in the FE's workings. Note Show[Dynamic@Graphics[..]] does not work; you have to have the structure Show[Graphics[Dynamic@stuff]] (or have Dynamic buried further within stuff). Below I use ParametricPlot[] to dynamically construct the stuff to be plotted.

plt[t_] := ParametricPlot[{Cos[s] + t, Sin[s] + t (t + 2 Cos[s])}, {s, 0, 2 Pi}];
spp = StreamPlot[{1, 2 x}, {x, -1.2, 2.0}, {y, -1.2, 2.0}];
Animate[Show[Graphics[Dynamic@First@plt[u], Options[plt[0]]], spp, 
  PlotRange -> All],
 {u, 0, 0.5}]

The options Options[plt[0]] could be pre-computed and injected, but since in the above it is never recomputed, it doesn't matter.

$\endgroup$
  • $\begingroup$ Great, that does the trick! My problem really was to figure out how to apply the Dynamic. Thanks! $\endgroup$ – Pirx Oct 2 '16 at 21:52
  • $\begingroup$ @Pirx You're welcome. Yeah, I think this problem & trick deserves to be better known. $\endgroup$ – Michael E2 Oct 2 '16 at 21:54
  • 1
    $\begingroup$ @Pirx Here's an alternative solution, with a slightly different styling inherited from StreamPlot instead of from ParametricPlot: Animate[StreamPlot[{1, 2 x}, {x, -1.2, 2.0}, {y, -1.2, 2.0}, Epilog -> Dynamic@First@plt[u]], {u, 0, 0.5}] $\endgroup$ – Michael E2 Oct 2 '16 at 21:59
  • $\begingroup$ Yes. I'm still at a stage where I'm asking myself whether I was just being dense and should have read the docs more attentively, or whether it's really something that's not easy to discover. For once, that's not even a knock of Wolfram; the functionality is so enormous that I understand it's just hard to document everything properly. But, specifically, how would I have figured out exactly how to use Dynamic here, from the built-in documentation? $\endgroup$ – Pirx Oct 2 '16 at 21:59
  • 3
    $\begingroup$ @Pirx I figured out it a long time ago (in V6) by paying attention to what worked and what didn't and thinking about it -- and by a lot of trial and error, and rereading the advanced docs. The generic tip I got from the developers was that the Dynamic[] has to get passed to the Front End. In Show[Dynamic@Plot[],..], it fails in the Kernel, before it reaches the FE. Therefore you have to think of something else. Of course, "passed to the FE" is not the whole story, but for a simple rule, I get pretty good mileage out of it. $\endgroup$ – Michael E2 Oct 2 '16 at 22:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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