【问题标题】:FuncAnimation cannot blit away the first frame imshow content when blit=True?当 blit=True 时,FuncAnimation 无法删除第一帧 imshow 内容?
【发布时间】:2020-04-24 00:17:10
【问题描述】:

当在FuncAnimation 中使用imshow 艺术家时,第一帧不能被删除。它将始终保持第一帧不变,但其他艺术家的行为正确。我们怎样才能解决这个问题? 代码如下:

from matplotlib import pyplot as plt, animation, cm
def show_imshow_blit_bug(start=0, blit=True):
    pic = np.zeros((10, 10), dtype=float)
    x = np.arange(0, 2 * np.pi, 0.01)
    amp = (x.max() - x.min()) / 2

    fig, ax = plt.subplots()
    extent = [x.min(), x.max(), -amp, amp]
    _cm = cm.jet
    picf = pic.flat
    picf[0] = 1
    picf[-1] = 0.5
    imart = ax.imshow(pic,
                      origin='lower',
                      extent=extent,
                      cmap=_cm
                      )
    # imart.set_animated(True) # set or not has no effect
    line, = ax.plot(x, np.sin(x)*amp)
    line2, = ax.plot(x[[0, -1]], np.array([-amp, amp]), 'r')
    line2.set_animated(True) # this make line2 disappear, since updater does not return this artist
    line3, = ax.plot(x[[0, -1]], np.array([amp, -amp]), 'C1')
    #line3 will be keeped since _animated = False
    ax.set_xlim(x.min(), x.max())
    ax.set_ylim(-amp * 1.1, amp * 1.1)
    fig.tight_layout()

    def updater(fn):
        print(fn)
        np.random.shuffle(picf)
        imart.set_data(np.ma.masked_where(pic == 0, pic))
        line.set_ydata(np.sin(x + fn / 10.0)*amp)
        return (imart, line,) # Both artist will be in blit list

    nframe = range(start, 200)
    anima = animation.FuncAnimation(fig,
                            updater,
                            nframe,
                            interval=20,
                            blit=blit,
                            repeat=False
                            )
    plt.show()

我知道有一个hack solution 可以将init_func 中的艺术家设置为不可见。但这是一个 hack,我不想使用与其余代码不兼容的 init_func

【问题讨论】:

    标签: python matplotlib animation


    【解决方案1】:

    FuncAnimation documentation 状态

    init_func:可调用,可选

    用于绘制清晰框架的函数。 如果没有给出,将使用从帧序列中第一项绘制的结果。该函数将在第一帧之前调用一次。)

    因此,使用init_func 并不是一种黑客行为,也不是不受欢迎的——它实际上是预期的用途。

    你会启动一个空图像

    imart = ax.imshow([[]], ...)
    

    有一个初始化函数

    def init():
        return imart,line,
    

    还有一个更新函数

    def updater(fn):
        np.random.shuffle(picf)
        imart.set_data(np.ma.masked_where(pic == 0, pic))
        line.set_ydata(np.sin(x + fn / 10.0)*amp)
        return (imart, line,)
    

    并实例化FuncAnimation

    anima = animation.FuncAnimation(fig,
                            updater,
                            nframe,
                            init_func=init,
                            interval=20,
                            blit=blit,
                            repeat=False
                            )
    

    【讨论】:

    • 这是一个黑客。因为您创建了一个空的imart。如果没有init_func_init_draw 只会调用 updater(0)。如果您查看代码,_init_draw 所做的只是将init_func 返回的所有艺术家注册为set_animated(True)。理论上,它不应该在那里留下任何框架。正如我所说,这只在 imshow 上失败了。其他艺术家不需要空的初始艺术家。
    • 不知道问题在问什么。如果您觉得这是一个错误,SO 不是报告它的正确地方,请转到matplotlib issue tracker。但是,如果您考虑一下图像可能有充分的理由没有将 _animated 属性转换为可见性,那么以上是一个明智的解决方案。或者,也许您只是在此处重申您想问的确切内容。
    猜你喜欢
    • 1970-01-01
    • 2018-06-20
    • 2013-11-19
    • 1970-01-01
    • 2021-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多