2
$\begingroup$

I am using Manipulate to simulate Brownian motion. I want to be able to zoom in. Thus, I want to use Dynamic for the PlotRange option so that this can be done quickly without recomputing the motion. It works properly without Dynamic (except for speed), but using Dynamic changes its operation so that the range is no longer what I ask for once I zoom in sufficiently. See this by changing the "horizontal zoom". I also have the same PlotRange in Show. It seems I need both. No doubt I am not doing other things optimally, but this issue is a separate problem. Here is my code, first without the first Dynamic and second with it. At the end is a smaller example. It behaves differently, but again the behavior depends on whether PlotRange has Dynamic or not. This last example contains both types of code in it. It comes in two forms, one using Show and one not.

Manipulate[
Module[{bmPath, iterate}, SeedRandom[seed]; 
iterate[l_List] := 
Module[{i = 1, len = Length[l], new = l}, 
While[i < Length[new], 
 new = Insert[
   new, (new[[i]] + new[[i + 1]])/2 + 
    RandomVariate[NormalDistribution[0, .5/Sqrt[(len - 1)]]], 
   i + 1]; i = i + 2]; new]; 
bmPath = {0, RandomVariate[NormalDistribution[0, 1]]}; 
Do[bmPath = iterate[bmPath], {n}]; 
Show[ListLinePlot[bmPath, AxesLabel -> {"Time", "Location"}, 
DataRange -> {0, 1}, 
PlotRange -> {Clip[{hcenter - 2^(-zoom), hcenter + 2^(-zoom)}, {0,
     1}], vcenter + {-2, 2}/2^(scale/2)}], 
Plot[{Sqrt[x], -Sqrt[x]}, {x, 0, 1}, 
PlotStyle -> If[bound, Dotted, Opacity[0]]], 
PlotRange -> 
Dynamic[{Clip[{hcenter - 2^(-zoom), hcenter + 2^(-zoom)}, {0, 1}],
   vcenter + {-2, 2}/2^(scale/2)}], 
AxesOrigin -> Dynamic[{hcenter, vcenter}], 
ImageSize -> {475, 360}]],
{{n, 10, "detail"}, 1, 40, 1, Appearance -> {"Labeled", "Open"}, 
AnimationRate -> rate}, {{rate, 1, "rate"}, 1, 3, 1, 
Appearance -> "Labeled"}, {{bound, False, 
"show sqrt bounds"}, {True, False}}, Delimiter, {{hcenter, .5, 
"horizontal center"}, 0, 1, .01/2^(zoom - 1), 
Appearance -> {"Labeled", "Open"}, 
AnimationRate -> .2/2^(zoom - 1)}, {{vcenter, 0, 
"vertical center"}, -3, 3, .01/2^(scale - 1), 
Appearance -> {"Labeled", "Open"}, 
AnimationRate -> .1/2^(scale - 1)}, Delimiter, {{zoom, 1, 
"horizontal zoom"}, 1, 20, 1, 
Appearance -> {"Labeled", "Open"}}, {{scale, 1, 
"vertical scale"}, -2, 20, 1, 
Appearance -> {"Labeled", "Open"}}, Delimiter, {{seed, 77777, 
"new random case"}, 10000, 999999, 1, Appearance -> "Open", 
AnimationRate -> newrate}, {{newrate, 1, "rate of new case"}, 1, 10,
1, Appearance -> "Labeled"},
ControlPlacement -> Right, SynchronousUpdating -> False]


