在IPython Notebook中Matplotlib动画无法工作(空白图)

26

我尝试了多个动画示例代码,但无法使它们正常工作。这是我从Matplotlib文档中尝试的一个基本示例:

"""
A simple example of an animated plot
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

fig, ax = plt.subplots()

x = np.arange(0, 2*np.pi, 0.01)        # x-array
line, = ax.plot(x, np.sin(x))

def animate(i):
    line.set_ydata(np.sin(x+i/10.0))  # update the data
    return line,

#Init only required for blitting to give a clean slate.
def init():
    line.set_ydata(np.ma.array(x, mask=True))
    return line,

ani = animation.FuncAnimation(fig, animate, np.arange(1, 200), init_func=init,
    interval=25, blit=True)
plt.show()
当我在IPython笔记本上执行上述代码时,只会看到生成的一个空白图。我已经尝试从多个服务器(包括Wakari)上运行此代码,在多台机器上使用多个浏览器(Chrome、Firefox、IE)都是如此。我可以很好地将动画保存为mp4文件,并在播放时看起来很棒。任何帮助都将不胜感激!

1
不使用内联图形运行它。 - tacaswell
5个回答

47
总结一下你有以下选项:
  • Using display in a loop Use IPython.display.display(fig) to display a figure in the output. Using a loop you would want to clear the output before a new figure is shown. Note that this technique gives in general not so smooth resluts. I would hence advice to use any of the below.

    import matplotlib.pyplot as plt
    import matplotlib.animation
    import numpy as np
    from IPython.display import display, clear_output
    
    t = np.linspace(0,2*np.pi)
    x = np.sin(t)
    
    fig, ax = plt.subplots()
    l, = ax.plot([0,2*np.pi],[-1,1])
    
    animate = lambda i: l.set_data(t[:i], x[:i])
    
    for i in range(len(x)):
    animate(i)
    clear_output(wait=True)
    display(fig)
    
    plt.show()

  • %matplotlib notebook Use IPython magic %matplotlib notebook to set the backend to the notebook backend. This will keep the figure alive instead of displaying a static png file and can hence also show animations.
    Complete example:

    %matplotlib notebook
    import matplotlib.pyplot as plt
    import matplotlib.animation
    import numpy as np
    
    t = np.linspace(0,2*np.pi)
    x = np.sin(t)
    
    fig, ax = plt.subplots()
    l, = ax.plot([0,2*np.pi],[-1,1])
    
    animate = lambda i: l.set_data(t[:i], x[:i])
    
    ani = matplotlib.animation.FuncAnimation(fig, animate, frames=len(t))
    
    plt.show()

  • %matplotlib tk Use IPython magic %matplotlib tk to set the backend to the tk backend. This will open the figure in a new plotting window, which is interactive and can thus also show animations.
    Complete example:

    %matplotlib tk
    import matplotlib.pyplot as plt
    import matplotlib.animation
    import numpy as np
    
    t = np.linspace(0,2*np.pi)
    x = np.sin(t)
    
    fig, ax = plt.subplots()
    l, = ax.plot([0,2*np.pi],[-1,1])
    
    animate = lambda i: l.set_data(t[:i], x[:i])
    
    ani = matplotlib.animation.FuncAnimation(fig, animate, frames=len(t))
    
    plt.show()

  • Convert animation to mp4 video:

    from IPython.display import HTML
    HTML(ani.to_html5_video())
    

    or use plt.rcParams["animation.html"] = "html5" at the beginning of the notebook. This will require to have ffmpeg video codecs available to convert to HTML5 video. The video is then shown inline. This is therefore compatible with %matplotlib inline backend. Complete example:

    %matplotlib inline
    import matplotlib.pyplot as plt
    plt.rcParams["animation.html"] = "html5"
    import matplotlib.animation
    import numpy as np
    
    t = np.linspace(0,2*np.pi)
    x = np.sin(t)
    
    fig, ax = plt.subplots()
    l, = ax.plot([0,2*np.pi],[-1,1])
    
    animate = lambda i: l.set_data(t[:i], x[:i])
    
    ani = matplotlib.animation.FuncAnimation(fig, animate, frames=len(t))
    ani
    %matplotlib inline
    import matplotlib.pyplot as plt
    import matplotlib.animation
    import numpy as np
    
    t = np.linspace(0,2*np.pi)
    x = np.sin(t)
    
    fig, ax = plt.subplots()
    l, = ax.plot([0,2*np.pi],[-1,1])
    
    animate = lambda i: l.set_data(t[:i], x[:i])
    
    ani = matplotlib.animation.FuncAnimation(fig, animate, frames=len(t))
    
    from IPython.display import HTML
    HTML(ani.to_html5_video())

  • Convert animation to JavaScript:

    from IPython.display import HTML
    HTML(ani.to_jshtml())
    

    or use plt.rcParams["animation.html"] = "jshtml" at the beginning of the notebook. This will display the animation as HTML with JavaScript. This highly compatible with most new browsers and also with the %matplotlib inline backend. It is available in matplotlib 2.1 or higher.
    Complete example:

    %matplotlib inline
    import matplotlib.pyplot as plt
    plt.rcParams["animation.html"] = "jshtml"
    import matplotlib.animation
    import numpy as np
    
    t = np.linspace(0,2*np.pi)
    x = np.sin(t)
    
    fig, ax = plt.subplots()
    l, = ax.plot([0,2*np.pi],[-1,1])
    
    animate = lambda i: l.set_data(t[:i], x[:i])
    
    ani = matplotlib.animation.FuncAnimation(fig, animate, frames=len(t))
    ani
    %matplotlib inline
    import matplotlib.pyplot as plt
    import matplotlib.animation
    import numpy as np
    
    t = np.linspace(0,2*np.pi)
    x = np.sin(t)
    
    fig, ax = plt.subplots()
    l, = ax.plot([0,2*np.pi],[-1,1])
    
    animate = lambda i: l.set_data(t[:i], x[:i])
    
    ani = matplotlib.animation.FuncAnimation(fig, animate, frames=len(t))
    
    from IPython.display import HTML
    HTML(ani.to_jshtml())


谢谢您总结了所有内容。这正是我在寻找的!两个评论:(a) 从matplotlib 2.1.0开始,我猜应该使用ani.to_html5_video()而不是ani.to_html5(); (b) @Perfi是谁?我在这个页面上看不到他发表的回答或评论。 - Antony Hatchkins
有点神秘的事情是:我在处理这个选项时遇到了麻烦,直到我意识到 %matplotlib inline%matplotlib notebook 之间存在冲突。我需要删除 %matplotlib inline 并按照这里描述的两次运行 %matplotlib notebook:https://github.com/ipython/ipython/issues/10873 - atkat12
1
@atkat12 如果你想在一半时更改后端,这似乎是我也在这里找到的解决方案。 - ImportanceOfBeingErnest
在Google Colab中,在循环中使用display是可行的(但会闪烁得很厉害)。如果你用ani替换plt.show(),那么#matplotlib notebook也可以工作(输出视频而不是在循环期间更新)。%matplotlib tk不起作用(不支持)。mp4也会输出一个视频。jshtml会输出带有播放控件的视频。 - Alec Jacobson
使用%matplotlib widget对我有效。但是notebook没有起作用。 - undefined

12
根据这个答案,你可以通过启用`nbagg`后端并输入命令`%matplotlib nbagg`在IPython笔记本中实现动画(以及完整的交互支持)。

5
我之前和你一样遇到了完全相同的问题。由于我是一个完全的新手,所以tcaswell的答案对我来说有点晦涩难懂。也许你已经理解了他的意思或者找到了自己的解决方案。如果你还没有找到解决方法,我会在这里提供一个。我谷歌了“matplotlib inline figures”并找到了this这个网站,它提到你需要启用matplotlib模式。不幸的是,仅使用%maplotlib并没有任何帮助。然后我在IPython控制台上随便输入了%matplotlib qt,现在它就可以正常工作了,尽管绘图出现在一个单独的窗口中。

这对我有用。是的,在一个单独的窗口中。我希望有一个直接保存动漫为视频文件的选项,而不是PNG。 - Bhanu Chander

2
我也遇到了这个问题,发现需要理解matplotlib后端的概念,如何启用特定的后端以及哪些后端适用于FuncAnimation。我编写了一个 ipython笔记本来解释细节,并汇总了哪些后端适用于Mac、Windows和wakari.io 上的 FuncAnimation。该笔记本还总结了哪些后端适用于ipython interact()小部件,以及基本matplotlib绘图的情况下绘图出现的位置(内联或次级窗口)。代码和说明包括在内,所以您可以重现任何结果。
底线是,无法使使用FuncAnimation创建的动画内联显示在ipython笔记本中。但是,您可以在单独的窗口中将其显示出来。事实证明,我需要为我本学期教授的本科课程创建可视化效果,虽然我更希望动画能够内联显示,但至少我能够创建一些有用的可视化效果,在课堂上展示。

0

当动画结束时,在Jupyter中没有内联视频也会发生这种情况。

HTML(ani.to_html5_video())

如果不在笔记本单元格的最末尾,输出将被抑制。

您可以按以下方式使用它

out = HTML(ani.to_html5_video())

只需在新单元格中键入 out` 即可在线获取视频。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接