Matplotlib animation in for loop? - python

I'm trying to plot some data by animation in a for loop. I want it to wait until the animation is finished and then proceed in the for loop. Pause seems to work to allow this but sometimes the movies are very long and I want to close and move to the next one. Anybody know how I can achieve this?
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
import time
for j in range(0,2):
fig = plt.figure(j)
mngr = plt.get_current_fig_manager()
mngr.window.setGeometry(j*256,0,256, 256)
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], lw=2)
# initialization function: plot the background of each frame
def init():
line.set_data([], [])
return line,
# animation function. This is called sequentially
def animate(i):
x = np.linspace(0, 2, 1000)
y = np.sin(2 * np.pi * (x - 0.01 * i+j/4.))
line.set_data(x, y)
return line,
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=200, interval=20, blit=True,repeat=False)
plt.pause(0.02*200)
plt.show(block=True)

One way is to use a KeyboardInterrupt exception to move to the next plot.
For better readability, move your plotting into a function:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
import time
def animate_multi(j):
fig = plt.figure(j)
mngr = plt.get_current_fig_manager()
mngr.window.setGeometry(j*256,0,256, 256)
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], lw=2)
# initialization function: plot the background of each frame
def init():
line.set_data([], [])
return line,
# animation function. This is called sequentially
def animate(i):
x = np.linspace(0, 2, 1000)
y = np.sin(2 * np.pi * (x - 0.01 * i+j/4.))
line.set_data(x, y)
return line,
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=200, interval=20, blit=True,repeat=False)
plt.pause(0.02*200)
plt.close()
plt.show(block=True)
Now, in your loop except KeyboardInterrup and continue to the next animation:
for j in range(5):
try:
print('Working on plot', j)
animate_multi(j)
except KeyboardInterrupt:
plt.close()
Note: You might have to press <Ctrl>-<C> twice to skip to the next animation.

Related

Matplotlib animate plot - Figure not responding until loop is done

I am trying to animate a plot where my two vectors X,Y are updating through a loop.
I am using FuncAnimation. The problem I am running into is the Figure would show Not Responding or Blank until the loop is completed.
So during the loop, I would get something like:
But if I stopped the loop or at the end, the figure would appear.
I have set my graphics backend to automatic.
Here is the example of the code:
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
def animate( intermediate_values):
x = [i for i in range(len(intermediate_values))]
y = intermediate_values
plt.cla()
plt.plot(x,y, label = '...')
plt.legend(loc = 'upper left')
plt.tight_layout()
x = []
y = []
#plt.ion()
for i in range(50):
x.append(i)
y.append(i)
ani = FuncAnimation(plt.gcf(), animate(y), interval = 50)
plt.tight_layout()
#plt.ioff()
plt.show()
The structure of animation in matplotlib is that the animation function is not used in the loop process, but the animation function is the loop process. After setting up the initial graph, the animation function will update the data.
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
x = []
y = []
fig = plt.figure()
ax = plt.axes(xlim=(0,50), ylim=(0, 50))
line, = ax.plot([], [], 'b-', lw=3, label='...')
ax.legend(loc='upper left')
def animate(i):
x.append(i)
y.append(i)
line.set_data(x, y)
return line,
ani = FuncAnimation(fig, animate, frames=50, interval=50, repeat=False)
plt.show()

How do I create a matplotlib animation with multiple animated functions

I am trying to create an animation of growing concentric circles in python. As the program runs, more circles should generate from the centre and grow outwards
Right now I have this, which just creates one expanding circle.
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
ax = plt.axes(xlim=(0, 128), ylim=(0, 128))
line, = ax.plot([], [], lw=2)
def init():
line.set_data([], [])
return line,
def animate(i):
theta = np.linspace(0, 2 * np.pi, 100)
r = np.sqrt(i)
x = r * np.cos(theta) + 64
y = r * np.sin(theta) + 64
line.set_data(x, y)
return line,
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=1000, interval=10, blit=True)
plt.gca().set_aspect('equal', adjustable='box')
plt.show()
How do I modify my code so that new growing circles generate from the middle to create growing concentric circles.
You can keep a list of lines, and add a new one every few frames with a smaller radius
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
ax = plt.axes(xlim=(0, 128), ylim=(0, 128))
# Keep a list of lines instead of a single one
lines = ax.plot([], [], lw=2)
def init():
for line in lines:
line.set_data([], [])
return lines
def animate(i):
# Add a new line every 100 frames
if i // 100 >= len(lines):
new_line, = ax.plot([], [], lw=2)
lines.append(new_line)
for line_num, line in enumerate(lines):
theta = np.linspace(0, 2 * np.pi, 100)
# Reduce the radius of the new lines
r = np.sqrt(i - 100 * line_num)
x = r * np.cos(theta) + 64
y = r * np.sin(theta) + 64
line.set_data(x, y)
return lines
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=1000, interval=10, blit=True)
plt.gca().set_aspect('equal', adjustable='box')
plt.show()