Manipulate[
Module[{bmPath, iterate}, SeedRandom[seed]; 
iterate[l_List] := 
Module[{i = 1, len = Length[l], new = l}, 
While[i < Length[new], 
 new = Insert[
   new, (new[[i]] + new[[i + 1]])/2 + 
    RandomVariate[NormalDistribution[0, .5/Sqrt[(len - 1)]]], 
   i + 1]; i = i + 2]; new]; 
bmPath = {0, RandomVariate[NormalDistribution[0, 1]]}; 
Do[bmPath = iterate[bmPath], {n}]; 
Show[ListLinePlot[bmPath, AxesLabel -> {"Time", "Location"}, 
DataRange -> {0, 1}, 
PlotRange -> Dynamic[{Clip[{hcenter - 2^(-zoom), hcenter + 2^(-zoom)}, {0,
     1}], vcenter + {-2, 2}/2^(scale/2)}]], 
Plot[{Sqrt[x], -Sqrt[x]}, {x, 0, 1}, 
PlotStyle -> If[bound, Dotted, Opacity[0]]], 
PlotRange -> 
Dynamic[{Clip[{hcenter - 2^(-zoom), hcenter + 2^(-zoom)}, {0, 1}],
   vcenter + {-2, 2}/2^(scale/2)}], 
AxesOrigin -> Dynamic[{hcenter, vcenter}], 
ImageSize -> {475, 360}]],
{{n, 10, "detail"}, 1, 40, 1, Appearance -> {"Labeled", "Open"}, 
AnimationRate -> rate}, {{rate, 1, "rate"}, 1, 3, 1, 
Appearance -> "Labeled"}, {{bound, False, 
"show sqrt bounds"}, {True, False}}, Delimiter, {{hcenter, .5, 
"horizontal center"}, 0, 1, .01/2^(zoom - 1), 
Appearance -> {"Labeled", "Open"}, 
AnimationRate -> .2/2^(zoom - 1)}, {{vcenter, 0, 
"vertical center"}, -3, 3, .01/2^(scale - 1), 
Appearance -> {"Labeled", "Open"}, 
AnimationRate -> .1/2^(scale - 1)}, Delimiter, {{zoom, 1, 
"horizontal zoom"}, 1, 20, 1, 
Appearance -> {"Labeled", "Open"}}, {{scale, 1, 
"vertical scale"}, -2, 20, 1, 
Appearance -> {"Labeled", "Open"}}, Delimiter, {{seed, 77777, 
"new random case"}, 10000, 999999, 1, Appearance -> "Open", 
AnimationRate -> newrate}, {{newrate, 1, "rate of new case"}, 1, 10,
1, Appearance -> "Labeled"},
ControlPlacement -> Right, SynchronousUpdating -> False]


Manipulate[
Module[{bmPath}, bmPath = {0, 2, 1}; 
Row[{ListLinePlot[bmPath, AxesLabel -> {"Time", "Location"}, 
 DataRange -> {0, 1}, 
 PlotRange -> 
  Dynamic[{Clip[{.5 - 2^(-zoom), .5 + 2^(-zoom)}, {0, 1}], {-2, 
     2}}], ImageSize -> {200, 100}], 
ListLinePlot[bmPath, AxesLabel -> {"Time", "Location"}, 
 DataRange -> {0, 1}, 
 PlotRange -> {Clip[{.5 - 2^(-zoom), .5 + 2^(-zoom)}, {0, 
     1}], {-2, 2}}, ImageSize -> {200, 100}]}]],
{{zoom, 1, "horizontal zoom"}, 1, 20, 1, 
Appearance -> {"Labeled", "Open"}},
ControlPlacement -> Right, SynchronousUpdating -> True]


Manipulate[
Module[{bmPath}, bmPath = {0, 2, 1}; 
Row[{ListLinePlot[bmPath, AxesLabel -> {"Time", "Location"}, 
 DataRange -> {0, 1}, 
 PlotRange -> 
  Dynamic[{Clip[{.5 - 2^(-zoom), .5 + 2^(-zoom)}, {0, 1}], {-2, 
     2}}], ImageSize -> {200, 100}], 
Show[ListLinePlot[bmPath, AxesLabel -> {"Time", "Location"}, 
  DataRange -> {0, 1}], 
 PlotRange -> 
  Dynamic[{Clip[{.5 - 2^(-zoom), .5 + 2^(-zoom)}, {0, 1}], {-2, 
     2}}], ImageSize -> {200, 100}]}]],
{{zoom, 1, "horizontal zoom"}, 1, 20, 1, 
Appearance -> {"Labeled", "Open"}},
ControlPlacement -> Right, SynchronousUpdating -> True]
$\endgroup$
7
  • 3
    $\begingroup$ Is this a minimum working example? $\endgroup$
    – Michael E2
    Commented May 3, 2014 at 23:02
  • $\begingroup$ Of course some of the sliders could be eliminated, but they are not very complicated. Because I am not sure what is causing the problem and I need to have all those things there, it is hard to find the minimum example. I have already tried many variations. Sorry about that. However, if you execute this code, I think it will be clear what is going on. I'm happy to clarify anything. $\endgroup$
    – Russ Lyons
    Commented May 3, 2014 at 23:10
  • $\begingroup$ I just added a minimal example. Sorry for not doing so from the start. $\endgroup$
    – Russ Lyons
    Commented May 4, 2014 at 0:13
  • $\begingroup$ It's because Dynamic[{Clip[{.5 - 2^(-zoom), .5 + 2^(-zoom)}, {0, 1}], {-2, 2}}] is a not a proper form for the option PlotRange. Further the Dynamic wrapper isn't needed. $\endgroup$
    – m_goldberg
    Commented May 4, 2014 at 0:38
  • $\begingroup$ Would you mind giving a fuller explanation or pointing to more? As you can see from the first code, Dynamic is needed there when it modifies PlotRange for Show. The whole point of using Dynamic is to speed things up when zooming (or panning, etc.). $\endgroup$
    – Russ Lyons
    Commented May 4, 2014 at 1:19

