Tim's Blog

Matplotlib Animations

21 Jul 2018

I was browsing through other blogs and reading like I normally do, and noticed that some blogs had animations on the homepage. I thought to myself, gosh wouldn’t that be cool to have on my blog, especially since physics really lends itself to cool animations. In this blog post, I’m going to make three animations of a simple pendulum, the Lennard-Jones potential, and the Maxwell construction. Without further ado, I’ll dive right in.

I was browsing through other blogs and reading like I normally do, and noticed that some blogs had animations on the homepage. I thought to myself, gosh wouldn’t that be cool to have on my blog, especially since physics really lends itself to cool animations. In this blog post, I’m going to make three animations of a simple pendulum, the Lennard-Jones potential, and the Maxwell construction. Without further ado, I’ll dive right in.

To make the animations I’ll use the matplotlib.animation.FuncAnimation API. This API is really easy to use, all that has to be done is define a function that updates the graph for every timestep, which is really easy if data is already in array form. Then I’ll display the animations using the HTML5 video display provided by IPython, but save them as mp4 videos for displaying on the blog homepage.

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rc
from matplotlib.animation import FuncAnimation
from scipy.integrate import solve_ivp
import seaborn as sns
from scipy.optimize import brentq
from scipy.integrate import quad
from IPython.display import HTML
import warnings

warnings.filterwarnings('ignore')
sns.set(style = "darkgrid")

xsize = 12.0
ysize = 8.0

A Simple Pendulum

First animation I want to make will be relatively simple, just a pendulum whose motion is given by the equation,

Since I’m doing this calculation on a computer I don’t have to make the small angle approximation, but I can just solve the equation numerically using scipy.integrate.solve_ivp. I also want to make a graph of $\theta\left(t\right)$ and $\frac{\mathrm{d}\theta}{\mathrm{d}t}$.

g = 9.8
l = 1.5

def pendulum(t, thetas):
    theta, dot_theta = thetas
    return (dot_theta, -(g/l)*np.sin(theta))

tmin = 0.0
tmax = 30.0
pts = 500
ts = np.linspace(tmin, tmax, pts)

sol = solve_ivp(pendulum, [tmin, tmax], [np.pi/3.0, 0.0], t_eval = ts)
%%capture
fig, (ax1, ax2) = plt.subplots(nrows = 2)
fig.set_size_inches(xsize, ysize)

scat = ax1.scatter(sol.t[0], sol.y[0][0], s = 200, color = "k")
line = ax1.plot([0, 0], [0, 0], "k--")[0]
theta_line = ax2.plot(sol.t[0], sol.y[0][0], "g-", label = r"$\theta$")[0]
dottheta_line = ax2.plot(sol.t[0], sol.y[1][0], "r--", label = r"$\frac{\mathrm{d}\theta}{\mathrm{d}t}$")[0]

def animate(i):
    scat.set_offsets(np.c_[-l*np.sin(sol.y[0][i]), -l*np.cos(sol.y[0][i])])
    line.set_ydata([0.0, -l*np.cos(sol.y[0][i])])
    line.set_xdata([0.0, -l*np.sin(sol.y[0][i])])
    theta_line.set_xdata(sol.t[:i])
    theta_line.set_ydata(sol.y[0][:i])
    dottheta_line.set_xdata(sol.t[:i])
    dottheta_line.set_ydata(sol.y[1][:i])
    ax2.set_xlim((0.0, sol.t[i]))

anim = FuncAnimation(fig, animate, interval = 100, frames = len(sol.t)-1)

ax1.axis("equal")
ax1.set(xlim=(-1.6, 1.6), ylim=(-1.6, 0))
ax1.scatter(0.0, 0.0, s = 120, color = "k")
ax1.annotate(r"$\ell=1.5\mathrm{m}$"+"\n"+r"$g=9.8\frac{\mathrm{m}}{\mathrm{s}^2}$", xy = (-2.5, -0.35))
ax1.set_title("Animation of a Simple Pendulum")
ax1.set_xlabel("X Distance "+r"$\left[m\right]$")
ax1.set_ylabel("Y Distance "+r"$\left[m\right]$")
ax2.legend()
ax2.set_xlim((0.0, 0.00001))
ax2_ymax = np.max([np.max(sol.y[0]), np.max(sol.y[1])])
ax2_ymin = np.min([np.min(sol.y[0]), np.min(sol.y[1])])
ax2.set_ylim((ax2_ymin, ax2_ymax))
ax2.set_xlabel("Time "+r"$\left[\mathrm{s}\right]$")
ax2.set_ylabel("Angle "+r"$\left[\mathrm{rad}\right]$"+" and Angular Velocity "+r"$\left[\frac{\mathrm{rad}}{\mathrm{s}}\right]$")
HTML(anim.to_html5_video())