In this tutorial, we illustrate how animations can be produced with the Matplotlib
module.
We load the necessary functions as follows
import matplotlib.pyplot as plt
from matplotlib import animation
Examples of animations can be found in the matplotlib
website:
Matplotlib Animation.
In this first example, we want to simulate the motion of a projectile according to the parametric equations $$ x(t) = (v_0 \cos\alpha) t, \qquad y(t)= (v_0\sin\alpha) t - g\frac{t^2}{2} \qquad \text{(1-2)} $$ starting at $t=0$ with initial velocity $(v_0 \cos\alpha, v_0\sin\alpha)$. We end the motion at $t_{max}= D/v_0 \cos\alpha$ when $x= D$. At $t=t_{max}$ we have $y=h$ according (2). We will also plot a rectangular building whose base is at $(D,0)$, of width $2d$ and height $h$. We will follow these steps:
Step 1: we import the necessary modules and functions
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
Step 2: we define the necessary parameters, such as $v_0$, $\alpha$, $g$, $D$, $d$, etc.
We will increment time with step size dt
corresponding to Nstep
. Nstep
will also define
the number of frames of the animation.
v0 = 50 # [m/s]
g = 9.81 # [m/s^2]
alpha= 50 # [deg]
D= 220 # [m]
d= 10 # [m]
alpha = alpha*np.pi/180 # launch angle
Tmax = D/(v0*np.cos(alpha)) # maximum time of motion
xmax = D+2*d # parameters for the graphical window
ymax = 0.55*(v0*np.sin(alpha))**2 /g
Nstep= 400 # number of time steps /number of frames
dt= Tmax/Nstep # time increment
h= D*np.tan(alpha)-0.5*g*(D/v0/np.cos(alpha))**2 # height of rectangular object
Step 3: we set up the figure, the axis, and the plot element to be animated. This element is an empty line object with the desired attributes. The line object will be updated along the simulation at a later stage (Step 6). We also add the static rectangular object to the plot.
fig = plt.figure()
ax = plt.axes(xlim=(0, xmax), ylim=(0, ymax))
plt.xlabel('x(m): horizontal distance')
plt.ylabel('y(m): height')
line, = ax.plot([], [], 'o', ls='-', ms=8, markevery=[0,-1])
xR,yR = D-d,0. # lower left corner of rectangle
dx,dy= 2*d, h # dimensions of rectangle
rect = plt.Rectangle((xR,yR), dx,dy, facecolor= 'black', edgecolor= 'black')
ax.add_patch(rect)
Step 4: we define an initialization function to plot the background of each frame. This function sets the line object with empty data. By returning the line object, the animator now knows which plot object needs to be updated during the animation.
def init():
line.set_data([], [])
return line,
Step 5: we define the animation function which updates the line object with time.
It has a single argument: the integer i
which defines the frame number. Time is defined
in terms of this integer i
, according to a particular scale. In our case, the line object is defined
by 2 arrays $x$ and $y$ parameterized with time according to equations (1-2).
This function will be called sequencially by the animator.
def animate(i):
t= np.linspace(0, i*dt, 2*i)
x = v0*np.cos(alpha)*t
y = v0*np.sin(alpha)*t -0.5*g*t**2
line.set_data(x, y)
return line,
Step 6: now we call the animator FuncAnimation
.
The resulting object must be assigned to a variable, here anim
. We define the animation by
the number of frames Nstep
with a 20ms delay between frames. The blit
keyword is important: it
indicates the animator to only redraw the parts of the plot which have changed.
By setting blit=True
, the animations display much more quickly and the resulting video file
will be smaller. The optional save
command saves the data in mp4 video file.
The show
command display thes final result.
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=Nstep, interval=20, blit=True)
# save the animation as an mp4. This requires ffmpeg or mencoder to be
# installed. The extra_args ensure that the x264 codec is used, so that
# the video can be embedded in html5.
anim.save('projectile_animation.mp4', fps=30, extra_args=['-vcodec', 'libx264'])
plt.show()
The python
script can be found here.
In this script, we add a clock to display the time elapsed.