[UPDATE: A full Solar System model is now available that you can view, animated using the techniques described in this post! See Ptolemy’s cosmos, to scale.]
You will recall my previous blog post that tried to build the necessary scaffolding for me to finally write up my 2017 PyCon Ireland keynote on the structure of the Medieval universe. It ran into several problems with matplotlib animations — but, having written that post, I realized that the problem ran deeper.
How could any animation show a Solar System, when a Solar System’s motion never exactly repeats? The orbital periods of the planets aren’t exact multiples of each other, and don’t provide a moment when the planets reach their original positions and the animation can start over again. At whatever moment an animation finished and looped back to the beginning, the planets would visibly and jarringly jump back to their original position.
But then I remembered that modern browsers support animation directly, and thought: could a python script produce an SVG diagram with a separate CSS animation for each planet, that repeated each time that specific planet finished a revolution?
The result would be an animated Solar System that fits into a few thousand bytes, would render with perfect clarity, and runs continuously for as long has the viewer was willing to watch!
But there’s a problem.
The CSS animation mechanism is perfect
for the simplest possible planetary orbit: uniform circular motion.
Here’s a simple SVG diagram in which a planet
and the line connecting it to the origin
are grouped within a single <g> element.
%pylab inline from IPython.display import HTML 𝜏 = 2.0 * pi circular_svg = ''' <svg version="1.1" width=220 height=220> <g transform="translate(110, 110)"> <circle cx=0 cy=0 r=100 stroke=lightgray stroke-width=1 fill=none /> <g class="anim %s"> <line x1=0 y1=0 x2=100 y2=0 stroke=lightgray /> <circle cx=100 cy=0 r=5 fill=#bb0 /> </g> <circle cx=0 cy=0 r=3 fill=#040 /> </g> </svg> ''' HTML(circular_svg % 'stationary')
Populating the interactive namespace from numpy and matplotlib
We use translate() to move (0,0) to the middle of the diagram
where it can serve as the circle’s center.
We paint a big circle for the orbit,
small circles to mark the orbit’s center and a planet,
and a line to link them.