3 Answers 3

3
$\begingroup$

It appears that ListLinePlot needs the PlotRange to be an actual list of numbers or another valid setting; something of the form PlotRange -> Dynamic[expr] generates an error. Here's an example:

Module[{bmPath}, bmPath = {0, 2, 1};
 Show[
  ListLinePlot[bmPath, AxesLabel -> {"Time", "Location"}, 
   DataRange -> {0, 1}, ImageSize -> {200, 100}, 
   PlotRange -> 
    Dynamic@{Clip[{.5 - 2^(-2), .5 + 2^(-2)}, {0, 1}], {-2, 2}}]
  ]]

ListLinePlot::prng: Value of option PlotRange -> {{0.25,0.75},{-2,2}} is not All, Full, Automatic, a positive machine number, or an appropriate list of range specifications. >>

ListLinePlot seems to use PlotRange to compute things like the axes, and must have an actual numerical setting or one like Automatic. The way around is to take the graphics returned by ListLinePlot and reset the PlotRange with Show. Graphics may have a dynamic PlotRange. ListLinePlot also explicitly sets the AxesOrigin, so that needs to be reset to Automatic with Show as well.

Manipulate[
 Module[{bmPath},
  bmPath = Accumulate@RandomReal[{-0.1, 0.1}, 10000];
  Row[{
    Show[
     ListLinePlot[bmPath, AxesLabel -> {"Time", "Location"}, 
      DataRange -> {0, 1}, ImageSize -> {200, 100}],
     PlotRange -> Dynamic@{Clip[{.5 - 2^(-zoom), .5 + 2^(-zoom)}, {0, 1}], Automatic},
     PlotRangePadding -> 0,
     AxesOrigin -> Automatic
     ]}]
  ],
 {{zoom, 1, "horizontal zoom"}, 1, 20, 1, Appearance -> {"Labeled", "Open"}},
 ControlPlacement -> Right, SynchronousUpdating -> True]

Mathematica graphics

$\endgroup$
4
  • $\begingroup$ It seems to me that your example does not work: Try increasing the zoom. it is supposed to zoom by a factor of 2 for each increase by 1, but it stops doing that around the value of zoom = 4 and is especially evident around zoom = 8. $\endgroup$
    – Russ Lyons
    Commented May 4, 2014 at 2:45
  • $\begingroup$ @RussLyons PlotRange is working. It's PlotRangePadding that you're observing. Set it as you desire. Above I modified it to be 0. ListLinePlot does not follow the standard Plot option defaults it seems; this may be version dependent. $\endgroup$
    – Michael E2
    Commented May 4, 2014 at 12:22
  • $\begingroup$ @RussLyons You're welcome. $\endgroup$
    – Michael E2
    Commented May 4, 2014 at 14:48
  • 1
    $\begingroup$ @MichaelE2, this problem also appears in other array plotting functions (Array/Matrix Plot)- it has been annoying/puzzling me for the past hour. Thanks for clarifying (+1) $\endgroup$
    – gpap
    Commented Dec 5, 2014 at 13:29
3
$\begingroup$

Let me quote something:

Kuba said:

Why some Options works with Dynamic and other doesn't?

John Fultz said:

The difference is that some option values get translated directly into FE option values. Others affect kernel computation, but don't have a direct translation into the FE.

And, as I've lectured many times before, Dynamic is useless unless it's displaying, directly, in the FE.

For example, look at the Plot function. Something like ImageSize goes directly to the FE. So Dynamic translates well there. But PlotPoints affects the underlying mechanisms of Plot itself, not anything the FE is actually doing.

If you want to change PlotPoints based upon a Dynamic setting, then you need to recompute the entire Plot. So Dynamic needs to wrap the entire Plot.

*FE -> FrontEnd

