Description
When creating an animation with FuncAnimation and contourf I have run into an issue where the more frames I have the slower things become. This is illustrated in the code below. I print a progress bar, which displays both progress and the time required for the current step. As the animation creation progresses you will see that each step takes longer and longer. I was able to mitigate this by creating a derived class MyFuncAnimation, where I overloaded the function save. In the new version of save I go through and clear all collections associated with self._drawn_artists, after writer.grab_frame, in the following way:
for collection in self._drawn_artists.collections: gca().collections.remove(collection)
I am not sure if there is a better way to do this, but it was the only way I could figure out how to address the issue.
Matplot Version = 1.5.1
Python Version = 3.5.2
Platform = MAC OS 10.11.6
Installed matplotlib through pip
Example:
#!/usr/bin/env python3
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import mlab, cm
from matplotlib.animation import FuncAnimation
import sys
import time
barWidth = 40
n_steps = 100
class ProgressBar():
'''
Provides a simple progress bar class
'''
def __init__(self, nsteps, width=barWidth):
self._start = self._stop = time.time()
self._nsteps = nsteps
self._width = width
self._status = ""
def update(self, step):
'''
This function produces and updates a progress bar.
It was stolen and modified from
http://stackoverflow.com/a/15860757/1552338
'''
self._start = self._stop
self._stop = time.time()
self._status = self._stop - self._start
progress = float(step)/float(self._nsteps - 1)
if progress >= 1:
progress = 1
self._status = "Complete...\r\n"
block = int(round(self._width * progress))
text = "\rProcessing: [{}] {:.1%} {:.3}".format("#" * block
+ "-" * (self._width
- block),
progress,
self._status)
sys.stdout.write(text)
sys.stdout.flush()
# Create x, y data
delta = 0.5
extent = (-3, 4, -4, 3)
x = np.arange(-3.0, 4.001, delta)
y = np.arange(-4.0, 3.001, delta)
X, Y = np.meshgrid(x, y)
# Boost the upper limit to avoid truncation errors.
levels = np.arange(-2.0, 1.601, 0.4)
fig, ax = plt.subplots(1, 1) # create our figure and axes
progress = ProgressBar(n_steps) # initialize the progress bar
def update(frame_number):
'''
This is where our contour is creating
'''
sigma = np.random.uniform(0, 1, 4)
Z1 = mlab.bivariate_normal(X, Y, sigma[0], sigma[1], 0.0, 0.0)
Z2 = mlab.bivariate_normal(X, Y, sigma[2], sigma[3], 1, 1)
Z = (Z1 - Z2) * 10
norm = cm.colors.Normalize(vmax=abs(Z).max(), vmin=-abs(Z).max())
cmap = cm.PRGn
contf = plt.contourf(X, Y, Z, levels,
cmap=cm.get_cmap(cmap, len(levels) - 1),
norm=norm)
progress.update(frame_number)
return contf
# Construct the animation, using the update function as the animation
# director.
anim = FuncAnimation(fig, update, interval=n_steps)
anim.save("AnimContourf.mp4")
plt.close(fig)
sys.stdout.write("\n")