I recently needed to overlay a Matplotlib animation on an image in a keynote
presentation. This requires creating an animation with a transparent background
so that only the plot elements are shown. It turns out that this is possible
using the Matplotlib animation objects (note: I've only tried this on Mac). The
key elements to doing this are to (1) make the Matplotlib figure background
invisible, (2) save the video using a png codec (yes, the image format), and (3)
to pass keyword arguments through the animation object to the individual
Matplotlib savefig
calls. I'll show a simple example below of a circle
orbiting in a circle with a trail of points that fade out. (Note: running this
code requires installing
JSanimation.) First, imports:
# Third-party
from matplotlib import animation
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
from JSAnimation.IPython_display import display_animation
We start by defining how many frames (timesteps) to use in the animation, and how many circles to draw in the trail:
n_frames = 128
n_trails = 8
The circle will orbit in a circle:
t = np.linspace(0, 10, n_frames)
x = np.sin(t)
y = np.cos(t)
Finally, the meat of the code containing the calls to Matplotlib:
fig,ax = plt.subplots(1,1,figsize=(8,8))
ax.set_xlim(-1.1, 1.1)
ax.set_ylim(-1.1, 1.1)
# turn off axis spines
ax.xaxis.set_visible(False)
ax.yaxis.set_visible(False)
ax.set_frame_on(False)
# set figure background opacity (alpha) to 0
fig.patch.set_alpha(0.)
fig.tight_layout()
pt, = ax.plot([], [], linestyle='none', marker='o', ms=15, color='r')
trails = []
for i,alpha in enumerate(np.linspace(1.,0,n_trails)):
l, = ax.plot([], [], linestyle='none', marker='o', ms=6, alpha=alpha, c='w', zorder=-1000)
trails.append(l)
def init():
pt.set_data([], [])
for trail in trails:
trail.set_data([], [])
return (pt,) + tuple(trails)
def update(i):
ix = i - n_trails
pt.set_data(x[i], y[i])
for j,trail in zip(range(len(trails))[::-1],trails):
if ix+j < 0:
continue
trail.set_data(x[ix+j], y[ix+j])
return (pt,) + tuple(trails)
ani = animation.FuncAnimation(fig, update, n_frames, init_func=init,
interval=20, blit=True)
display_animation(ani)
Notice the lines that hide the plot elements and make the figure background transparent:
ax.xaxis.set_visible(False)
ax.yaxis.set_visible(False)
ax.set_frame_on(False)
and
fig.patch.set_alpha(0.)
To save the video out with a transparent background, the other critical
arguments are to the save()
call, especially the keyword arguments passed
through via savefig_kwargs
:
ani.save('circle_anim.mov', codec="png",
dpi=100, bitrate=-1,
savefig_kwargs={'transparent': True, 'facecolor': 'none'})