I'm trying to animate a 2d path, and I would like it to have a sort of "Disappearing Tail", where at any given time, it shows only the last 5 (for example) particles.
What I currently have is quite far from this:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation, rc
from IPython.display import HTML
sample_path = np.random.uniform(size=(100,2))
fig, ax = plt.subplots()
x = np.arange(-1, 1, 0.01) # x-array
line, = ax.plot(sample_path[0,0], sample_path[0,1])
def connect(i):
(x0,y0) = sample_path[i-1,:]
(x1,y1) = sample_path[i,:]
plt.plot([x0,x1],[y0,y1],'ro-')
return line,
def init():
line.set_ydata(np.ma.array(x, mask=True))
return line,
ani = animation.FuncAnimation(fig, connect, np.arange(1, 100), init_func=init,
interval=200, blit=True)
HTML(ani.to_html5_video())
This retains a 'full tail', i.e. after k steps, it shows all of the first k locations.
Is there a way to adapt what I've got so that the animation only shows the most recent history of the particle?
You would probably want to update the line instead of adding a lot of new points to the plot. Selecting the 5 most recent points can be done via indexing, e.g.
sample_path[i-5:i, 0]
Complete example, where we take care not to have a negative index and also don't use blit (which does not make sense if saving the animation).
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation, rc
r = np.sin(np.linspace(0,3.14,100))
t = np.linspace(0, 10, 100)
sample_path = np.c_[r*(np.sin(t)+np.cos(t)), r*(np.cos(t)-np.sin(t))]/1.5
fig, ax = plt.subplots()
line, = ax.plot(sample_path[0,0], sample_path[0,1], "ro-")
def connect(i):
start=max((i-5,0))
line.set_data(sample_path[start:i,0],sample_path[start:i,1])
return line,
ax.set_xlim(-1,1)
ax.set_ylim(-1,1)
ani = animation.FuncAnimation(fig, connect, np.arange(1, 100), interval=200)
plt.show()
Not as good as ImportanceOfBeingErnest's answer technically, but it still does the job and looks pretty cool, just plot the latest points and clear the old ones. I added a few more and sped it up because I thought it looked better with a longer trail.
def connect(i):
#clear current points
plt.clf()
#prevent axis auto-resizing
plt.plot(0,0)
plt.plot(1,1)
#generate points to plot
(x0,y0) = sample_path[i-8,:]
(x1,y1) = sample_path[i-7,:]
(x2,y2) = sample_path[i-6,:]
(x3,y3) = sample_path[i-5,:]
(x4,y4) = sample_path[i-4,:]
(x5,y5) = sample_path[i-3,:]
(x6,y6) = sample_path[i-2,:]
(x7,y7) = sample_path[i-1,:]
(x8,y8) = sample_path[i,:]
#plot old points
plt.plot([x0,x1,x2,x3,x4,x5,x6,x7],[y0,y1,y2,y3,y4,y5,y6,y7],'ro-')
#plot new point in blue
plt.plot([x7,x8],[y7,y8],'bo-')
return line,
def init():
line.set_ydata(np.ma.array(x, mask=True))
return line,
ani = animation.FuncAnimation(fig, connect, frames=np.arange(1, 100),
init_func=init,
interval=50, blit=True)
HTML(ani.to_html5_video())
Related
I am trying to animate a patch.Rectangle object using matplotlib. I want the said object to move along a path.Arc.
A roundabout way to do this would be (approximately) :
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
import matplotlib.patches as mpat
fig, ax = plt.subplots()
ax.set(xlim=(0, 10), ylim=(0, 10))
# generate the patch
patch = mpat.Rectangle((5, 5), 1, 4)
patch.rotation_point = 'center'
# generate the path to follow
path_to_follow = mpat.Arc((5, 5), 2, 2)
ax.add_patch(path_to_follow)
def init():
patch.set(x=5, y=5)
ax.add_patch(patch)
return patch,
def animate(i, ax):
new_x = 5 + np.sin(np.radians(i)) - 0.5 # parametric form for the circle
new_y = 5 + np.cos(np.radians(i)) - 2
patch.set(x=new_x, y=new_y, angle=90-i)
return patch,
anim = animation.FuncAnimation(fig, animate,
init_func=init,
fargs=[ax],
frames=360,
interval=10,
blit=True)
plt.show()
The rectangle follows a circle, but a parametric one. Would it be possible to make it follow any path?
In other words, I would like to know if there are other simpler methods to do this (make my patch follow my path, here a circle), and if that could be generalized to other path.
Thanks in advance !
I searched into the matplotlib doc for a methods which gives the parametric form for a given path (but apparently there is not), or for a methods which directly move a patch along a path (obviously, there was not).
Here is one way to use matplotlib.path.Path to generate a path, whose vertices can be obtained using the method cleaned, to move a patch along it.
I have tried to showcase how blue and red colored Rectangles can be moved along a (blue) linear path and a (red) circular path, respectively:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation, path
import matplotlib.patches as mpat
fig, ax = plt.subplots()
ax.set(xlim=(0, 10), ylim=(0, 10))
# generate a linear path
path1 = np.column_stack((np.arange(500)/50, np.arange(500)/50))
# generate a circular path
circle = path.Path.circle(center=(5, 5), radius=1)
path2 = circle.cleaned().vertices[:-3]
# create patches
patch1 = mpat.Rectangle((0, 0), 1, 3)
patch2 = mpat.Rectangle((0, 0), 1, 3, color='red', fill=None)
# plot path vertices
plt.scatter(x=path1[:, 0], y=path1[:, 1], s=2)
plt.scatter(x=path2[:, 0], y=path2[:, 1], color='red', s=2)
def init():
patch1.set(x=0, y=0)
patch2.set(x=5, y=6)
ax.add_patch(patch1)
ax.add_patch(patch2)
return [patch1, patch2]
def animate(i, ax):
j = i % 500 # path1 has shape (500, 2)
k = (i % 16) # path2 has shape (16, 2)
patch1.set(x=path1[j][0], y=path1[j][1], angle=-j)
patch2.set(x=path2[k][0], y=path2[k][1], angle=-k)
return [patch1, patch2]
anim = animation.FuncAnimation(fig, animate,
init_func=init,
fargs=[ax],
frames=360,
interval=100,
blit=True)
plt.show()
If your path is some collection of coordinates, you can not only translate the rectangle, but also compute the vector from one point to the next and update the rectangle angle accordingly. In the next example (mix of your code with mine), we generate from the beginning the path, but it could be instead live read from some external source.
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
import matplotlib.patches as mpat
# create some path with pairs of X and Y coordinates
t = np.linspace(0, 360, 361)
X = 5. * np.sin(np.radians(t))
Y = t * (t-360*2) / 8000 + 7.5
# create x and y lists to store the position pairs as they are plotted
x = [X[0],]
y = [Y[0],]
# plotting
fig, ax = plt.subplots()
ax.set(xlim=(-10, 10), ylim=(-10, 10))
patch = mpat.Rectangle((x[0], y[0]), 1, 3)
def init():
patch.set(x=x[0], y=y[0])
ax.plot(X, Y)
ax.add_patch(patch)
return patch,
def animate(i, ax):
new_x = X[i] # we are getting from pre-generated data,
new_y = Y[i] # but it could be some function, or even live external source
vx = new_x - x[-1] # calculate the vectors, which are used for angle
vy = new_y - y[-1]
x.append(new_x) # store for next iteration, so that we can calculate the vectors
y.append(new_y)
new_alfa = np.degrees(np.arctan2(vy, vx))
patch.set(x=new_x, y=new_y, angle = new_alfa)
return patch,
anim = animation.FuncAnimation(fig, animate,
init_func=init,
fargs=[ax],
frames=360,
interval=20,
blit=True)
plt.show()
Thanks a lot for your answers, here is the code I made (mixing the two answers) and which does exactly what I wanted, if it helps anyone :
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
import matplotlib.patches as mpat
fig, ax = plt.subplots()
ax.set(xlim=(-6, 6), ylim=(-6, 6))
# generate a circular path
circle = mpat.Arc((0, 0), 10, 10, theta1=20, theta2=220, color='green')
path = circle.get_transform().transform_path(circle.get_path()).cleaned().vertices[:-3] # get_path is not enough because of the transformation, so we apply to the path the same transformation as the circle has got from the identity circle
ax.add_patch(circle)
# create patch
patch = mpat.Rectangle((0, 0), 1, 4, color='red', fill=None)
patch.rotation_point = 'center'
# plot path vertices
plt.scatter(x=path[:, 0], y=path[:, 1], color='red', s=2)
shape = len(path)
def init():
patch.set(x=5-0.5, y=6-2) # we substract to get to the center
ax.add_patch(patch)
return [patch]
def animate(i, ax):
k = i % shape
new_x = path[k][0]
new_y = path[k][1]
vx = new_x - path[k-1][0]
vy = new_y - path[k-1][1]
patch.set(x=new_x-0.5, y=new_y-2, angle=np.degrees(np.arctan2(vy, vx) + 90))
return [patch]
anim = animation.FuncAnimation(fig, animate,
init_func=init,
fargs=[ax],
frames=360,
interval=200,
blit=True,
repeat=False)
plt.show()
To improve this, is anyone know how to increase the number of points given? In other words, increase the len of path to be more precise in moving the rectangle.
Thanks in advance !
Context: I am trying to create a teaching demo tool to show how the iteration guesses through a set of points to ultimately arrive at the root of an equation
Problem: I want to animate using matplotlib to show the iterations viusally. Specifically, given a curve (see along side) and an initial guess (say 1.5 in this particular case), I want to compose an animation of 3 scenes:
draw a vertical line at x = guess (=1.5), to meet the curve at y= 9 (aka value).
Draw a line through (guess, value) with a slope 'm' (generated by my code). Delete the vertical line at this stage and keep the second line
Delete the second line after a pause
For illustration, here is the image
Additionally here is my code:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
xdata, ydata = [], []
xdata2, ydata2 = [], []
ln, = plt.plot([], [])
def init():
ax.set_xlim(-3, 3)
ax.set_ylim(-10, 10)
return [ln]
def update(frame):
xdata.append(frame)
ydata.append(frame ** 3 + 4 * frame ** 2 + frame - 6)
ln.set_data(xdata, ydata)
return [ln]
def update2(frame):
xdata2.append(1.5)
ydata2.append(frame)
ln.set_data(xdata2,ydata2)
return[ln]
ani = FuncAnimation(fig, update, frames=np.linspace(-3, 3, 100),
init_func=init, blit=True)
ani2 = FuncAnimation(fig, update2, frames=np.linspace(0, 3, 100),blit=True)
plt.show()
This is a simplified version of the problem that I am trying to solve and is not part of the code that involves the calculation of the iterations etc. For now I am just trying to draw the curve in Update and post that, draw a vertical line at x=1.5.
Results: At my end, the entire animation is a set of flickering where it is apparent that matplotlib switches "thread context" very rapidly between the two FuncAnimation calls
The desired animation in your next question can be achieved in the form of drawing a curve as a base graph, adding line graphs frame by frame, and deleting that graph object when necessary.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import time
fig, ax = plt.subplots()
x = np.linspace(-3, 3, 100)
y = x ** 3 + 4 * x **2 + x -6
xx = x[74]
yy = y[74]
#print(xx,yy)
xx2 = x[65]
yy2 = y[65]
#print(xx2,yy2)
ln, = ax.plot(x, y)
ln2, = ax.plot([], [])
ln3, = ax.plot([],[])
ax.set_xlim(-3, 3)
ax.set_ylim(-10, 10)
# Move axes center and spines off
ax.spines[['top', 'right']].set_visible(False)
ax.spines[['left', 'bottom']].set_position('center')
# Show ticks axes only
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
def update(i):
ln2.set_data((xx, xx), (0, yy))
ln2.set_color('k')
if i == 2:
ln3.set_data((xx2, xx), (yy2, yy))
ln3.set_color('red')
ln3.set_width=3
if i >=3:
ln2.set_data([],[])
ln3.set_data([],[])
return ln2,ln3
ani = FuncAnimation(fig, update, frames=[0,1,2,3], interval=500, blit=True, repeat=True)
plt.show()
Note this is a follow-up question of How to make an animation of a Lissajous curve;
My first idea was to edit my original question and ask for the animation, but I understand and respect SO way of operating. So the best is making another question.
I want to make an animation of the curve (where you incrementally draw it) with parametrization: x(t) = sin(3t) and y(y) = sin(4t) where t[0, 2pi].
For doing so I would add the code:
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
ln, = plt.plot([], [], 'b')
def init():
ax.set_xlim(-1, 1)
ax.set_ylim(-1, 1)
return ln,
def update(frame):
x.append(np.sin(4*frame))
y.append(np.sin(3*frame))
ln.set_data(x, y)
return ln,
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
init_func=init, blit=True)
The problem is that with this code it doesn't draw the whole curve from scratch. What does is overdrawing it, getting overlapping.
How can I draw it from scratch (i.e. starting with white background)? I've been thinking about an if else but got nothing.
Thanks
EDIT
Let me show you the whole code:
%matplotlib notebook
import matplotlib.pyplot as plt
import math
import numpy as np
from matplotlib.animation import FuncAnimation
# set the minimum potential
rm = math.pow(2, 1 / 6)
t = np.linspace(-10, 10, 1000, endpoint = False)
x = []
y = []
for i in t: #TypeError 'int' object is not iterable
x_i = np.sin( 3 * i )
y_i = np.sin( 4 * i )
x.append(x_i)
y.append(y_i)
# set the title
plt.title('Plot sin(4t) Vs sin(3t)')
# set the labels of the graph
plt.xlabel('sin(3t)')
plt.ylabel('sin(4t)')
fig, ax = plt.subplots()
ln, = plt.plot([], [], 'b')
def init():
ax.set_xlim(-1, 1)
ax.set_ylim(-1, 1)
return ln,
def update(frame):
x.append(np.sin(4*frame))
y.append(np.sin(3*frame))
ln.set_data(x, y)
return ln,
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
init_func=init, blit=True)
# display the graph
plt.show()
This is the image I get at the beginning (screenshot taken after approximately 1s after started running; that's why you see that funny line): https://imgur.com/a/bNoViDA. As you can see it doesn't start from scratch (i.e not from white background)
This is the plot I get at the end: https://imgur.com/a/WQHHUk9
I am seeking getting that ending point but drawing everything from scratch, without starting with the shown plot.
I wanted to visualize the path of a 2D-algorithm. So I wrote a short Python code, that produces such a animation. The problem is, that for each pixel (a plt.Rectangle) I add, the code gets slower and slower. The first 20 pixels get displayed in about 1 second, the last 20 pixels take already 3 seconds. And obviously it gets even worse for bigger grids and more pixels.
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(7, 7)
ax = plt.axes(xlim=(0, 20), ylim=(0, 20))
pixels = list()
def init():
return list()
def animate(i):
index = len(pixels)
index_x, index_y = index // 20, index % 20
pixel = plt.Rectangle((index_x, index_y), 1, 1, fc='r')
ax.add_patch(pixel)
pixels.append(pixel)
return pixels
anim = animation.FuncAnimation(fig, animate,
init_func=init,
frames=100,
interval=5,
blit=True)
plt.show()
It's quite clear to me, why it takes longer. Since the number of patches gets bigger and bigger each frame, matplotlibs rendering gets slower and slower. But not this slow! How can I get more speed? Is there a way that I can keep the old plot and only overwrite the current pixel?
I tried timing the animate function and for some reason there is no apparent slowdown in the function itself. Besides, blit should ensure only the latest rectangle is drawn. A possible way to prevent the redraw you suggest is to rasterize the plot with,
m=ax.add_patch(pixel)
m.set_rasterized(True)
Although this doesn't seem to improve speed for my timing. I think the increase must result somewhere in matplotlib when updating the plot. This is clear using interactive plotting, e.g.
from matplotlib import pyplot as plt
import time
fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(7, 7)
ax = plt.axes(xlim=(0, 20), ylim=(0, 20))
npx = 20; npy = 20
Npix = npx*npy
plt.ion()
plt.show()
for i in range(Npix):
#ax.cla()
t0 = time.time()
index_x, index_y = i // 20, i % 20
pixel = plt.Rectangle((index_x, index_y), 1, 1, fc='r')
ax.add_patch(pixel)
fig.set_rasterized(True)
plt.pause(0.0001)
t1 = time.time()
print("Time=",i,t1-t0)
Which gives for the rasterised, non-rasterised and cleared axis (ax.cla) case,
I'm not sure why this happens, maybe someone with better insight into matplotlib would be able to help. One way to speed up the plot is to setup and put all rectangles in a patchcollection. Then the animation just changes the facecolor so only the rectangles which need be shown are displayed,
from matplotlib import pyplot as plt
from matplotlib import animation
import numpy as np
from matplotlib.collections import PatchCollection
fig = plt.figure()
fig.set_dpi(100)
fig.set_size_inches(7, 7)
ax = plt.axes(xlim=(0, 20), ylim=(0, 20))
npx = 20; npy = 20
Npix = npx*npy
displayed = np.zeros((npx, npy, 4))
pixels = []
def init():
for index in range(Npix):
index_x, index_y = index // npx, index % npy
pixel = plt.Rectangle((index_x, index_y), 1, 1, fc='r', ec='none')
pixels.append(pixel)
return pixels
pixels = init()
collection = PatchCollection(pixels, match_original=True, animated=True)
ax.add_collection(collection)
def animate(index):
index_x, index_y = index // npx, index % npy
displayed[index_x, index_y] = [1, 0, 0, 1]
collection.set_facecolors(displayed.reshape(-1, 4))
return (collection,)
anim = animation.FuncAnimation(fig, animate,
frames=400,
interval=1,
blit=True,
repeat=False)
plt.show()
This is much faster, although I couldn't work out how to turn edges on or off so just disable for all rectangles.
I'm having issues with redrawing the figure here. I allow the user to specify the units in the time scale (x-axis) and then I recalculate and call this function plots(). I want the plot to simply update, not append another plot to the figure.
def plots():
global vlgaBuffSorted
cntr()
result = collections.defaultdict(list)
for d in vlgaBuffSorted:
result[d['event']].append(d)
result_list = result.values()
f = Figure()
graph1 = f.add_subplot(211)
graph2 = f.add_subplot(212,sharex=graph1)
for item in result_list:
tL = []
vgsL = []
vdsL = []
isubL = []
for dict in item:
tL.append(dict['time'])
vgsL.append(dict['vgs'])
vdsL.append(dict['vds'])
isubL.append(dict['isub'])
graph1.plot(tL,vdsL,'bo',label='a')
graph1.plot(tL,vgsL,'rp',label='b')
graph2.plot(tL,isubL,'b-',label='c')
plotCanvas = FigureCanvasTkAgg(f, pltFrame)
toolbar = NavigationToolbar2TkAgg(plotCanvas, pltFrame)
toolbar.pack(side=BOTTOM)
plotCanvas.get_tk_widget().pack(side=TOP)
You essentially have two options:
Do exactly what you're currently doing, but call graph1.clear() and graph2.clear() before replotting the data. This is the slowest, but most simplest and most robust option.
Instead of replotting, you can just update the data of the plot objects. You'll need to make some changes in your code, but this should be much, much faster than replotting things every time. However, the shape of the data that you're plotting can't change, and if the range of your data is changing, you'll need to manually reset the x and y axis limits.
To give an example of the second option:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 6*np.pi, 100)
y = np.sin(x)
# You probably won't need this if you're embedding things in a tkinter plot...
plt.ion()
fig = plt.figure()
ax = fig.add_subplot(111)
line1, = ax.plot(x, y, 'r-') # Returns a tuple of line objects, thus the comma
for phase in np.linspace(0, 10*np.pi, 500):
line1.set_ydata(np.sin(x + phase))
fig.canvas.draw()
fig.canvas.flush_events()
You can also do like the following:
This will draw a 10x1 random matrix data on the plot for 50 cycles of the for loop.
import matplotlib.pyplot as plt
import numpy as np
plt.ion()
for i in range(50):
y = np.random.random([10,1])
plt.plot(y)
plt.draw()
plt.pause(0.0001)
plt.clf()
This worked for me. Repeatedly calls a function updating the graph every time.
import matplotlib.pyplot as plt
import matplotlib.animation as anim
def plot_cont(fun, xmax):
y = []
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
def update(i):
yi = fun()
y.append(yi)
x = range(len(y))
ax.clear()
ax.plot(x, y)
print i, ': ', yi
a = anim.FuncAnimation(fig, update, frames=xmax, repeat=False)
plt.show()
"fun" is a function that returns an integer.
FuncAnimation will repeatedly call "update", it will do that "xmax" times.
This worked for me:
from matplotlib import pyplot as plt
from IPython.display import clear_output
import numpy as np
for i in range(50):
clear_output(wait=True)
y = np.random.random([10,1])
plt.plot(y)
plt.show()
I have released a package called python-drawnow that provides functionality to let a figure update, typically called within a for loop, similar to Matlab's drawnow.
An example usage:
from pylab import figure, plot, ion, linspace, arange, sin, pi
def draw_fig():
# can be arbitrarily complex; just to draw a figure
#figure() # don't call!
plot(t, x)
#show() # don't call!
N = 1e3
figure() # call here instead!
ion() # enable interactivity
t = linspace(0, 2*pi, num=N)
for i in arange(100):
x = sin(2 * pi * i**2 * t / 100.0)
drawnow(draw_fig)
This package works with any matplotlib figure and provides options to wait after each figure update or drop into the debugger.
In case anyone comes across this article looking for what I was looking for, I found examples at
How to visualize scalar 2D data with Matplotlib?
and
http://mri.brechmos.org/2009/07/automatically-update-a-figure-in-a-loop
(on web.archive.org)
then modified them to use imshow with an input stack of frames, instead of generating and using contours on the fly.
Starting with a 3D array of images of shape (nBins, nBins, nBins), called frames.
def animate_frames(frames):
nBins = frames.shape[0]
frame = frames[0]
tempCS1 = plt.imshow(frame, cmap=plt.cm.gray)
for k in range(nBins):
frame = frames[k]
tempCS1 = plt.imshow(frame, cmap=plt.cm.gray)
del tempCS1
fig.canvas.draw()
#time.sleep(1e-2) #unnecessary, but useful
fig.clf()
fig = plt.figure()
ax = fig.add_subplot(111)
win = fig.canvas.manager.window
fig.canvas.manager.window.after(100, animate_frames, frames)
I also found a much simpler way to go about this whole process, albeit less robust:
fig = plt.figure()
for k in range(nBins):
plt.clf()
plt.imshow(frames[k],cmap=plt.cm.gray)
fig.canvas.draw()
time.sleep(1e-6) #unnecessary, but useful
Note that both of these only seem to work with ipython --pylab=tk, a.k.a.backend = TkAgg
Thank you for the help with everything.
All of the above might be true, however for me "online-updating" of figures only works with some backends, specifically wx. You just might try to change to this, e.g. by starting ipython/pylab by ipython --pylab=wx! Good luck!
Based on the other answers, I wrapped the figure's update in a python decorator to separate the plot's update mechanism from the actual plot. This way, it is much easier to update any plot.
def plotlive(func):
plt.ion()
#functools.wraps(func)
def new_func(*args, **kwargs):
# Clear all axes in the current figure.
axes = plt.gcf().get_axes()
for axis in axes:
axis.cla()
# Call func to plot something
result = func(*args, **kwargs)
# Draw the plot
plt.draw()
plt.pause(0.01)
return result
return new_func
Usage example
And then you can use it like any other decorator.
#plotlive
def plot_something_live(ax, x, y):
ax.plot(x, y)
ax.set_ylim([0, 100])
The only constraint is that you have to create the figure before the loop:
fig, ax = plt.subplots()
for i in range(100):
x = np.arange(100)
y = np.full([100], fill_value=i)
plot_something_live(ax, x, y)