I'm using matplotlib animation by calling:
plot = animation.FuncAnimation(fig, update, frames=data_gen(a), init_func=init, interval=10, blit=True)
Here, "a" is an initial value for the data_gen function which looks like this:
data_gen(x)
old_x = x
while True:
new_x = func(old_x)
old_x = new_x
yield new_x
The intention for this code is for data_gen to produce a new value for new_x each time the animated plot is updated.
BUT... this happens instead:
animation.py throws an error in the init() method of the FuncAnimation class.
The problem happens in this code:
elif iterable(frames):
self._iter_gen = lambda: iter(frames)
self.save_count = len(frames)
The error is "TypeError: object of type 'generator' has no len()"
It looks like data_gen is iterable but it has no len().
Here is more of the code for the init() method in the FuncAnimation class:
# 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 isinstance(frames, collections.Callable):
self._iter_gen = frames
elif iterable(frames):
self._iter_gen = lambda: iter(frames)
self.save_count = len(frames)
else:
self._iter_gen = lambda: iter(list(range(frames)))
self.save_count = frames
I'm not sure why my data_gen is not a collections.Callable. If it were, then len(frames) would never happen.
Any suggestions for what I should do about this would be appreciated!
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 runtimeC) is the most fun ;)
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:and your animation should work.
As a side note, don't use
plot
as a variable name. A lot of people bulk importpyplot
into their name space (such as byipython --pylab
) which hasplot
->matplotlib.pyplot.plot
->plt.gca().plot
hence it makes makes it more likely your code will confuse someone.