iPython笔记本中的动画功能

34

我正在尝试在iPython笔记本中添加动画,但是没有找到解决方案。我看到一个帖子讨论使用交互式小部件,但我对此有几个问题:

首先,我看到的所有小部件示例都使用滑块或其他输入方式,而我只希望在运行单元格时自动播放动画。其次,Jupyter网站上的所有文档似乎都已过时--每当我下载和运行它们的笔记本时,都会收到关于某些模块被弃用的消息,然后在文件的后面会出现一些失败运行的情况,这可能是因为它们正试图导入和访问不存在的文件。

我看到了一些关于此主题的其他页面,但它们通常需要下载二进制文件或其他模块,但我部分使用Anaconda来教授一些学生数学,希望不要通过让他们下载和安装更复杂的东西来 further confuse the issue并且还花费时间不谈论数学。

因此,简而言之,是否有一种方法可以在iPython笔记本中创建动画,而仅需要使用可直接与Anaconda提供的软件配合使用的简单导入命令?

[编辑:我还应该注意到,我已经使用Tkinter制作了动画,并且我肯定可以在matplotlib中制作一个动画。因此,如果有一种方法可以在iPython笔记本中呈现您使用这些工具生成的动画,那对我来说肯定是一种有效的解决方案。]

[进一步编辑:我想我还可以说一下我希望此刻进行动画的内容,尽管我真的希望能够相当灵活地演示我可以进行动画的范围。现在,我正在尝试制作一个数字钟,其中以苏美尔60进制数字为基础来显示每个数字,以说明不同的计数和基数系统。因此,它应该最初显示|,然后在一秒钟后显示||,依此类推,直到十被表示为<,等等,直到最终时钟跳过一分钟,现在它显示|:|来代表一分钟,一秒钟。]

[致未来的读者:如果您正在实现动画并愿意公开托管它,请在评论中留下链接!我很想看看人们如何制作动画,也有点好奇他们在制作什么动画。]


JSAnimation,但需要额外安装。您可以使用IPython.display.clear_output替换诸如绘图之类的输出,但它不足以平滑地实现动画效果。 - Thomas K
JSAnimation现在不需要额外的安装了。自从2.1版本以来,它已经合并到matplotlib中。使用方法在@ImportanceOfBeingErnest的最后一个片段中展示。 - Harsh
4个回答

56

以下是在Jupyter/IPython中使用matplotlib制作动画图表的一些选项:

  • 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 (option mentionned by @Perfi already):

    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())


{btsdaf} - Addem
1
{btsdaf} - ImportanceOfBeingErnest
在matplotlib中将动画转换为JavaScript是一件好事,特别是对于匆忙之人来说,它消除了安装ffmpeg编解码器的麻烦。 @ImportanceOfBeingErnest 在答案中使用代码片段非常好。我想知道将代码作为CSS放在答案中是故意的还是HTML/JS等都是这样?我必须承认,我花了几分钟时间感到困惑,只是点击“运行代码片段”,期望看到一些Python输出。 - Harsh
@Harsh 对于混淆我感到抱歉。我误用了这个CSS/JavaScript功能来隐藏代码,以免答案变得混乱。这使得答案中的所有选项都能清晰地显示出来,同时也为需要它的任何人提供了一个完整的示例(我总是喜欢提供MCVEs以使某些命令不含糊)。不幸的是,这个“隐藏代码”功能在其他语言如Python中不可用。 - ImportanceOfBeingErnest
1
上述第一种(较慢)方法非常适用于在线动画,即当您逐帧生成数据框时,而不是事先拥有所有数据时。 - Novak
对于未来的读者:这些解决方案都没有按预期工作。其中一些显示空白“窗口”,其他则显示两个“窗口”。 - Antonio Sesto

11

你可能会对这个教程感兴趣。

如果你能将所需内容转化为 matplotlib 动画,而我相当确定从你的描述中可以做到,那么你就可以使用

from matplotlib import rc, animation
rc('animation', html='html5')

并使用以下方式显示您的动画

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

可能会有用!


4
为什么这段代码会显示两个“窗口”,一个是空白的,另一个有视频? - Antonio Sesto

3

Jupyter小部件是显示动画的好方法。下面的代码显示了一个动态的gif.....

from ipywidgets import Image
from IPython import display
animatedGif = "animatedGifs/01-progress.gif" #path relative to your notebook
file = open(animatedGif , "rb")
image = file.read()
progress= Image(
    value=image,
    format='gif',
    width=100,
    height=100)
display.display(progress)

您可以使用以下方式关闭此动画:
progress.close()

注意:我从http://www.downgraf.com/inspiration/25-beautiful-loading-bar-design-examples-gif-animated/找到了一些漂亮的动态gif图。


2
我遇到了类似的问题,这个问题帮助我入门了。我编写了一个笔记本,演示了如何使用FuncAnimation,以及为什么要以这种方式执行某些操作的良好解释。它还链接了FFmpeg的说明。它还链接到我在开发和理解动画方面使用的示例。您可以在以下网址查看我的贡献: 动画演示 对于您的问题,您可能会发现交互式滑块是更好的工具。我还创建了一个演示Jupyter中交互式小部件的笔记本。它在此处可用: 这里; 但是,交互式部分在此处不起作用。
两者都在GitHub存储库中可用。

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