matplotlib.animation.FuncAnimate 中的额外帧

Extra Frame in matplotlib.animation.FuncAnimate

我正在使用 matplotlib 动画探索实时图表。目前,我只是在数组中添加一个随机整数,并根据新数字更新我的绘图。问题是我似乎从情节中获得了额外的价值。

我有以下代码:

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import random

fig = plt.figure()
ax1 = fig.add_subplot(1, 1, 1)

xs = []
ys = []

def animate(i, xs, ys):
    
    x = i + 1
    y = random.randint(1, 50)
    
    print '{}: {}, {}'.format(i, x, y)
    
    xs.append(x)
    ys.append(y)
            
    ax1.clear()
    ax1.plot(xs, ys)
        
ani = animation.FuncAnimation(fig,
                              animate,
                              frames = 10,
                              fargs = (xs, ys),
                              repeat = False)
plt.show()

我只想绘制 10 个值,所以我在 FuncAnimate 调用中设置了 frames = 10。但是,print 语句正在输出第 11 个值:

所以很明显生成了 11 个帧,而不是 10 个。查看 FuncAnimate 的文档,我看不出为什么会发生这种情况。

谁能告诉我我错过了什么?

谢谢!

也许这不是解决它的最优雅的方法,但您可以使用标志作为解决方法,以避免在第一个循环中出现 运行 动画:

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import random

fig = plt.figure()
ax1 = fig.add_subplot(1, 1, 1)

xs = []
ys = []

flag = 0
def animate(i, xs, ys):

    global flag

    if i == 0 and flag == 0:
        flag = 1
        return

    if flag == 1:
        x = i + 1
        y = random.randint(1, 50)

        print '{}: {}, {}'.format(i, x, y)

        xs.append(x)
        ys.append(y)

        ax1.clear()
        ax1.plot(xs, ys)


ani = animation.FuncAnimation(fig,
                              animate,
                              frames = 10,
                              fargs = (xs, ys),
                              repeat = False)
plt.show()

输出:

0: 1, 37
1: 2, 2
2: 3, 46
3: 4, 39
4: 5, 30
5: 6, 47
6: 7, 16
7: 8, 3
8: 9, 3
9: 10, 49

剧情:


编辑:
我做了一些研究。 此行为是由于您(和我)没有指定 FuncAnimationinit_func 参数。你可以从 documentation:

中读到

init_func : callable, optional A function used to draw a clear frame. If not given, the results of drawing from the first item in the frames sequence will be used. This function will be called once before the first frame. The required signature is:

def init_func() -> iterable_of_artists

If blit == True, init_func must return an iterable of artists to be re-drawn. This information is used by the blitting algorithm to determine which parts of the figure have to be updated. The return value is unused if blit == False and may be omitted in that case.

如果不指定init_func,重复第一帧(作为初始化帧)。
也就是说,我认为避免重复的最正确方法是调用一个 init 函数,其中你不绘制任何东西:

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import random

fig = plt.figure()
ax1 = fig.add_subplot(1, 1, 1)

xs = []
ys = []

def init():
    ax1.clear()

def animate(i, xs, ys):
    x = i + 1
    y = random.randint(1, 50)

    print '{}: {}, {}'.format(i, x, y)

    xs.append(x)
    ys.append(y)

    ax1.clear()
    ax1.plot(xs, ys)


ani = animation.FuncAnimation(fig = fig,
                              func = animate,
                              init_func = init,
                              frames = 10,
                              fargs = (xs, ys),
                              repeat = False)

plt.show()

输出:

0: 1, 12
1: 2, 25
2: 3, 20
3: 4, 49
4: 5, 49
5: 6, 28
6: 7, 26
7: 8, 49
8: 9, 10
9: 10, 2

动画: