【问题标题】:matplotlib animation FuncAnimation frames argumentmatplotlib 动画 FuncAnimation 帧参数
【发布时间】:2014-01-08 17:58:09
【问题描述】:

我正在通过调用使用 matplotlib 动画:

plot = animation.FuncAnimation(fig, update, frames=data_gen(a), init_func=init, interval=10, blit=True)

这里,“a”是 data_gen 函数的初始值,如下所示:

data_gen(x)
    old_x = x
    while True:
        new_x = func(old_x)
        old_x = new_x
        yield new_x

此代码的目的是让 data_gen 在每次更新动画图时为 new_x 生成一个新值。

但是……这反而发生了:

animation.py 在 FuncAnimation 类的 init() 方法中引发错误。

问题发生在这段代码中:

elif iterable(frames):
    self._iter_gen = lambda: iter(frames)
    self.save_count = len(frames)

错误是“TypeError: 'generator' 类型的对象没有 len()”

看起来 data_gen 是可迭代的,但它没有 len()。

下面是 FuncAnimation 类中 init() 方法的更多代码:

    # 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

我不确定为什么我的 data_gen 不是 collections.Callable。如果是,那么 len(frames) 将永远不会发生。

任何关于我应该怎么做的建议都将不胜感激!

【问题讨论】:

  • 参见:错误:github.com/matplotlib/matplotlib/issues/1769 PR:github.com/matplotlib/matplotlib/pull/2634(感谢@tcaswell)

标签: python animation matplotlib iterable callable


【解决方案1】:

解决方案是 A) 预先生成所有数据并将其推送到列表中(如果您确实有有限数量的帧),即data_list = list(data_gen) B) 从我的分支的源代码安装以解决此问题:PR #2634 或 C) 猴子补丁 matplotlib,即只需将安装中的错误代码替换为运行时的固定代码

C) 是最好玩的 ;)

# 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 = []

我们现在有一个函数monkey_patch_init,它(我声称)是固定代码。我们现在只需用这个函数替换有缺陷的 __init__ 函数:

matplotlib.animation.FuncAnimation.__init__ = monkey_patch_init

你的动画应该可以工作了。

ani = animation.FuncAnimation(fig, update, frames=data_gen(a), init_func=init, interval=10, blit=True)

附带说明,不要使用plot 作为变量名。很多人将pyplot 批量导入到他们的名称空间中(例如ipython --pylab),其中包含plot -> matplotlib.pyplot.plot -> plt.gca().plot 因此它使您的代码更有可能使某人感到困惑。

【讨论】:

  • 谢谢@tcaswell。我做了更糟糕的事?!我刚刚注释掉了这一行: self.save_count = len(frames) (并且我停止使用 'plot' 作为变量名。)
  • 我的第一个猴子补丁。丑陋,但它对我有用。 :) 我还必须补充:进口六;从 matplotlib.cbook 导入可迭代;从 matplotlib.animation 导入 TimedAnimation
  • @gregallan 具有此修复程序的 mpl 稳定版本已发布一年多,您应该升级。
  • @tcaswell 这是完全更新的 RHEL7.1,它提供了 python-matplotlib-1.2.0-15.el7。我完全同意 RH 应该升级。同时,感谢您的解决方法!我想我不是 RHEL7 上唯一的人。
猜你喜欢
  • 2021-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多