如何在 for 循环中为 matplotlib 图制作动画

How can I animate a matplotlib plot from within for loop

我想用 for 循环的每次迭代中计算的值更新我的 matplotlibplot。我的想法是,我可以实时查看计算了哪些值,并在我的脚本 运行ning 中逐次观察进度迭代。我不想先遍历循环、存储值然后执行绘图。

一些示例代码在这里:

from itertools import count
import random

from matplotlib.animation import FuncAnimation
import matplotlib.pyplot as plt


def animate(i, x_vals, y_vals):
    plt.cla()
    plt.plot(x_vals, y_vals)

if __name__ == "__main__":
    x_vals = []
    y_vals = []
    fig = plt.figure()
    index = count()

    for i in range(10):
        print(i)
        x_vals.append(next(index))
        y_vals.append(random.randint(0, 10))
        ani = FuncAnimation(fig, animate, fargs=(x_vals, y_vals))
        plt.show()

我在网上看到的大多数示例都处理了动画的所有内容都是全局变量的情况,我想避免这种情况。当我使用调试器逐行调试我的代码时,图形确实出现了并且是动画的。当我只是 运行 没有调试器的脚本时,图形显示但没有任何内容,我可以看到我的循环没有通过第一次迭代,首先等待图形 window 关闭然后继续。

在 matplotlib 中制作动画时永远不应该使用循环。

animate 函数会根据您的时间间隔自动调用。

像这样的东西应该可以工作

def animate(i, x=[], y=[]):
    plt.cla()
    x.append(i)
    y.append(random.randint(0, 10))
    plt.plot(x, y)


if __name__ == "__main__":
    fig = plt.figure()
    ani = FuncAnimation(fig, animate, interval=700)
    plt.show()

有许多备选方案可能会在不同情况下派上用场。这是我用过的一个:

import matplotlib.pyplot as plt
import numpy as np
from time import sleep



x = np.linspace(0, 30, 51)
y = np.linspace(0, 30, 51)
xx, yy = np.meshgrid(x, y)


# plt.style.use("ggplot")
plt.ion()
fig, ax = plt.subplots()
fig.canvas.draw()

for n in range(50):
    # compute data for new plot
    zz = np.random.randint(low=-10, high=10, size=np.shape(xx))

    # erase previous plot
    ax.clear()

    # create plot
    im = ax.imshow(zz, vmin=-10, vmax=10, cmap='RdBu', origin='lower')

    # Re-render the figure and give the GUI event loop the chance to update itself
    # Instead of the two lines one can use "plt.pause(0.001)" which, however gives a
    # decepracted warning.
    # See https://github.com/matplotlib/matplotlib/issues/7759/ for an explanation.
    fig.canvas.flush_events()
    sleep(0.1)


# make sure that the last plot is kept
plt.ioff()
plt.show()

此外,如果只有数据发生变化并且您不想重新绘制整个图形(因为这非常耗时),则线图或 imshow 对象的 set_data(...) 方法很有用。

试图详细说明@dumbpotato21 的回答,这里是我的尝试:

import random

from matplotlib.animation import FuncAnimation
import matplotlib.pyplot as plt



def data():
    cnt = 0
    x = []
    y = []
        
    for i in  range(1,10):
        # x = []
        # y = []
        

        x.append(cnt*i)
        y.append(random.randint(0, 10))

        
        cnt += 1
        
        
        yield  x, y, cnt
    
    input('any key to exit !!!')
    quit()


def init_animate():
    pass

def animate( data, *fargs) :
    
    print('data : ', data, '\n data type : ', type(data), ' cnt : ', data[2])
    
    plt.cla()
    
    x = [i*k for i in data[0]]
    
    y = [i*p for i in data[1]]
    
    plt.plot(x,y)


if __name__ == "__main__":
    fig = plt.figure()
    
    k = 3
    p = 5
    
    ani = FuncAnimation(fig, animate, init_func=init_animate, frames=data,  interval=700, fargs = [k,p])
    plt.show()