11
$\begingroup$

I stumbled upon this (rather contrived but interesting) integer sequence. As it exhibits quite different behaviour at different scales, I would like to generate an animated ListPlot of it, where I'm changing the domain and range at an exponential rate to zoom through the orders of magnitude.

I've got something working but it's pretty glitchy and I'm having trouble getting the size of the points to shrink at a good proportional rate.

seq[n_] := seq@n = Module[{b = 2, l},
   While[! IntegerQ[l = Sqrt@Length@IntegerDigits[n, b]], ++b];
   Flatten[Transpose@(IntegerDigits[n, b]~Partition~l)]~FromDigits~b
   ]
plot[n_] := 
 ListPlot[
   seq /@ Range[n], 
   PlotRange -> {{0, n + 1}, {0, n + 1}}, 
   AspectRatio -> 1, 
   ImageSize -> 400, 
   PlotStyle -> PointSize[0.2/n]
 ]
frames = Rasterize[#, "Image"] & /@ Table[plot[10^(n/25)], {n, 25, 100}];
ListAnimate[frames]

or ultimately

Export["sequence.gif", frames]

which gives

enter image description here

As you can see, despite the fixed aspect ratio and the fixed image size, the actual frames seem to have different sizes, leading to artefacts at the bottom. The axes are glitching all over the place as well, probably due to the changing tick labels.

Ideally I also want to increase the maximum n by another one or two orders of magnitude. I've also considered making the lower bound grow as well (so that I'm always showing a fixed ratio between nMax and nMin, since the interesting features of the plot are concentrated around the seq[n]==n line).

How could I improve the animation to get rid of the glitches, get a consistently useful PointSize and just generally make it look smoother?


Edit: I've incorporated some of the great suggestions in the comments. Here is my current version of the plot function, this time with fixed PointSize to show the issue of the increasing density. I've also adapted the code to only plot one order of magnitude at a time, because lower-left 10th of the domain isn't really interesting at any given scale:

plot[n_] := 
 ListPlot[
   {#, seq@#} & /@ Range[Round[n/10], Round@n], 
   PlotRange -> {{n/10 - 1, n + 1}, {n/10 - 1, n + 1}}, 
   AspectRatio -> 1, 
   ImageSize -> 400, 
   PlotStyle -> PointSize[0.01], 
   ImagePadding -> {{10, 10}, {10, 10}}, 
   TicksStyle -> Directive[FontOpacity -> 0, FontSize -> 0]
 ]

And this is the corresponding animation:

enter image description here

However, that still has issues with the point size and the efficiency of the solution. As I said, I'd like to continue up to one or two more orders of magnitude, and the problem only gets worse, of course.

I also wonder if it would be possible to generate the full ListPlot only once (probably without any axes at all) and then generate an animation of a growing window into that ListPlot. I feel like that should be significantly faster to process, especially if I want to increase the framerate. Of course, that wouldn't make the PointSize issue any easier.

$\endgroup$
19
  • $\begingroup$ You want to add the ImagePadding option to the plot: something like ImagePadding -> {{10, 5}, {15, 5}}. $\endgroup$
    – march
    Commented Dec 1, 2015 at 21:16
  • 1
    $\begingroup$ Perhaps you could eliminate the axes and their ticks. The ticks change so rapidly in the animation that I find them a serious distraction rather than aid to interpreting what is being displayed. Perhaps there is some other way to to annotate the plot that would provide contextual info and not be so distracting. $\endgroup$
    – m_goldberg
    Commented Dec 1, 2015 at 21:19
  • $\begingroup$ ImagePadding -> {{50, 10}, {50, 10}}, will fix it $\endgroup$ Commented Dec 1, 2015 at 21:19
  • 1
    $\begingroup$ Note, there is no need for Rasterize here. Both ListAnimate and Export will handle the graphic objects. $\endgroup$
    – george2079
    Commented Dec 1, 2015 at 21:28
  • $\begingroup$ "...get a consistently useful PointSize..." you have made the point size change with n so presumably by "consistent" you do not mean "constant". Can you clarify? $\endgroup$ Commented Dec 1, 2015 at 21:36

2 Answers 2

6
$\begingroup$

In cases like this, you might have better results using AbsolutePointSize rather than PointSize, which plots things as a proportion of the plot area.

plot[n_] := 
 ListPlot[{#, seq@#} & /@ Range[Round[n/10], Round@n], 
  PlotRange -> {{n/10 - 1, n + 1}, {n/10 - 1, n + 1}}, 
  AspectRatio -> 1, ImageSize -> 400, 
  PlotStyle -> AbsolutePointSize[2], 
  ImagePadding -> {{10, 10}, {10, 10}}, 
  TicksStyle -> Directive[FontOpacity -> 0, FontSize -> 0]]

frames = Rasterize[#, "Image"] & /@ 
   Table[plot[10^(n/25)], {n, 25, 100}];

Export["aps.gif", frames]

enter image description here

Depending on how much shrinkage you want for the point sizes, you could also consider scaling the AbsolutePointSize by n in some way.

plot[n_] := 
 ListPlot[{#, seq@#} & /@ Range[Round[n/10], Round@n], 
  PlotRange -> {{n/10 - 1, n + 1}, {n/10 - 1, n + 1}}, 
  AspectRatio -> 1, ImageSize -> 400, 
  PlotStyle -> AbsolutePointSize[2/(0.05 n)], 
  ImagePadding -> {{10, 10}, {10, 10}}, 
  TicksStyle -> Directive[FontOpacity -> 0, FontSize -> 0]]

enter image description here

$\endgroup$
5
$\begingroup$

As for the point size problem, I got what I thought a better looking plot by simply removing PlotStyle -> PointSize[0.01] from the definition of plot. Here it how it looks for large n.

plot[10000] 

plot10000

plot[10000]

plot100000

$\endgroup$
1
  • $\begingroup$ This is what I had originally, and I found that there were noticeable skips in point size during the animation (which is why I specified the PointSize in the first place). However, now that the other glitches are removed this seems to be much less of a problem. $\endgroup$ Commented Dec 2, 2015 at 7:22

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.