I am trying to do an animation using the FuncAnimation module, but my code only produces one frame and then stops. It seems like it doesn't realize what it needs to update. Can you help me what went wrong?
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
x = np.linspace(0,2*np.pi,100)
def animate(i):
PLOT.set_data(x[i], np.sin(x[i]))
print("test")
return PLOT,
fig = plt.figure()
sub = fig.add_subplot(111, xlim=(x[0], x[-1]), ylim=(-1, 1))
PLOT, = sub.plot([],[])
animation.FuncAnimation(fig, animate, frames=len(x), interval=10, blit=True)
plt.show()
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
x = np.linspace(0,2*np.pi,100)
fig = plt.figure()
sub = fig.add_subplot(111, xlim=(x[0], x[-1]), ylim=(-1, 1))
PLOT, = sub.plot([],[])
def animate(i):
PLOT.set_data(x[:i], np.sin(x[:i]))
# print("test")
return PLOT,
ani = animation.FuncAnimation(fig, animate, frames=len(x), interval=10, blit=True)
plt.show()
You need to keep a reference to the animation object around, otherwise it gets garbage collected and it's timer goes away.
There is an open issue to attach a hard-ref to the animation to the underlying Figure object.
As written, your code well only plot a single point which won't be visible, I changed it a bit to draw up to current index
Related
Good day !
Problem explanation:
I want to animate a Polygon which values I receive from an array (in my simple example it is a moving sqaure). I want to keep the Polygon's x-and y-values mutable. Dont worry about what movement the Polygon does. It is just an example. Working with "set_xy()" like in the solution from 'animation to translate polygon using matplotlib' is wanted.
Goal -> in every animation frame I want to load the Polygon values from the arrays (P1x,P1y,P2x,P2y,...) and update the figure.
Question:
In my code I still have problems to work with the patches. I'm trying to update the Polygon values with the index i. How do I have to define the patch? Does this have to be done bevor the animation call?
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation
import matplotlib.patches as patches
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_xlim(-10,10)
ax.set_ylim(-10,10)
P1x=[0.0,0.5,1.0,1.5,2.0,2.5,3.0]
P1y=[0.0,0.0,0.0,0.0,0.0,0.0,0.0]
P2x=[1.0,1.5,2.0,2.5,3.0,3.5,4.0]
P2y=[0.0,0.0,0.0,0.0,0.0,0.0,0.0]
P3x=[1.0,1.5,2.0,2.5,3.0,3.5,4.0]
P3y=[1.0,1.0,1.0,1.0,1.0,1.0,1.0]
P4x=[0.0,0.5,1.0,1.5,2.0,2.5,3.0]
P4y=[1.0,1.0,1.0,1.0,1.0,1.0,1.0]
def init():
return patch,
def animate(i):
v = np.array([
[P1x[i], P1y[i]],
[P2x[i], P2y[i]],
[P3x[i], P3y[i]],
[P4x[i], P4y[i]]
])
patch=patches.Polygon(v,closed=True, fc='r', ec='r')
return patch,
ani = animation.FuncAnimation(fig, animate, np.arange(1, 5), init_func=init,
interval=1000, blit=True)
plt.show()
Thanks a lot for your help!
Yes, you will need to create the Polygon first and add it to the axes. Inside the animating function you may use the patch's patch.set_xy() method to update the vertices of the polygon.
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation
import matplotlib.patches as patches
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_xlim(-10,10)
ax.set_ylim(-10,10)
P1x=[0.0,0.5,1.0,1.5,2.0,2.5,3.0]
P1y=[0.0,0.0,0.0,0.0,0.0,0.0,0.0]
P2x=[1.0,1.5,2.0,2.5,3.0,3.5,4.0]
P2y=[0.0,0.0,0.0,0.0,0.0,0.0,0.0]
P3x=[1.0,1.5,2.0,2.5,3.0,3.5,4.0]
P3y=[1.0,1.0,1.0,1.0,1.0,1.0,1.0]
P4x=[0.0,0.5,1.0,1.5,2.0,2.5,3.0]
P4y=[1.0,1.0,1.0,1.0,1.0,1.0,1.0]
P = np.concatenate((np.array([P1x, P2x, P3x, P4x]).reshape(4,1,len(P1x)),
np.array([P1y, P2y, P3y, P4y]).reshape(4,1,len(P1x))), axis=1)
patch = patches.Polygon(P[:,:,0],closed=True, fc='r', ec='r')
ax.add_patch(patch)
def init():
return patch,
def animate(i):
patch.set_xy(P[:,:,i])
return patch,
ani = animation.FuncAnimation(fig, animate, np.arange(P.shape[2]), init_func=init,
interval=1000, blit=True)
plt.show()
I tried using matplotlib's ArtistAnimation. The text and titles of the figure are supposed to change in each frame, but they don't.
I have read tons of posts on similar problems, but I still don't understand what is the solution. The demos don't show updating titles as far as I could find.
If anybody out there knows, I would be grateful!
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation
fig =plt.figure()
ims=[]
for iternum in range(4):
plt.title(iternum)
plt.text(iternum,iternum,iternum)
ims.append([plt.scatter(np.random.randint(0,10,5), np.random.randint(0,20,5),marker='+' )])
#plt.cla()
ani = animation.ArtistAnimation(fig, ims, interval=500, blit=False,
repeat_delay=2000)
plt.show()
To animate artists, you have to return a reference to each artists in your ims[] array, including the Text objects.
However it doesn't work for the title, I don't know why. Maybe somebody with a better understanding of the mechanisms involved will be able to enlighten us.
Nevertheless, the title is just a Text object, so we can produce the desired effect using:
fig = plt.figure()
ax = fig.add_subplot(111)
ims=[]
for iternum in range(4):
ttl = plt.text(0.5, 1.01, iternum, horizontalalignment='center', verticalalignment='bottom', transform=ax.transAxes)
txt = plt.text(iternum,iternum,iternum)
ims.append([plt.scatter(np.random.randint(0,10,5), np.random.randint(0,20,5),marker='+' ), ttl, txt])
#plt.cla()
ani = animation.ArtistAnimation(fig, ims, interval=500, blit=False,
repeat_delay=2000)
You need to supply the artists to animate as a list of sequences to the ArtistAnimation. In the code from the question you only supply the scatter, but not the text and title.
Unfortunately the title is also part of the axes and thus will not change even if supplied. So you may use a normal text instead.
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation
fig, ax = plt.subplots()
ims=[]
for iternum in range(4):
title = plt.text(0.5,1.01,iternum, ha="center",va="bottom",color=np.random.rand(3),
transform=ax.transAxes, fontsize="large")
text = ax.text(iternum,iternum,iternum)
scatter = ax.scatter(np.random.randint(0,10,5), np.random.randint(0,20,5),marker='+')
ims.append([text,scatter,title,])
ani = animation.ArtistAnimation(fig, ims, interval=500, blit=False,
repeat_delay=2000)
plt.show()
You may consider using FuncAnimation instead of ArtistAnimation. This would allow to change the title easily.
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation
fig, ax = plt.subplots()
ims=[]
text = ax.text(0,0,0)
scatter = ax.scatter(np.random.randint(0,10,5), np.random.randint(0,20,5),marker='+')
def update(iternum):
plt.title(iternum)
text.set_position((iternum, iternum))
text.set_text(str(iternum))
scatter.set_offsets(np.random.randint(0,10,(5,2)))
ani = animation.FuncAnimation(fig, update, frames=4, interval=500, blit=False,
repeat_delay=2000)
plt.show()
I want to create a matplotlib animation, but instead of having matplotlib call me I want to call matplotlib. For example I want to do this:
from random import random
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
def update(frame):
plt.scatter(random(),random())
fig, ax = plt.subplots()
ani = FuncAnimation(fig, update, interval=340, repeat=True)
ani.save("my.mov", "avconv")
Like this:
def update():
plt.scatter(random(),random())
fig, ax = plt.subplots()
ani = MadeUpSubClassPassiveAnimation(fig)
while True:
update()
ani.update()
# do other stuff ...
ani.save("my.mov", "avconv")
I realize I could drive a live plot like this:
def update():
plt.scatter(x, y)
plt.pause(0.01)
fig, ax = plt.subplots()
plt.ion()
while True:
update()
time.sleep(1)
But AFAIK I need to use Animation for the save() functionality. So, is it possible to drive Animation rather than have it drive me? If so how?
An Animation is run when being saved. This means that the animation needs to reproducibly give the same result when being run twice (once for saving, once for showing). In other words, the animation needs to be defined in terms of successive frames. With this requirement, any animation can be constructed using a callback on either a function (FuncAnimation) or on a list of frames (ArtistAnimation).
The example from the question could be done with an ArtistAnimation (in order not to have different random numbers for the saved and the shown animation, respectively):
from random import random
import matplotlib.animation
import matplotlib.pyplot as plt
def update(frame: int) -> list[matplotlib.artist.Artist]:
sc = ax.scatter(random(), random())
return [sc]
fig, ax = plt.subplots()
artists = []
for i in range(10):
sc = update(i)
artists.append(sc)
# If you want previous plots to be present in all frames, add:
# artists = [[j[0] for j in artists[:i+1]] for i in range(len(artists))]
ani = matplotlib.animation.ArtistAnimation(fig, artists, interval=100)
ani.save(__file__ + ".gif", writer="imagemagick")
plt.show()
I am trying to do an animation using the FuncAnimation module, but my code only produces one frame and then stops. It seems like it doesn't realize what it needs to update. Can you help me what went wrong?
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
x = np.linspace(0,2*np.pi,100)
def animate(i):
PLOT.set_data(x[i], np.sin(x[i]))
print("test")
return PLOT,
fig = plt.figure()
sub = fig.add_subplot(111, xlim=(x[0], x[-1]), ylim=(-1, 1))
PLOT, = sub.plot([],[])
animation.FuncAnimation(fig, animate, frames=len(x), interval=10, blit=True)
plt.show()
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
x = np.linspace(0,2*np.pi,100)
fig = plt.figure()
sub = fig.add_subplot(111, xlim=(x[0], x[-1]), ylim=(-1, 1))
PLOT, = sub.plot([],[])
def animate(i):
PLOT.set_data(x[:i], np.sin(x[:i]))
# print("test")
return PLOT,
ani = animation.FuncAnimation(fig, animate, frames=len(x), interval=10, blit=True)
plt.show()
You need to keep a reference to the animation object around, otherwise it gets garbage collected and it's timer goes away.
There is an open issue to attach a hard-ref to the animation to the underlying Figure object.
As written, your code well only plot a single point which won't be visible, I changed it a bit to draw up to current index
im new in here and new in python, im doing some animations with animation.FuncAnimation of matplotliib. The animation works perfectly but i´m having problems saving the animations. here is the part of the code of the animation.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig, ax = plt.subplots()
line, = ax.plot(range(N),sin(x[0,:]),'o-')
ax.axis([0,1,-1,1])
def animate(i):
line.set_ydata(sin(x[i,:])) # update the data
return line,
def init():
line.set_ydata(np.ma.array(x[0,:], mask=True))
return line,
ani = animation.FuncAnimation(fig, animate, np.arange(1, 10000),
interval=25, init_func=init, blit=True)
ani.save('2osc.mp4', writer="ffmpeg")
plt.show()
where x[:,:] is previously set. ani.save is saving every frame of the animation as a .npg image instade of saving the movie. I dont know if this is how it is suposed to work and i have to do the movie with the .npg with another program or if im doing something wrong.
Obs: i've previously installed ffmpeg and it seems to be working just fine.
For me this code seems to be running fine:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig, ax = plt.subplots(1,1)
x=np.linspace(np.pi,4*np.pi,100)
N=len(x)
ax.set_xlim(len(x))
ax.set_ylim(-1.5,1.5)
line, = ax.plot([],[],'o-')
def init():
line.set_ydata(np.ma.array(x[:], mask=True))
return line,
def animate(i, *args, **kwargs):
y=np.sin(x*i)
line.set_data(np.arange(N),y) # update the data
return line,
ani = animation.FuncAnimation(fig, animate, init_func=init,
frames=100, interval=10, blit= False, repeat = False)
ani.save('2osc.mp4', writer="ffmpeg")
fig.show()
You can install the ffmpeg library by using:
sudo apt-get install ffmpeg