【问题标题】:Animation stops working when upgrading to matplotlib 3.3.2升级到 matplotlib 3.3.2 时动画停止工作
【发布时间】:2020-10-27 19:42:15
【问题描述】:

我有一段用于动画可视化的 Python 代码最近停止工作。我已将问题跟踪到从matplotlib 3.2.2 升级到 3.3.2。我比较了matplotlib 3.2.2 和 3.3.2 的文档,主要变化是示例中的 HMTLAnimationWriter 和勘误表。我认为我的代码没有理由停止工作。

我提出了bug report at matplotlib

A) 预期行为

文章末尾的代码在 y 方向上上下移动了一条线。它在matplotlib 3.2.2 上成功地做到了这一点,但在 3.3.2 上却没有。这可以在不同的设置中重现。

B) 问题

当我使用matplotlib 3.3.2 时,会打开一个空图。

当我使用matplotlib 3.2.2 从命令行(例如python test.py)运行代码时,我没有收到Depreciation Warning 或任何其他错误消息。与matplotlib 3.3.2 类似。这已经过测试

  • C1:配备 Asrock Z3​​70 P4、Nvidia 1050 Ti、i5-8600K 的台式机。
    测试:

    • Python:3.8.3,matplotlib:3.2.2 正常
    • Python:3.8.3,matplotlib:3.3.2(有问题
  • C2:Acer Spin 5 SP513-52N 笔记本电脑。
    测试:

    • Python:3.8.3,matplotlib:3.2.2 正常
    • Python:3.8.3,matplotlib:3.3.2(有问题
  • 根据用户评论:
    测试:

    • Win 10,Python:3.8.3,matplotlib:3.3.2(有问题
    • Ubuntu 20.04,Python:3.8.3,matplotlib:3.1.2 正常
    • Ubuntu 20.04,Python:3.8.3,更新到 matplotlib:3.3.2(有问题

在我的两种情况下,当我升级时问题出现了,当我降级时问题消失了。所以,我的猜测是问题出在matplotlib 3.3.2。

有趣的一点是,如果我使用 Pillowriter 创建动画 gif,生成的 gif 在 matplotlib 的所有版本中都会按预期执行。

问题

  1. 这是 API 的错误还是功能?
  2. 如果它是一项功能,那么推荐的新动画方法是什么(最好具有向后兼容性)。看起来,并不是所有的FuncAnimation() 命令都会受到影响。 This works with matplotlib 3.3.2.
  3. 如果是错误,是否有解决方法?

代码

我包含一个 MCVE 代码,它重现了主要问题并适用于 matplotlib 3.2.2,但不适用于 3.3.2。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation

def create_animated_plot(xs, niter, xlim =(-1.5, 1.5), ylim = [-3, 3]):

    line_coords = np.vstack((  np.array([-1,1]), np.array([0,0]) ))
    
    boxData = [np.array([np.zeros(niter), xs])]

    fig, ax1 = plt.subplots(1,1)
    line, = ax1.plot([], [], lw=2)
    ax1.set_ylabel('position')
    ax1.set_ylim(ylim)
    ax1.set_xlim(xlim)

    lines = [ax1.plot([],[],lw=2,color="black")[0]]

    def init():
        lines[0].set_data([],[])
        return lines

    def animate(i):
        xs = [boxData[0][0, i]]
        ys = [boxData[0][1, i]]

        lines[0].set_data(line_coords[0,:]+xs[0], line_coords[1,:]+ys[0]) 
        return lines

    anim = animation.FuncAnimation(fig, animate, init_func=init,
                                frames=niter, interval=10, blit=True)


niter = 1001
t = np.linspace(0,10,niter)

create_animated_plot(xs =np.sin(t), niter=niter)
plt.show()


附加信息

以下是我原始代码中的图像(我在这篇文章中将其简化为 MCVE 代码):

  • 原始代码工作示例的动画 gif:此图中有两个动画(顶部子图:盒子上下移动,底部:红线在图上移动)。

  • 使用 matplotlib 3.3.2 的输出的 png:两个动画都不会表现出预期的行为。顶部甚至不会绘制盒子。在底部的子图中,第一帧将绘制红线,但随后它不会移动。

请注意,此处发布的 MCVE 代码只是创建了两个图表的上框,并显示了一条带有matplotlib ≤3.2.2 的弹跳线,但一个带有matplotlib 3.3.2 的空框。

【问题讨论】:

标签: python matplotlib animation


【解决方案1】:

问题在于 gc 现在更积极地收集对动画对象的引用。这与bug有关

一个简单的解决方法是传递如下引用:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation

def create_animated_plot(xs, niter, xlim =(-1.5, 1.5), ylim = [-3, 3]):

    line_coords = np.vstack((  np.array([-1,1]), np.array([0,0]) ))
    
    boxData = [np.array([np.zeros(niter), xs])]

    fig, ax1 = plt.subplots(1,1)
    line, = ax1.plot([], [], lw=2)
    ax1.set_ylabel('position')
    ax1.set_ylim(ylim)
    ax1.set_xlim(xlim)

    lines = [ax1.plot([],[],lw=2,color="black")[0]]

    def init():
        lines[0].set_data([],[])
        return lines

    def animate(i):
        xs = [boxData[0][0, i]]
        ys = [boxData[0][1, i]]

        lines[0].set_data(line_coords[0,:]+xs[0], line_coords[1,:]+ys[0]) 
        return lines

    anim = animation.FuncAnimation(fig, animate, init_func=init,
                                frames=niter, interval=10, blit=True)
    return anim  # return anim object reference ########################################################

niter = 1001
t = np.linspace(0,10,niter)

anim = create_animated_plot(xs =np.sin(t), niter=niter)   # assign to variable ###########################
plt.show()

如果你有一个类,你也可以将动画对象分配给 self。

注意:如果没有Mr. T

的帮助和耐心,我无法得出这个答案

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-11
    • 1970-01-01
    • 1970-01-01
    • 2018-10-26
    • 1970-01-01
    • 1970-01-01
    • 2016-03-16
    • 2018-09-05
    相关资源
    最近更新 更多