The solution is to either A) pre-generate all of your data and shove it into a list (if you really have a finite number of frames), ie data_list = list(data_gen)
B) install from source off my branch that fixes this: PR #2634 or C) monkey patch matplotlib, that is just replace the buggy code in your installation with the fixed code at runtime
C) is the most fun ;)
# copied directly from the proposed fix
def monkey_patch_init(self, fig, func, frames=None, init_func=None, fargs=None,
save_count=None, **kwargs):
if fargs:
self._args = fargs
else:
self._args = ()
self._func = func
# Amount of framedata to keep around for saving movies. This is only
# used if we don't know how many frames there will be: in the case
# of no generator or in the case of a callable.
self.save_count = save_count
# Set up a function that creates a new iterable when needed. If nothing
# is passed in for frames, just use itertools.count, which will just
# keep counting from 0. A callable passed in for frames is assumed to
# be a generator. An iterable will be used as is, and anything else
# will be treated as a number of frames.
if frames is None:
self._iter_gen = itertools.count
elif six.callable(frames):
self._iter_gen = frames
elif iterable(frames):
self._iter_gen = lambda: iter(frames)
if hasattr(frames, '__len__'):
self.save_count = len(frames)
else:
self._iter_gen = lambda: xrange(frames).__iter__()
self.save_count = frames
# If we're passed in and using the default, set it to 100.
if self.save_count is None:
self.save_count = 100
self._init_func = init_func
# Needs to be initialized so the draw functions work without checking
self._save_seq = []
TimedAnimation.__init__(self, fig, **kwargs)
# Need to reset the saved seq, since right now it will contain data
# for a single frame from init, which is not what we want.
self._save_seq = []
We now have a function monkey_patch_init
which is (what I claim) is the fixed code. We now just replace the buggy __init__
function with this function:
matplotlib.animation.FuncAnimation.__init__ = monkey_patch_init
and your animation should work.
ani = animation.FuncAnimation(fig, update, frames=data_gen(a), init_func=init, interval=10, blit=True)
As a side note, don't use plot
as a variable name. A lot of people bulk import pyplot
into their name space (such as by ipython --pylab
) which has plot
-> matplotlib.pyplot.plot
-> plt.gca().plot
hence it makes makes it more likely your code will confuse someone.