Time dependent plot matplotlib

I would like to plot point-by-point a sine wave in Python via Matplotlib, for which, each point, is added every x milliseconds, in order to obtain a smooth animation of the drawing.
This is my attempt:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from math import sin
fig, ax = plt.subplots()
x = [0]
line, = ax.plot(x, np.asarray(0))
def animate(i):
x.append(x[-1]+0.04)
line.set_xdata(np.asarray(x)*2*np.pi/5)
line.set_ydata(np.sin(np.asarray(x)*2*np.pi/5))
plt.draw()
def init():
line.set_ydata(np.ma.array(x, mask=True))
return line,
ani = animation.FuncAnimation(fig, animate, 10, init_func=init, interval=40, blit=True)
plt.show()
Which raises:
RuntimeError: The animation function must return a sequence of Artist objects.
What did I mistaken? What is, in your opinion, the most efficient way to obtain this effect?
PS The time axis should stay fixed and not move, so it should be wider than the plot
Firstly you are getting the error because your animate(i) is not returning anything. You need to return line,. Secondly you are not using the iin animate(i) aswell.
Here is a simple sine curve animation from https://jakevdp.github.io/blog/2012/08/18/matplotlib-animation-tutorial/:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
# First set up the figure, the axis, and the plot element we want to
animate
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], lw=2)
# initialization function: plot the background of each frame
def init():
line.set_data([], [])
return line,
# animation function. This is called sequentially
def animate(i):
x = np.linspace(0, 2, 1000)
y = np.sin(2 * np.pi * (x - 0.01 * i))
line.set_data(x, y)
return line,
# call the animator. blit=True means only re-draw the parts that have
changed.
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=200, interval=20, blit=True)
plt.show()
There is additional inspiration in the link which might help you further.
Animate should return a sequence of artist objects:
You should add:
return line, to the end of the animate function
def animate(i):
x.append(x[-1]+0.04)
line.set_xdata(np.asarray(x)*2*np.pi/5)
line.set_ydata(np.sin(np.asarray(x)*2*np.pi/5))
return line,
Source:
Another answer
Simple Example

How do I get a fill_between shape in Funcanimation?

I would like to make a moving plot where the area under the curve gets colored while the curve is getting plotted.
I have googled a bit and found that I should somehow create a patch. However, I do not understand any of the examples they give, so let me ask it here with my specific example:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
import pylab as p
data = np.loadtext('datafile.dat', delimiter=',')
A = data[:,1]
B = data[:,2]
fig = plt.figure(figsize=(25,5), dpi=80)
ax = plt.axes(xlim=(0, 3.428), ylim=(-1,1))
line, = ax.plot([], [], lw=5)
def init():
line.set_data([], [])
return line,
def animate(i):
x = A[0:(i-1)*400]
y = B[0:(i-1)*400]
line.set_data(x,y)
# Here is the problem. I would now like to add the following line
# p.fill_between(x, 0, y, facecolor = 'C0', alpha = 0.2)
return line,
anim = animation.FuncAnimation(fig,animate, init_func=init, frames = 857, interval=20, blit=True)
I hope someone can give me a solution for my problem or at least point me in the correct direction.
So my question would be: how can I add the commented part without any errors?
Assuming you want blit = True, you will need to return the patch produced by fill_between as well.
p = plt.fill_between(x, y, 0)
return line, p,
Complete working example:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
X = np.linspace(0,3.428, num=250)
Y = np.sin(X*3)
fig = plt.figure(figsize=(13,5), dpi=80)
ax = plt.axes(xlim=(0, 3.428), ylim=(-1,1))
line, = ax.plot([], [], lw=5)
def init():
line.set_data([], [])
return line,
def animate(i):
x = X[0:(i-1)]
y = Y[0:(i-1)]
line.set_data(x,y)
p = plt.fill_between(x, y, 0, facecolor = 'C0', alpha = 0.2)
return line, p,
anim = animation.FuncAnimation(fig,animate, init_func=init,
frames = 250, interval=20, blit=True)
plt.show()

Matplotlib animation not working

I cannot run matplotlib animations using anaconda. I’m trying to run this on Spyder:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], lw=2)
# initialization function: plot the background of each frame
def init():
line.set_data([], [])
return line,
# animation function. This is called sequentially
def animate(i):
x = np.linspace(0, 2, 1000)
y = np.sin(2 * np.pi * (x - 0.01 * i))
line.set_data(x, y)
return line,
# call the animator. blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=200, interval=20, blit=True)
plt.show()
But it gives me a blank plot. I'm using this directly off of the documentation website as an example and it is not working.
I think you're using Pycharm which have some bug.
you need to toggle off scientific mode off in preference->tools->python scientific-> show plots in tool window.
and add
%matplotlib qt5
before drawing

Categories