Hands-on Tutorials

Animations are great data visualization tools to convey complicated insights engagingly. In this article, we will walk through the steps of creating an Animation with Matplotlib
and Celluloid
.
This is what we will make: it simulates various projectile motion trajectories and updates the associated histogram of the projectile shooting range.
This tutorial goes as follows. After introducing the animation packages and the employed data, we dive straight into creating the animation. We go from simple to complex: to start, we animate a single trajectory, followed by animating multiple trajectories. Finally, we will add a histogram component and take a close look at how to synchronize the histogram updates with the trajectory data.
If your time is short, the simple example of animating a single trajectory should be sufficient to give you a good grasp of the general workflow. Otherwise, I would encourage you to go through all the steps.
This Jupyter Notebook contains the code for this tutorial. Alternatively, you could run the code on Google Colaboratory.
Without further ado, let’s get to it!
Table of Content
· 1. Packages · 2. Data · 3. Animate A Single Trajectory · 4. Animate Multiple Trajectories · 5. Animate Histogram · 6. Side Notes · About the Author
1. Packages
In this tutorial, we will use theCelluloid
module. If you have ever made a plot with Matplotlib
, creating animations with Celluloid
is no more difficult. The basic idea is to use a "Camera" to take snapshots of individual frames, which are later rolled up into an animation.
To install Celluloid
, use
pip install celluloid
Also, to display the created animation within the Jupyter notebook, we need to import HTML
from IPython.display
.
2. Data
For this Tutorial, we will load the pre-calculated projectile trajectory data: two NumPy 2D arrays that record the 𝑥 and 𝑦 coordinates of the projectile trajectories, respectively.
Both NumPy arrays have 1000 rows, corresponding to 1000 different trajectories. Each trajectory is discretized with 20 points, hence the NumPy arrays have 20 columns. One sample trajectory is plotted below.

3. Animate A Single Trajectory
Now we are ready to create some animations! We start by simulating a single trajectory. Let’s first see the code and the output, and then we elaborate on the steps to get there.
- We set up the graph using
Matplotlib
(line 12–16). - We initiate a
Camera
instance using the created graph (line 19). - We create 20 frames, where each frame depicts the current location of the projectile and its trajectory.
camera.snap()
is used to take a snapshot of the individual frames (line 22–35). - We call
camera.animate()
to roll the captured snapshots up into an animation (line 38). - We display the animation with
HTML
(line 41).
Under the hood, camera.animate()
uses [animation.ArtistAnimation(](https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.animation.ArtistAnimation.html))
from Matplotlib
. We feed three parameters to camera.animate()
: the interval, which controls the delay between frames in milliseconds; the repeat, which controls whether the animation should repeat when the sequence of frames is completed; the _repeatdelay, which controls the delay in milliseconds before repeating the animation when the animation is set to repeat.
4. Animate Multiple Trajectories
Once we get the hang of simulating a single trajectory, simulating multiple trajectories becomes easy. We simply need to add an extra loop to cycle through all the trajectories.
For demonstration purposes, we will simulate the first 30 trajectories. The steps are the same as the last example. However, in this example, we will create a total of 20×30 frames to capture all 30 trajectories.
Here is the animation we’ve just made.
5. Animate Histogram
In this final step, we will add an updating histogram on top of multiple trajectory simulations. This histogram describes the distribution of the shooting range, and it updates when receiving new data, i.e., when a sample trajectory reaches its end.
First, let’s extract the range data and obtain the bins’ edges for plotting the histogram.
Then, let’s specify how we want our histogram to behave:
- the histogram has its own y-axis;
- the histogram only gets updated in the frames when a sample trajectory reaches its end;
- in other frames when the projectile is still "flying," the histogram should stay the same.
To address those requirements, we will
- use
ax.twin()
to create a twin Axes that shares the x-axis while having an independent y-axis. This new twin axis will host our histogram; - maintain a list R, which contains the range values for all sample trajectories. R starts as an empty list and gets appended when a new trajectory reaches its end. The final x coordinate value of this new trajectory (i.e., its shooting range) is appended to R;
-
plot the histogram using the up-to-date R.
Here are the results.
There you have it! Thanks for going through the entire tutorial😊 Hopefully, the stuff covered in this tutorial could help create your own animations!
6. Side Notes
The animation we’ve just made is intended to show the audience the uncertainty of the projectile shooting range under various combinations of initial projectile velocity and shooting angle. This type of visualization is also known as the Hypothetical Outcome Plots, a powerful technique that is especially good at delivering intuitive and effective uncertainty visualization. To learn more about hypothetical outcome plots, take a look at this article:
Uncertainty Visualization Made Easy With Hypothetical Outcome Plots
About the Author
I’m a Ph.D. researcher working on uncertainty quantification and reliability analysis for aerospace applications. Statistics and data science form the core of my daily work. I love sharing what I’ve learned in the fascinating world of statistics. Check my previous posts to find out more and connect with me on Medium and Linkedin.