如何暂停/恢复matplotlib ArtistsAnimation

时间:2017-01-09 21:50:27

标签: python animation matplotlib

我的问题是恢复matplotlib ArtistsAnimation

我的代码是:

def PlotFields(self):
    fig = plt.figure()
    axess = []
    for i in range(0,self.number_fields):                   
                  axess.append(fig.add_subplot((self.number_fields+1)//2,2,i+1))

    #find min and max in time    
    mins = {}
    maxs = {}    
    for key,field in self.fields.items():
        mins[key] = field[:,:,:,self.z_slice].min()
        maxs[key] = field[:,:,:,self.z_slice].max()
        if mins[key] == maxs[key]:#this fixes bug in imshow when vmin = vmax 
            mins[key] = mins[key]-0.1
            maxs[key] = maxs[key]+0.1


    #set up list of images for animation
    movie = []    
    images = []   
    nt = self.fields[list(self.fields)[0]].shape[0] #number of time slices
    print('time slices = {}'.format(nt))
    first = 1  
    for time in range(0,nt):    

        images.clear()
        i = 0 
        for key,field in self.fields.items():            
            if self.cut == 'xy':
                images.append(axess[i].pcolor(field[time,:,:,self.z_slice].T, vmin = mins[key], vmax = maxs[key]))                                        
                axess[i].set_xlabel('x')            
                axess[i].set_ylabel('y')                        
            elif self.cut == 'xz':
                images.append(axess[i].pcolor(field[time,:,:,self.y_slice].T, vmin = mins[key], vmax = maxs[key]))                                        
                axess[i].set_xlabel('x')            
                axess[i].set_ylabel('z')
            else:
                print('unknown cut --- exiting !!')
                quit()
            axess[i].set_title(key)
            i = i + 1            
        if first == 1:
            for i in range(0,self.number_fields):
                fig.colorbar(images[i], ax = axess[i])    
                first = 0   
    #    time_title.set_text('t={}'.format(t_array[time]))
        time_title = axess[0].annotate('t={}'.format(self.t_array[time]),xy = (0.1,1.2))           
        collected_list = [*images] #apparently a bug in matplotlib forces this solution        
        collected_list.append(time_title)
        movie.append(collected_list)       

    #for i in range(0,number_fields):
    #    fig.colorbar(images[i], ax = axess[i])    


    #run animation        
    self.ani = anim.ArtistAnimation(fig, movie, interval=500, blit = False, repeat_delay = 1000)    
    fig.canvas.mpl_connect('button_press_event', self.onClick)
    if self.save_movie == True:    
        try:
            ani.save('xy_film.mp4')
            #ani.save('film.mp4',writer = FFwriter, fps=30, extra_args=['-vcodec', 'libx264'])
        except Exception:
            print("Save failed: Check ffmpeg path")
    plt.show()


def onClick(self, event):
    self.pause == True
    if self.pause == False:
        self.ani._stop()
        self.pause = True
        print('self pause = False')
    else:
        self.ani._start()
        self.pause = False
    #pause ^= True
        print('self pause = True')

动画停止onClick但在第二次点击时会抛出以下错误,该错误应该恢复动画(如果可能):

  File "PlotFieldsFieldAligned.py", line 149, in onClick
self.ani._start()
File "/home/yolen/scicomp/anaconda3/lib/python3.5/site-    packages/matplotlib/animation.py", line 665, in _start
self.event_source.add_callback(self._step)
AttributeError: 'NoneType' object has no attribute 'add_callback' 

任何帮助表示赞赏:-D

1 个答案:

答案 0 :(得分:1)

虽然在这种情况下似乎FuncAnimation可能比ArtistAnimation更适合,但两者都可以 以同样的方式停止/开始。请参阅此问题stop / start / pause in python matplotlib animation

重点是“私人”ArtistAnimation._start()功能没有按照您的想法行事。因此,使用ArtistAnimation.event_source.stop()ArtistAnimation.event_source.start()函数是明智的。

下面是一个最小的,可运行的示例,显示如何通过单击鼠标按钮来启动/停止ArtistAnimation

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

class SomeClass():

    def __init__(self):
        self.pause = False

        self.fig, ax = plt.subplots()
        ax.set_aspect("equal")

        self.movie = []
        nt = 10
        X,Y = np.meshgrid(np.arange(16), np.arange(16))

        for t in range(nt):
            data = np.sin((X+t*1)/3.)**2+ 1.5*np.cos((Y+t*1)/3.)**2
            pc = ax.pcolor(data)
            self.movie.append([pc])

        self.ani = animation.ArtistAnimation(self.fig, self.movie, interval=100)    
        self.fig.canvas.mpl_connect('button_press_event', self.onClick)
        plt.show()

    def onClick(self, event):
        if self.pause:
            self.ani.event_source.stop()
        else:
            self.ani.event_source.start()
        self.pause ^= True

a = SomeClass()