【问题标题】:Matplotlib animate fill_between shapeMatplotlib 动画 fill_between 形状
【发布时间】:2020-11-06 23:53:10
【问题描述】:

我正在尝试为 matplotlib 中的 fill_between 形状设置动画,但我不知道如何更新 PolyCollection 的数据。举个简单的例子:我有两条线,我总是在它们之间填充。当然,线条会发生变化并具有动画效果。

这是一个虚拟示例:

import matplotlib.pyplot as plt

# Init plot:
f_dummy = plt.figure(num=None, figsize=(6, 6));
axes_dummy = f_dummy.add_subplot(111);

# Plotting:
line1, = axes_dummy.plot(X, line1_data, color = 'k', linestyle = '--', linewidth=2.0, animated=True);
line2, = axes_dummy.plot(X, line2_data, color = 'Grey', linestyle = '--', linewidth=2.0, animated=True);
fill_lines = axes_dummy.fill_between(X, line1_data, line2_data, color = '0.2', alpha = 0.5, animated=True);

f_dummy.show();
f_dummy.canvas.draw();
dummy_background = f_dummy.canvas.copy_from_bbox(axes_dummy.bbox);

# [...]    

# Update plot data:
def update_data():
   line1_data = # Do something with data
   line2_data = # Do something with data
   f_dummy.canvas.restore_region( dummy_background );
   line1.set_ydata(line1_data);
   line2.set_ydata(line2_data);

   # Update fill data too

   axes_dummy.draw_artist(line1);
   axes_dummy.draw_artist(line2);

   # Draw fill too

   f_dummy.canvas.blit( axes_dummy.bbox );

问题是如何在每次调用 update_data() 时根据 line1_data 和 line2_data 更新 fill_between Poly 数据并在 blit 之前绘制它们(“# Update fill data too” & “# Draw fill too”)。我尝试了 fill_lines.set_verts() 但没有成功,找不到示例...

谢谢!

【问题讨论】:

  • 您可能需要删除并完全重新绘制每一帧。 *collection 对象不适合更新。原因是他们已经丢弃了所有允许您在数据空间和绘图空间之间映射的元数据,并且只保留了要绘制的内容的列表。这是快速渲染它们的权衡。
  • 你的意思是在 update_data 中使用 f_dummy.canvas.draw() 吗?我从这个开始,但不幸的是我需要快速绘图,因为我正在实时处理和播放信号,并且我需要绘图不影响播放(调用 draw() 会停止播放)。如果您知道在播放声音时重绘所有内容的快速线程技巧,那就太好了 - 我用 threading.start(...) 调用了 draw。我知道还有其他更快的绘图库,但我更喜欢坚持使用 matplotlib,并且恢复/blit 技巧对我来说足够快。

标签: python animation matplotlib plot


【解决方案1】:

好的,正如有人指出的那样,我们在这里处理一个集合,所以我们必须删除并重绘。所以在update_data函数的某处,删除与之关联的所有集合:

axes_dummy.collections.clear()

并绘制新的“fill_between”PolyCollection:

axes_dummy.fill_between(x, y-sigma, y+sigma, facecolor='yellow', alpha=0.5)

需要类似的技巧来将未填充的等高线图覆盖在已填充的等高线图之上,因为未填充的等高线图也是一个集合(我想是线条?)。

【讨论】:

  • 如果您只想删除一个集合,您可以使用coll.get_label() 获取正确的集合,前提是您先标记了该集合。
【解决方案2】:

这不是我的答案,但我发现它最有用:

http://matplotlib.1069221.n5.nabble.com/animation-of-a-fill-between-region-td42814.html

你好毛里西奥, 补丁对象比线对象更难使用,因为与线对象不同的是,它从用户提供的输入数据中删除了一个步骤。这里有一个类似于你想做的例子:http://matplotlib.org/examples/animation/histogram.html

基本上,您需要在每一帧修改路径的顶点。它可能看起来像这样:

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

fig, ax = plt.subplots()
ax.set_xlim([0,10000])

x = np.linspace(6000.,7000., 5)
y = np.ones_like(x)

collection = plt.fill_between(x, y)

def animate(i):
    path = collection.get_paths()[0]
    path.vertices[:, 1] *= 0.9

animation.FuncAnimation(fig, animate,
                        frames=25, interval=30)

查看 path.vertices 以了解它们的布局方式。 希望有帮助, 杰克

【讨论】:

    【解决方案3】:

    如果您不想使用动画,或者从图形中删除所有内容以仅更新填充,您可以使用这种方式:

    致电fill_lines.remove(),然后再次致电axes_dummy.fill_between() 绘制新的。它在我的情况下有效。

    【讨论】:

      【解决方案4】:

      初始化pyplot交互模式

      import matplotlib.pyplot as plt
      
      plt.ion()
      

      在绘制填充时使用可选的标签参数:

      plt.fill_between(
          x, 
          y1, 
          y2, 
          color="yellow", 
          label="cone"
      )
      
      plt.pause(0.001) # refresh the animation
      

      稍后在我们的脚本中,我们可以按标签选择以删除特定填充或填充列表,从而在逐个对象的基础上制作动画。

      axis = plt.gca()
      
      fills = ["cone", "sideways", "market"]   
      
      for collection in axis.collections:
          if str(collection.get_label()) in fills:
              collection.remove()
              del collection
      
      plt.pause(0.001)
      

      您可以为要删除的对象组使用相同的标签;或以其他方式根据需要使用标签对标签进行编码以适应需要

      例如,如果我们有填充标签:

      “cone1”“cone2”“sideways1”

      if "cone" in str(collection.get_label()):
      

      将排序删除以“cone”为前缀的两个。

      你也可以用同样的方式为线条制作动画

      for line in axis.lines:
      

      【讨论】:

        【解决方案5】:

        另一个可行的习语是保留一个列表你的绘图对象;此方法似乎适用于任何类型的绘图对象。

        # plot interactive mode on
        plt.ion()
        
        # create a dict to store "fills" 
        # perhaps some other subclass of plots 
        # "yellow lines" etc. 
        plots = {"fills":[]}
        
        # begin the animation
        while 1: 
        
            # cycle through previously plotted objects
            # attempt to kill them; else remember they exist
            fills = []
            for fill in plots["fills"]:
                try:
                    # remove and destroy reference
                    fill.remove()
                    del fill
                except:
                    # and if not try again next time
                    fills.append(fill)
                    pass
            plots["fills"] = fills   
        
            # transformation of data for next frame   
            x, y1, y2 = your_function(x, y1, y2)
        
            # fill between plot is appended to stored fills list
            plots["fills"].append(
                plt.fill_between(
                    x,
                    y1,
                    y2,
                    color="red",
                )
            )
        
            # frame rate
            plt.pause(1)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-07-29
          • 1970-01-01
          • 1970-01-01
          • 2015-06-02
          • 2018-06-20
          • 1970-01-01
          相关资源
          最近更新 更多