Matplotlib 动画填充形状之间

问题描述 投票:0回答:7

我正在尝试为 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 );

问题是如何在每次调用

fill_between
时根据
Poly
line1_data
更新
line2_data
update_data()
数据并在
blit
之前绘制它们(“#也更新填充数据”&“#绘制也填满”)。我尝试了
fill_lines.set_verts()
但没有成功,也找不到例子。

python animation matplotlib plot
7个回答
15
投票

好吧,正如有人指出的,我们在这里处理一个集合,所以我们必须删除并重新绘制。因此,在

update_data
函数中的某个位置,删除与其关联的所有集合:

axes_dummy.collections.clear()

并绘制新的“fill_ Between”PolyCollection:

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

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


5
投票

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

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()
来绘制新的。它对我的情况有效。


3
投票

与这里大多数答案所述相反,每次要更新其数据时,无需删除并重新绘制由

PolyCollection
返回的
fill_between
。相反,您可以修改基础
vertices
对象的
codes
Path
属性。假设您已经通过
创建了一个
PolyCollection

import numpy as np
import matplotlib.pyplot as plt

#dummy data
x = np.arange(10)
y0 = x-1
y1 = x+1

fig = plt.figure()
ax = fig.add_subplot()
p = ax.fill_between(x,y0,y1)

现在您想用新数据

p
xnew
y0new
更新
y1new
。那么你能做的就是

v_x = np.hstack([xnew[0],xnew,xnew[-1],xnew[::-1],xnew[0]])
v_y = np.hstack([y1new[0],y0new,y0new[-1],y1new[::-1],y1new[0]])
vertices = np.vstack([v_x,v_y]).T
codes = np.array([1]+(2*len(xnew)+1)*[2]+[79]).astype('uint8')

path = p.get_paths()[0]
path.vertices = vertices
path.codes = codes

说明:

path.vertices
包含由
fill_between
绘制的面片的顶点,包括附加的开始和结束位置,
path.codes
包含如何使用它们的说明(1 = MOVE POINTER TO,2 = DRAW LINE TO,79 = CLOSE聚)。


0
投票

初始化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)

您可以对要删除的对象组使用相同的标签;或者根据需要用标签对标签进行编码以满足需要

例如,如果我们的填充标记为:

“锥体 1”“锥体 2”“侧向 1”

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

会删除所有以“cone”为前缀的内容。

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

for line in axis.lines:

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)

0
投票

您可以按照这个问题的建议直接绘制多边形并更新顶点:How to update PolyCollection in matplotlib

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

x = np.arange(0.0, 2, 0.01)
y = np.sin(2*np.pi*x)

fig, ax = plt.subplots()

polycolelction = ax.fill_between(x, y)


def vertices_between(x, y1, y2):
    if isinstance(y2, float | int):
        y2 = np.full(x.size, y2)
    y2 = np.array(y2)
    new_x = np.hstack((x, x[::-1]))
    new_y = np.hstack((y1, y2[::-1]))
    return np.vstack((new_x, new_y)).T


def update(i):
    y = 1.2*np.sin(i*np.pi*x)

    polycolelction.set_verts([vertices_between(x, y, 0)])
    fig.canvas.draw()
    fig.canvas.flush_events()


anim = FuncAnimation(fig, update, 10, interval=300)
plt.show()
© www.soinside.com 2019 - 2024. All rights reserved.