【问题标题】:Animated title in matplotlibmatplotlib 中的动画标题
【发布时间】:2013-07-09 21:00:53
【问题描述】:

我不知道如何在 FuncAnimation 情节(使用 blit)上制作动画标题。基于http://jakevdp.github.io/blog/2012/08/18/matplotlib-animation-tutorial/Python/Matplotlib - Quickly Updating Text on Axes,我构建了一个动画,但文本部分不会动画。简化示例:

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

vls = np.linspace(0,2*2*np.pi,100)

fig=plt.figure()
img, = plt.plot(np.sin(vls))
ax = plt.axes()
ax.set_xlim([0,2*2*np.pi])
#ttl = ax.set_title('',animated=True)
ttl = ax.text(.5, 1.005, '', transform = ax.transAxes)

def init():
    ttl.set_text('')
    img.set_data([0],[0])
    return img, ttl
def func(n):
    ttl.set_text(str(n))
    img.set_data(vls,np.sin(vls+.02*n*2*np.pi))
    return img, ttl

ani = animation.FuncAnimation(fig,func,init_func=init,frames=50,interval=30,blit=True)

plt.show()

如果blit=True 被删除,文本会显示出来,但速度会变慢。 plt.titleax.set_titleax.text 似乎失败了。

编辑:我发现了为什么第一个链接中的第二个示例有效;文本位于img 部分内。如果你把上面的1.005 变成.99,你就会明白我的意思了。可能有一种方法可以通过边界框来做到这一点,不知何故......

