【问题标题】:Redrawing Seaborn Figures for Animations为动画重绘 Seaborn 图形
【发布时间】:2017-09-15 10:00:30
【问题描述】:

一些seaborn 方法,例如JointPlot create new figures on each call。这使得无法创建像 matplotlib 这样的简单动画,其中对 plt.cla()plt.clf() 的迭代调用允许更新图形的内容,而无需每次都关闭/打开窗口。

我目前看到的唯一解决方案是:

for t in range(iterations):
    # .. update your data ..

    if 'jp' in locals():
        plt.close(jp.fig)

    jp = sns.jointplot(x=data[0], y=data[1])
    plt.pause(0.01)

这是因为我们在创建新窗口之前关闭了前一个窗口。但当然,这远非理想。

有没有更好的方法?可以以某种方式直接在先前生成的Figure 对象上完成绘图吗?或者有没有办法阻止这些方法在每次调用时生成新的数字?

【问题讨论】:

    标签: python matplotlib seaborn


    【解决方案1】:

    不幸的是,sns.jointplot 自己创建了一个图形。为了使联合图动画化,因此可以重用这个创建的图形,而不是在每次交互中重新创建一个新图形。

    jointplot 在内部创建一个JointGrid,因此直接使用它并分别绘制关节轴和边缘是有意义的。然后在动画的每一步中更新数据,清除轴并设置它们,就像在创建网格时一样。不幸的是,这最后一步涉及很多代码行。

    最终的代码可能如下所示:

    import matplotlib.pyplot as plt
    import matplotlib.animation
    import seaborn as sns
    import numpy as np
    
    def get_data(i=0):
        x,y = np.random.normal(loc=i,scale=3,size=(2, 260))
        return x,y
    
    x,y = get_data()
    g = sns.JointGrid(x=x, y=y, size=4)
    lim = (-10,10)
    
    def prep_axes(g, xlim, ylim):
        g.ax_joint.clear()
        g.ax_joint.set_xlim(xlim)
        g.ax_joint.set_ylim(ylim)
        g.ax_marg_x.clear()
        g.ax_marg_x.set_xlim(xlim)
        g.ax_marg_y.clear()
        g.ax_marg_y.set_ylim(ylim)
        plt.setp(g.ax_marg_x.get_xticklabels(), visible=False)
        plt.setp(g.ax_marg_y.get_yticklabels(), visible=False)
        plt.setp(g.ax_marg_x.yaxis.get_majorticklines(), visible=False)
        plt.setp(g.ax_marg_x.yaxis.get_minorticklines(), visible=False)
        plt.setp(g.ax_marg_y.xaxis.get_majorticklines(), visible=False)
        plt.setp(g.ax_marg_y.xaxis.get_minorticklines(), visible=False)
        plt.setp(g.ax_marg_x.get_yticklabels(), visible=False)
        plt.setp(g.ax_marg_y.get_xticklabels(), visible=False)
    
    
    def animate(i):
        g.x, g.y = get_data(i)
        prep_axes(g, lim, lim)
        g.plot_joint(sns.kdeplot, cmap="Purples_d")
        g.plot_marginals(sns.kdeplot, color="m", shade=True)
    
    frames=np.sin(np.linspace(0,2*np.pi,17))*5
    ani = matplotlib.animation.FuncAnimation(g.fig, animate, frames=frames, repeat=True)
    
    plt.show()
    

    【讨论】:

    • 我在怀疑这样的事情。我希望它会更直接,但这可以很好地完成工作,所以非常感谢。
    • 从 seaborn 的源代码中你会看到它显然没有考虑到动画情节的可能性。根据最终目标是什么,当然可以进行一些优化;我正在考虑将 JointGrid 子类化以使其更容易受到更新,将其放入新模块并在需要时调用它 - 但是只有在需要更频繁地执行此类动画时才有意义。还要记住,seaborn 主要包装了 matplotlib,因此一个解决方案可能是复制jointplot 纯粹使用 matplotlib 所做的事情。
    • 能否请您也说明一下如何在lmplot的情况下,我无法重绘
    • @PaariVendhan 这个问题问的是JointGrid,但基本上这个概念对于其他seaborn *Grids 也是一样的。您需要单独更新网格的轴。
    【解决方案2】:

    使用 celluloid 包 (https://github.com/jwkvam/celluloid) 我能够轻松地为 seaborn 地块制作动画:

    import numpy as np
    from celluloid import Camera
    import pandas as pd
    import seaborn as sns
    import matplotlib.pyplot as plt
    
    fig = plt.figure()
    camera = Camera(fig)
    
    # animation draws one data point at a time
    for i in range(0, data.shape[0]):
        plot = sns.scatterplot(x=data.x[:i], y=data.y[:i])
        camera.snap()
    
    anim = camera.animate(blit=False)
    anim.save('animation.mp4')
    

    我确信可以为关节图编写类似的代码

    【讨论】:

    • 事实证明,与他们的示例相反,保存功能在赛璐珞中不起作用,因为它使用枕头保存,不支持视频格式。这段代码对我来说失败了。
    • 我认为你需要安装 ffmpeg。
    • 嘿亚当。我发现指定作家是有效的。例如:anim.save('/home/blws1/Desktop/animated_gif.gif', writer='imagemagick')。在我的情况下,动画 gif 很好。我尝试使用 ffmpeg 作为指定的编写器,但无法使其适用于 mp4。
    • 你确定 FFmpeg 是正确的安装程序吗?在 Mac 上,我必须使用自制软件安装 FFmpeg,然后上面的代码运行良好
    • 请注意,每次都创建一个新图形的 seaborn 图形级界面不适用于此。一种解决方法,例如histplot 是预先制作坐标轴,然后将相同的坐标轴传递给 seaborn 函数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-28
    • 2017-09-25
    • 1970-01-01
    • 2019-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多