我正在尝试为 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()
但没有成功,也找不到例子。
好吧,正如有人指出的,我们在这里处理一个集合,所以我们必须删除并重新绘制。因此,在
update_data
函数中的某个位置,删除与其关联的所有集合:
axes_dummy.collections.clear()
并绘制新的“fill_ Between”PolyCollection:
axes_dummy.fill_between(x, y-sigma, y+sigma, facecolor='yellow', alpha=0.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 以了解它们的布局方式。 希望有帮助, 杰克
如果您不想使用动画,或者从图形中删除所有内容以仅更新填充,您可以使用这种方式:
调用
fill_lines.remove()
,然后再次调用axes_dummy.fill_between()
来绘制新的。它对我的情况有效。
与这里大多数答案所述相反,每次要更新其数据时,无需删除并重新绘制由
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聚)。
初始化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:
另一个可行的习惯用法是保留绘制对象的列表;此方法似乎适用于任何类型的绘制对象。
# 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)
您可以按照这个问题的建议直接绘制多边形并更新顶点: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()