【问题讨论】:

    标签: python animation matplotlib


    【解决方案1】:

    Animating matplotlib axes/tickspython matplotlib blit to axes or sides of the figure?

    所以,问题在于,在实际保存 blit 背景的animation 的内部(animation.py 的第 792 行),它抓取了 axes 边界框中的内容。当您有多个轴独立动画时,这是有道理的。在您的情况下,您只有一个 axes 需要担心,我们希望在轴边界框外部设置动画。通过一些猴子修补程序,对进入 mpl 内部并四处摸索的容忍度,并接受最快和最肮脏的解决方案,我们可以这样解决您的问题:

    import matplotlib
    import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    import numpy as np
    
    def _blit_draw(self, artists, bg_cache):
        # Handles blitted drawing, which renders only the artists given instead
        # of the entire figure.
        updated_ax = []
        for a in artists:
            # If we haven't cached the background for this axes object, do
            # so now. This might not always be reliable, but it's an attempt
            # to automate the process.
            if a.axes not in bg_cache:
                # bg_cache[a.axes] = a.figure.canvas.copy_from_bbox(a.axes.bbox)
                # change here
                bg_cache[a.axes] = a.figure.canvas.copy_from_bbox(a.axes.figure.bbox)
            a.axes.draw_artist(a)
            updated_ax.append(a.axes)
    
        # After rendering all the needed artists, blit each axes individually.
        for ax in set(updated_ax):
            # and here
            # ax.figure.canvas.blit(ax.bbox)
            ax.figure.canvas.blit(ax.figure.bbox)
    
    # MONKEY PATCH!!
    matplotlib.animation.Animation._blit_draw = _blit_draw
    
    vls = np.linspace(0,2*2*np.pi,100)
    
    fig=plt.figure()
    img, = plt.plot(np.sin(vls))
    ax = plt.axes()
    ax.set_xlim([0,2*2*np.pi])
    #ttl = ax.set_title('',animated=True)
    ttl = ax.text(.5, 1.05, '', transform = ax.transAxes, va='center')
    
    def init():
        ttl.set_text('')
        img.set_data([0],[0])
        return img, ttl
    
    def func(n):
        ttl.set_text(str(n))
        img.set_data(vls,np.sin(vls+.02*n*2*np.pi))
        return img, ttl
    
    ani = animation.FuncAnimation(fig,func,init_func=init,frames=50,interval=30,blit=True)
    
    plt.show()
    

    请注意,如果您的图中有多个轴,这可能无法按预期工作。一个更好的解决方案是扩展axes.bbox just 足以捕获您的标题+轴刻度标签。我怀疑 mpl 中的某个地方有代码可以做到这一点,但我不知道它在哪里。

    【讨论】:

    • 这可以全速运行!希望它被包含在 matplotlib 中,与猴子修补相比,但效果很好!
    • @HenrySchreiner 您的编辑应该已被接受。 (我刚刚重做了)。如果这解决了您的问题,您能否接受答案(左侧的大灰色复选框)。
    • 理想情况下,应该使用文本边界框(因为它是从动画函数传递的),但由于某种原因它没有被使用(尽管我认为它在艺术家中)。这是目前修复它的合理方法。 :) 谢谢!
    • @HenrySchreiner 动画代码仍然有点粗糙。有充分的理由不这样做主要代码(请参阅我的警告)。如果您想在主线中改进这一点,请执行此操作。他们在 mpl 上的开发人员非常友好。
    • 如果我在FuncAnimation 调用中使用repeat=False,然后等到动画结束并放大某处,绘图就会消失。
    【解决方案2】:

    要添加到 tcaswell 的“猴子补丁”解决方案中,您可以通过以下方式将动画添加到轴刻度标签。具体来说,要为 x 轴设置动画,请设置 ax.xaxis.set_animated(True) 并从动画函数返回 ax.xaxis

    import matplotlib
    import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    import numpy as np
    
    def _blit_draw(self, artists, bg_cache):
        # Handles blitted drawing, which renders only the artists given instead
        # of the entire figure.
        updated_ax = []
        for a in artists:
            # If we haven't cached the background for this axes object, do
            # so now. This might not always be reliable, but it's an attempt
            # to automate the process.
            if a.axes not in bg_cache:
                # bg_cache[a.axes] = a.figure.canvas.copy_from_bbox(a.axes.bbox)
                # change here
                bg_cache[a.axes] = a.figure.canvas.copy_from_bbox(a.axes.figure.bbox)
            a.axes.draw_artist(a)
            updated_ax.append(a.axes)
    
        # After rendering all the needed artists, blit each axes individually.
        for ax in set(updated_ax):
            # and here
            # ax.figure.canvas.blit(ax.bbox)
            ax.figure.canvas.blit(ax.figure.bbox)
    
    # MONKEY PATCH!!
    matplotlib.animation.Animation._blit_draw = _blit_draw
    
    vls = np.linspace(0,2*2*np.pi,100)
    
    fig=plt.figure()
    img, = plt.plot(np.sin(vls))
    ax = plt.axes()
    ax.set_xlim([0,2*2*np.pi])
    #ttl = ax.set_title('',animated=True)
    ttl = ax.text(.5, 1.05, '', transform = ax.transAxes, va='center')
    
    ax.xaxis.set_animated(True)
    
    def init():
        ttl.set_text('')
        img.set_data([0],[0])
        return img, ttl, ax.xaxis
    
    def func(n):
        ttl.set_text(str(n))
        vls = np.linspace(0.2*n,0.2*n+2*2*np.pi,100)
        img.set_data(vls,np.sin(vls))
        ax.set_xlim(vls[0],vls[-1])
        return img, ttl, ax.xaxis
    
    ani = animation.FuncAnimation(fig,func,init_func=init,frames=60,interval=200,blit=True)
    
    plt.show()
    

    【讨论】:

      【解决方案3】:

      你必须打电话

      plt.draw()
      

      之后

      ttl.set_text(str(n))
      

      这里有一个“没有 FuncAnimation()”的图形中的文本动画的非常简单的示例。试试吧,你会发现它是否对你有用。

      import matplotlib.pyplot as plt
      import numpy as np
      titles = np.arange(100)
      plt.ion()
      fig = plt.figure()
      for text in titles:
          plt.clf()
          fig.text(0.5,0.5,str(text))
          plt.draw()
      

      【讨论】:

      • 确实会画出它,但它会减慢它的速度,与blit=False 的速度相同。我希望只是重绘文本。
      • 为什么不简单地避免动画并使用 plt.ion() 制作自己的动画?有了它,你有很多控制权,而且你确定每一帧都在做什么……看看stackoverflow.com/questions/17444655/…
      • fig=plt.figure() img, = plt.plot(np.sin(vls)) ax = plt.axes() ax.set_xlim([0,2*2*np.pi ]) title = ax.text(.5, 1.005, '', transform = ax.transAxes) plt.ion() for i in range(100): img.set_data(vls,np.sin(vls+.02*( i%50)*2*np.pi)) title.set_text(str(i%50)) plt.draw()
      • 我测试过,还是很慢,不过我可以手动调用canvas.blit。我认为动画是一种更新/首选的方法(超过手动构建)。
      • 问题是“我如何在轴外的艺术家身上制作 blit 作品”
      猜你喜欢
      • 1970-01-01
      • 2017-01-31
      • 1970-01-01
      • 2018-05-05
      • 2015-08-16
      • 2021-02-01
      • 1970-01-01
      • 2011-06-26
      • 2014-06-07
      相关资源
      最近更新 更多