Matplotlib动画填充形状之间

时间:2013-04-20 13:15:56

标签: python animation matplotlib plot

我正在尝试在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数据,并在blit之前绘制它们(“#Update fill data too”&“#Draw fill too”)。我尝试了fill_lines.set_verts()但没有成功,找不到示例...

谢谢!

5 个答案:

答案 0 :(得分:5)

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

axes_dummy.collections.clear()

并绘制新的“fill_between”PolyCollection:

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

在填充的上面填充未填充的等高线图需要类似的技巧,因为未填充的等高线图也是一个集合(我猜想的是线条)。

答案 1 :(得分:3)

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

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

嗨Mauricio, 补丁对象比线对象更难处理,因为与对象不同的是从用户提供的输入数据中删除的步骤。有一个类似于你想要做的例子: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,看看它们是如何布局的。 希望有所帮助,    杰克

答案 2 :(得分:2)

如果您不想使用anitmation,或者从图中移除所有内容以仅更新填充,您可以使用我的方式:

致电fill_lines.remove(),然后再次致电axes_dummy.fill_between()以吸引新的from core.sequencer import Sequencer from gui.threadGui import ThreadGui t1 = ThreadGui() t2 = Sequencer() t1.start() t2.start() t1.join() t2.join() 。为我工作。

答案 3 :(得分:0)

初始化pyplot交互模式

import matplotlib.pyplot as plt

plt.ion()

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

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:

答案 4 :(得分:0)

另一种行之有效的方法是保留绘制对象的列表。这种方法似乎适用于任何类型的绘图对象。

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