Matplotlib动画更新LineCollection保存视频

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

我是 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)
python matplotlib spyder matplotlib-animation
© www.soinside.com 2019 - 2024. All rights reserved.