单个循环中的matplotlib动画控制间隔

时间:2017-10-03 17:50:31

标签: python animation matplotlib

是否有一种直接的方法可以在脚本运行时精确控制动画对象的显示时间,同时考虑到updatefig函数的每个循环所需的时间?

我正在编写一个应该在Raspberry Pi上运行的脚本。它拍摄了一个竞技场并跟踪移动点。

用户应该拥有的一个选项是查看程序在每个帧中正在执行的操作。显而易见的方法是使用matplotlib的动画模块,因为这应该是最快的绘图方式。为了在实验后自动关闭绘图并继续保存数据等。我希望脚本在给定时间后关闭绘图(帧数/帧速率)

我找到了一种关闭情节的方法,通过运行plt.ion()的脚本然后在调用动画后运行plt.pause()。

现在,什么停顿?似乎plt.pause()不会花费在updatefig()函数的每个循环上花费的时间。所以我不得不在调用plt.pause之前定义每个循环占用的时间。

为了说明问题,我编写了一个简短的示例代码(您可能需要更改plt.pause的行,具体取决于您的计算机的速度 - 这意味着这个循环占用了我的计算机。) / p>

import matplotlib.pyplot as plt
from matplotlib import animation
import numpy as np
import time
import random

plt.ion()

class example():
    '''
    In this example I want to illustrate that I don't know a good way to control 
    the timing of the animation module.
    I want to have 10 frames with an interval of 10 seconds, so I would think 
    that I only have to call plt.pause(10) after opening the animation.
    Unfortunately it seems that the animation.Funcanimation is essentially 
    blocking the plt.pause function when it's still in the loop.
    '''
    def __init__(self):

        self.image = np.zeros((1000,1000), dtype=np.float32)
        self.total_time = 0

        self.plotting()

    def plotting(self):

        fig = plt.figure(figsize=(7,7))
        ax = fig.add_subplot(111)
        video_object = ax.imshow(self.image, vmin=0, vmax=1000, animated=True)

        def init():
            self.image[:, :] = np.random.rand(1000, 1000)
            video_object = ax.imshow(self.image)
            return(video_object,)

        def updatefig(i):
            start_time = time.time()
            #self.image[:,:] = np.random.rand(1000,1000) # I leave this here as this is how it should be done
            for i in range(self.image.shape[0]): # slow looping 
                for j in range(self.image.shape[1]):
                    self.image[i,j] = random.uniform(0,1000)

            video_object.set_array(self.image)
            self.total_time += time.time() - start_time
            print('time in loop: ' + repr(time.time() - start_time)[0:5])
            return(video_object,)

        ani = animation.FuncAnimation(fig = fig, func = updatefig, init_func = init,
                                      frames = 10, interval=1000, blit=True,
                                      repeat=False)
        fig.show()
        plt.pause(10-(0.55*10))
        plt.close()
        print('Total time loop : ' + repr(self.total_time))

outer_time = time.time()
example()
print('Total time until close fig: ' + repr(time.time() - outer_time))

1 个答案:

答案 0 :(得分:2)

将交互模式与FuncAnimation混合可能不是一个好主意。相反,您可以使用计时器(fig.canvas.new_timer(interval=interval))在plt.close()毫秒后调用interval。这里interval将是重复时间(或动画间隔)的帧数加上一个小偏移量,这可能是实际创建窗口所需的时间。 在下面的例子中,这被选择为300毫秒,这对我来说很好。

import matplotlib.pyplot as plt
from matplotlib import animation
import numpy as np
import time
import random


class example():

    def __init__(self, nframes = 17, interval = 1000):

        self.image = np.zeros((1000,1000), dtype=np.float32)
        self.total_time = 0
        self.nframes = nframes
        self.interval = interval
        self.plotting()

    def plotting(self):

        fig = plt.figure(figsize=(7,7))
        ax = fig.add_subplot(111)
        video_object = ax.imshow(self.image, vmin=0, vmax=1000, animated=True)
        #creating a timer object and setting an interval of 
        # nframes * interval + time to first draw milliseconds
        timer = fig.canvas.new_timer(interval = self.nframes*self.interval+300) 
        timer.add_callback(plt.close)

        def init():
            self.image[:, :] = np.random.rand(1000, 1000)
            video_object = ax.imshow(self.image)
            # start timer
            timer.start()
            return(video_object,)

        def updatefig(k):
            start_time = time.time()
            #self.image[:,:] = np.random.rand(1000,1000) # I leave this here as this is how it should be done
            for i in range(self.image.shape[0]): # slow looping 
                for j in range(self.image.shape[1]):
                    self.image[i,j] = random.uniform(0,1000)

            video_object.set_array(self.image)
            self.total_time += time.time() - start_time
            print('time in loop: ' + repr(time.time() - start_time)[0:5] + "- " +str(k))
            return(video_object,)

        ani = animation.FuncAnimation(fig = fig, func = updatefig, init_func = init,
                                      frames = self.nframes, repeat=False,
                                      interval=self.interval, blit=True )

        plt.show()

        print('Total time loop : ' + repr(self.total_time))

outer_time = time.time()
example(nframes = 17, interval = 1000)
print('Total time until close fig: ' + repr(time.time() - outer_time))