'How can I animate a matplotlib plot from within for loop

I would like to update my matplotlibplot with values calculated in each iteration of a for loop. The idea is that I can see in real time which values are calculated and watch the progress iteration by iteration as my script is running. I do not want to first iterate through the loop, store the values and then perform the plot.

Some sample code is here:

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()

Most of the examples I have seen online, deal with the case where everything for the animation is global variables, which I would like to avoid. When I use a debugger to step through my code line by line, the figure does appear and it is animated. When I just run the script without the debugger, the figure displays but nothing is plot and I can see that my loop doesn't progress past the first iteration, first waiting for the figure window to be closed and then continuing.



Solution 1:[1]

trying to elaborate on @dumbpotato21 answer, here my attempt:

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()

Solution 2:[2]

There are a number of alternatives which might come in handy in different situations. Here is one that I have used:

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()

Additionally, the set_data(...) method of a line plot or imshow object is useful if only the data changes and you don't want to re-drw the whole figure (as this is very time consuming).

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 pippo1980
Solution 2