我是 Matplotlib 的新手,遇到了一个我无法解决的问题。
在下面的代码中,我想做的是创建多个光束段的动画,这些光束段在碰撞时移动并产生影响(还有一个计时器)。 我有很多梁节点(大约 100 个)、很多时间步长 (1000),所以我考虑使用 LineCollection 显示梁段。 现在,在 plt.show() 中使用 blit=True 一切正常,但是当我尝试将动画保存为 mp4 格式时,视频会在内存中保留光束的所有位置... 我看到我应该更新动画的元素,而不是一遍又一遍地创建新元素。我只是不知道如何更新我的元素(尤其是 LineCollection)。
这是我的实际代码:
def animation(self, t_init=0, t_fin=0.5, inter=5):
# initializing the framework of the animation
d1 = np.absolute(self.time_-t_init)
d2 = np.absolute(self.time_-t_fin)
idx_init = d1.argmin()
idx_fin = d2.argmin()
print("Start index: " + str(idx_init))
print("End index: " + str(idx_fin))
N_t = idx_fin - idx_init
nb_beam_nodes = len(self.num_nodes['list 1'])
nb_beams = nb_beam_nodes - self.m # self.m=6
# COORDINATES
x=np.zeros((1+(N_t//inter), nb_beam_nodes))
y=np.zeros(nb_beam_nodes)
xt=0
for i in range(idx_init, idx_fin+1, inter):
for idx, j in enumerate(self.num_nodes['list 1']):
j=int(j)
x[xt][idx]=float(self.coord[j-1].x) + 50*self.data_nodes[j]['displacements'][i]
xt=xt+1
for idx, j in enumerate(self.num_nodes['list 1']):
j=int(j)
y[idx]=float(self.coord[j-1].y)
# IMPACTS
impacts = {}
for i in range(self.N_t):
impacts[i] = {}
impacts[i]['efforts'] = []
impacts[i]['x-coord'] = []
impacts[i]['y-coord'] = []
for j in range(self.N_s):
if self.data_springs[j+1]['elasticforces'][i] > 500:
# effort
impacts[i]['efforts'].append(self.data_springs[j+1]['elasticforces'][i])
# coordinates
nnl = self.ressorttrans.listElem[j].nprim
nnr = self.ressorttrans.listElem[j].nsec
x_init = (float(self.coord[nnl-1].x)+float(self.coord[nnr-1].x))/2
y_init = (float(self.coord[nnl-1].y)+float(self.coord[nnr-1].y))/2
impacts[i]['x-coord'].append(x_init)
impacts[i]['y-coord'].append(y_init)
# creating windows parameters
fig = plt.figure()
ax = plt.axes(xlim=(0, 14), ylim=(-0.5, 4.5))
ax.set_xticks(np.arange(0, 14, step=1))
axtext = fig.add_axes([0.2, 0.9, 0.4, 0.1])
axtext.axis("off")
time = axtext.text(0.5, 0.5, "Time: "+str(0)+" sec", ha="left", va="top", style='italic')
time.set_bbox(dict(facecolor='red', alpha=0.5))
# initialization test
lc = mc.LineCollection([], colors="blue", linewidths=1)
plotted_beams = ax.add_collection(lc)
rect = ax.scatter([], [], color = 'blue', marker='s', s=320)
plotted_impacts = ax.scatter([], [], edgecolors='red', facecolors='none', s=[])
def animate(i):
# beams
beams = [None]*(nb_beams)
beam_nb = 0
for j in range(nb_beam_nodes-1):
num_point1=int(self.num_nodes['list 1'][j])
num_point2=int(self.num_nodes['list 1'][j+1])
if num_point2-num_point1==1:
beams[beam_nb] = [(x[i][j], y[j]), (x[i][j+1], y[j+1])]
beam_nb = beam_nb + 1
lc = mc.LineCollection(beams, colors="blue", linewidths=1)
plotted_beams = ax.add_collection(lc)
ax.autoscale
ax.margins(0.1)
# grids
xb = [i[0] for j in beams for i in j]
yb = [i[1] for j in beams for i in j]
rect = ax.scatter(xb, yb, color = 'blue', marker='s', s=320)
# impacts
real_idx = idx_init+i*inter
x_coords = impacts[real_idx]['x-coord']
y_coords = impacts[real_idx]['y-coord']
efforts = impacts[real_idx]['efforts']
plotted_impacts = ax.scatter(x_coords, y_coords, edgecolors='red', facecolors='none', s=efforts)
# timer
t = t_init + (i+1)*inter/10000
time.set_text("Time: "+str(t)+" sec")
return plotted_beams, rect, plotted_impacts, time,
ani = animation.FuncAnimation(fig, animate2, frames=len(x), init_func=init, interval=25, repeat=False, blit=True)
plt.show()
return ani
def save_anim(self, ani):
"""
Parameters
----------
ani (animation.FuncAnimation): animation that we seek to save
This function
Returns
-------
None.
"""
matplotlib.use("Agg")
Writer = animation.writers['ffmpeg']
writer = Writer(fps=15, metadata=dict(artist='Me'), bitrate=1800)
ani.save('test.mp4', writer=writer)