$\endgroup$
2
  • $\begingroup$ I don't think it will work to wrap the whole plot in Dynamic because then I cannot use SynchronousUpdating -> False, which is the whole point of speeding up the display by not recomputing the data (at least, as far as I understand it). $\endgroup$
    – Russ Lyons
    Commented May 4, 2014 at 14:44
  • $\begingroup$ @RussLyons This is not the anaswer that says what you have to do but it says why PlotRange with Dynamic is not working. Wrapping everything in Dynamic is quick solution but not necessairly good idea as you can tell. You may ofcourse try specific solutions. P.s. everything in Manipulate body is effectively wrapped in Dynamic. $\endgroup$
    – Kuba
    Commented May 4, 2014 at 14:49
1
$\begingroup$

The problem is that the PlotRangePadding of your ListLinePLot is absolute and doesn't use Scaled expressions.

Compare the behavior of these two examples:

center = 2;
width = 2;
llp = ListLinePlot[{1, 2, 3}];
p = Plot[x, {x, 1, 3}];

Manipulate[
 Show[
  llp,
  PlotRange -> Dynamic@{center + width {-1, 1} 2^-zoom, {1, 3}}
  ],
 {zoom, 1, 20, 1}
 ]

Manipulate[
 Show[
  p,
  PlotRange -> Dynamic@{center + width {-1, 1} 2^-zoom, {1, 3}}
  ],
 {zoom, 1, 20, 1}
 ]

Like your example, the first fails to zoom any further after a certain point. The second works fine.

Take a look at the option settings for each of those plots:

In[90]:= Options[llp, PlotRangePadding]

Out[90]= {PlotRangePadding -> {{0.04, 0.04}, {0.04, 0.04}}}

In[91]:= Options[p, PlotRangePadding]

Out[91]= {PlotRangePadding -> {Scaled[0.02], Scaled[0.02]}}

ref/PlotRangePadding:

PlotRangePadding is an option for graphics functions that specifies how much further axes etc. should extend beyond the range of coordinates specified by PlotRange.

So the behavior here is that your PlotRangePadding setting is keeping your range at a minimum of just over .08 coordinate units despite the PlotRange setting. You'll want to scale that padding as you zoom, thus Scaled is called for.

You might try setting PlotRangePadding in the ListLinePlot expression itself. For some reason, that doesn't seem to work. In 9.0.1 on Linux, I get back the exact same absolute setting.

It seems like you have to set it with Show, side-by-side with PlotRange. E.g.:

Manipulate[
 Show[
  llp,
  PlotRangePadding -> {[email protected], [email protected]},
  PlotRange -> Dynamic@{center + width {-1, 1} 2^-zoom, {1, 3}}
  ],
 {zoom, 1, 20, 1}
 ]

I made the same adjustment to your original example. It worked.

$\endgroup$
7
  • $\begingroup$ Thank you for the detailed explanation! $\endgroup$
    – Russ Lyons
    Commented May 4, 2014 at 14:35
  • $\begingroup$ @RussLyons, no problem at all, very glad to help. I don't mean to be overly concerned with rep etc., but what was missing from this answer that made you decide not to mark it as the accepted one? The answer you've currently marked as accepted didn't mention the actual issue at all until an edit and comment about 5 hours ago, which was about 8 hours after I posted this answer. $\endgroup$
    – William
    Commented May 4, 2014 at 18:16
  • $\begingroup$ It was hard to decide which to accept. I didn't see either of them until this morning, so the order of posting was not a factor. I decided that having 0 padding was what I really wanted, so I accepted that. Actually, while your explanation was very good and helpful, it did not completely answer my question in the sense that it did not explain why Dynamic made a change. Without testing it, I suspect that the reason is that Dynamic prevents the range from being seen at all; having a PlotRange that is seen overrides the default padding. That's why it was so confusing to me in my original code. $\endgroup$
    – Russ Lyons
    Commented May 4, 2014 at 20:39
  • $\begingroup$ @RussLyons, thanks for this feedback, very fair. Sorry I overlooked that aspect. Even after some more experimentation and lookup right now, I'm not sure why ListLinePlot doesn't complain at all about the Dynamic wrapper around its PlotRange setting. Plot certainly complains in the same setting. E.g. Manipulate[Plot[x, {x, 1, 3}, PlotRange -> Dynamic@s], {s, 1, 20}] vs. Manipulate[ListLinePlot[Range@3, PlotRange -> Dynamic@s], {s, 1, 20}]. I filed a report with WRI in case it's bad behavior. Anyway, thanks for your kind and thoughtful words. $\endgroup$
    – William
    Commented May 5, 2014 at 1:46
  • $\begingroup$ BTW, at some point when I have more time, it is possible I will decide that in the end, I will want scaled padding as you suggested. But for now I use 0. $\endgroup$
    – Russ Lyons
    Commented May 5, 2014 at 12:32

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.