I am trying to generate an animation of this plot with FuncAnimation. Those lines change over time, and that's what I would like to capture with FuncAnimation.
Currently, I can generate an animation, but one single line per subplot.
My code for animation roughly looks like this:
y1 = np.random.rand(1000, 5, 80)
y2 = np.random.rand(1000, 5, 80)
fig, axes = plt.subplots(1 ,2)
lines = []
x = np.linspace(0, 1, 1000)
for index, ax in enumerate(axes.flatten()):
if index == 0:
l, = ax.plot(y1[:,0,0], x)
if index == 1:
l, = ax.plot(y2[:,0,0], x)
lines.append(l)
def run(it):
for index, line in enumerate(lines):
if index == 0:
line.set_data(x, y1[:, 0, it]
if index == 1:
line.set_data(x, y2[:, 0, it]
return lines
ani = animation.FuncAnimation(fig, run, frames =80)
plt.show()
But, again, that code only generates only line per subplot. I'd like to have multiple lines per subplot (in the example code, that would be 5 lines). Does anyone know how do that? I don't have to use my code template, it could be something entirely different.
I've adapted the matplotlib animation example:
You can see which lines I've added/changed in the comments.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig, (ax, ax2) = plt.subplots(2) #create two axes
xdata, ydata = [], []
ln, = ax.plot([], [], 'ro')
ln2, = ax2.plot([], [], 'go') # added
def init():
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(-1, 1)
ax2.set_xlim(0, 2*np.pi) # added
ax2.set_ylim(-1, 1) # added
return ln,ln2 # added ln2
def update(frame):
xdata.append(frame)
ydata.append(np.sin(frame))
ln.set_data(xdata, ydata)
ln2.set_data(xdata, ydata) # added
return ln, ln2 #added ln2
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
init_func=init, blit=True)
plt.show()
Related
I have 35 different radial lines that I am displaying on a polar plot that I would like to animate as their angular dispersion increases. If I just want to animate one line I would do something like this:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
speed = 5.5
weight=0.5
angle=0
fig = plt.figure(figsize=(12, 12))
ax = plt.subplot(111, projection = 'polar')
ax.set_theta_direction(-1)
ax.set_theta_offset(np.pi / 2.0)
line, = ax.plot([0, angle], [0, speed],color='blue',linewidth=3,alpha=weight)
def animate(i):
angle=i*(np.pi/180)
new_datax = [0, angle]
lines.set_xdata(new_datax)
return lines,
anim = animation.FuncAnimation(fig, animate, frames=360, interval=20)
And that seems to spin round quite nicely! However if "speed, weight and angles" are arrays not just values how can I animate them all at once without having to do 35 different set_xdata? I know it's not like this!
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
speeds = np.array([5.5,5.5,5.1,5.5,5.6,5.7,5.8,6,6.5,7,7.5,8.5,9.5,11.5,17.5,23,26,29,32,27,22,14.5,9.5,6.3,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10,10])
weights = np.array([1,0.93,0.90,0.86,0.83,0.83,0.83,0.83,0.82,0.80,0.73,0.77,0.72,0.68,0.68,0.70,0.59,0.71,0.71,0.64,0.73,0.77,0.74,0.680.636977,0.59,0.54,0.53,0.51,0.48,0.46,0.40,0.44,0.38,0.36])
angles=np.linspace(0,0,35)*(np.pi/180)
fig = plt.figure(figsize=(12, 12))
ax = plt.subplot(111, projection = 'polar')
ax.set_theta_direction(-1)
ax.set_theta_offset(np.pi / 2.0)
for j in range (35):
lines, = ax.plot([0, angles[j]], [0, speeds[j]],color='blue',linewidth=3,alpha=weight3[j])
def animate(i):
angles=np.linspace(0,i,35)*(np.pi/180)
for j in range(35):
new_datax = [0, angles[j]]
lines.set_xdata(new_datax)
return lines,
anim = animation.FuncAnimation(fig, animate, frames=360, interval=20)
But I don't know how else to approach this problem! Any help would be greatly appreciated!
You need to keep track of all the line objects. Right now you're overwriting the lines object every time. Something like this should work:
lines = []
for j in range(35):
line, = ax.plot([0, angles[j]], [0, speeds[j]], color='blue', linewidth=3, alpha=weights[j])
lines.append(line)
def animate(i):
angles = np.linspace(0, i, 35) * (np.pi / 180)
for j in range(35):
new_datax = [0, angles[j]]
lines[j].set_xdata(new_datax)
return lines,
anim = animation.FuncAnimation(fig, animate, frames=360, interval=20)
When I remove linspace and plot points by typing them into a list by hand they are plotted just fine. However switch to linspace, and the points on the graph come up blank. What am I missing here? Printing the linspace lists show they are generating the values, but they don't seem to make the graph
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
%matplotlib qt
fig = plt.figure(figsize=(6,4))
axes = fig.add_subplot(1,1,1)
plt.title("Image That's Moving")
P=np.linspace(1,50,100)
T=np.linspace(1,50,100)
Position =[P]
Time = [T]
p2=[P]
t2=[T]
x,y=[],[]
x2,y2=[],[]
def animate(i):
x.append(Time[i])
y.append((Position[i]))
x2.append(t2[i])
y2.append((p2[i]))
plt.xlim(0,100)
plt.ylim(0,100)
plt.plot(x,y, color="blue")
plt.plot(x2,y2, color="red")
anim = FuncAnimation(fig, animate, interval=300)
It seems like you are facing a problem because of Position = [P] and Time = [T].
Because numpy.linspace already returns an array, you don't need additional [].
Here is a working example that is referenced from matplotlib tutorial.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
def init():
ax.set_xlim(0, 100)
ax.set_ylim(0, 100)
return ln,
def update(i):
xdata.append(T[i])
ydata.append(P[i])
ln.set_data(xdata, ydata)
return ln,
P = np.linspace(1, 50, 99)
T = np.linspace(1, 50, 99)
fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = plt.plot([], [], 'ro')
ani = FuncAnimation(fig, update, frames=np.arange(len(T)),
init_func=init, blit=True)
plt.show()
It is not as easy as your written code and, also, not related to np.linspace, AIK. Combining Choi answer (or matplotlib example) with another related SO post we can do this job using some code like:
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
def init():
ax1.set_xlim(0, 100)
ax1.set_ylim(0, 100)
ax2.set_xlim(0, 100)
ax2.set_ylim(0, 100)
return ln, ln2
def update(i, Position, Time, P2, T2, ln, ln2):
x.append(Time[i])
y.append(Position[i])
x2.append(T2[i] + 10)
y2.append(P2[i] + 10)
ln.set_data(x, y)
ln2.set_data(x2, y2)
return ln, ln2
Position = P2 = np.linspace(1, 50, 100)
Time = T2 = np.linspace(1, 50, 100)
fig = plt.figure(figsize=(6, 4))
plt.title("Image That's Moving")
plt.xticks([])
plt.yticks([])
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
x, y, x2, y2 = [], [], [], []
ln, = ax1.plot([], [], 'bo')
ln2, = ax2.plot([], [], 'ro')
ani = FuncAnimation(fig, update, frames=Time.shape[0], fargs=(Position, Time, P2, T2, ln, ln2), init_func=init, blit=True)
ani.save('test.gif', writer='imagemagick', fps=30)
I have an array x_trj that has shape (50,12), and I would like to make an animation for all the rows corresponding to certain columns in a 2-D plot (so I can see what direction each line is going). Below is my code:
from matplotlib.animation import FuncAnimation
fig,ax = plt.subplots()
# Plot initial line to fill in as we go
line, = ax.plot([], [], lw=2)
def init():
line.set_data([], [])
return line,
def animate(i):
# Plot resulting trajecotry of car
line.set_xdata(x_trj[i,0:9:4])
line.set_ydata(x_trj[i,1:10:4])
return line,
anim = FuncAnimation(fig, animate, init_func = init, frames=x_trj.shape[0], interval=200) # animation doesn't show up?
However, the animation does not show up at all. All I get is an empty figure. How should I fix this issue? I am writing my code in Google colab.
The animation shows up but it's empty (it has a built-in play button):
I don't know what values you have in x_traj but I had to set xlim, ylim to see animation because animation doesn't change visible area automatically and it displays line in area which I can see.
I tested it only on local computer.
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
np.random.seed(0) # `randint()` will always select the same values
x_trj = np.random.randint(0, 10, (52,12))
fig, ax = plt.subplots()
ax.set_xlim(0, 10) # it would need to get min(), max() values from x_trj
ax.set_ylim(0, 10) # it would need to get min(), max() values from x_trj
#ax = plt.axes(xlim=(0, 10), ylim=(0, 10)) # needs `ax =`
line, = ax.plot([], [], lw=2)
def init():
line.set_data([], [])
return line,
def animate(i):
print('i:', i)
x = x_trj[i,0:9:4]
y = x_trj[i,1:10:4]
print('x,y:', x, y)
line.set_xdata(x)
line.set_ydata(y)
return line,
anim = FuncAnimation(fig, animate, init_func=init, frames=x_trj.shape[0], interval=200)
plt.show()
Eventually you can change xlim, ylim during animation to change visible area but this may not look as you expect.
def animate(i):
print('i:', i)
x = x_trj[i,0:9:4]
y = x_trj[i,1:10:4]
print('x,y:', x, y)
line.set_xdata(x)
line.set_ydata(y)
ax.set_xlim(min(x), max(x)) # change visible are
ax.set_ylim(min(y), max(y)) # change visible are
return line,
EDIT
I will try to be more precise (above details have been removed because they are unnecessary):
I want to make an animation where a (red) ball departs from (0,0) and draws the function sin(x). The function has to be drawn in blue, and the leading point has to be red (just as seen on the above pic)
I have found a method to draw (animate) a function:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = plt.plot([], [], 'bo')
def init():
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(-1, 1)
return ln,
def update(frame):
xdata.append(frame)
ydata.append(np.sin(frame))
ln.set_data(xdata, ydata)
return ln,
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
init_func=init, blit=True)
plt.show()
My issue now is how to make the leading point red
I've been told that I should create an empty list of the line elements and use the "append()" method to add new line elements, but I still don't get how to do so.
Reference https://www.physicsforums.com/threads/how-to-make-an-animation-in-sympy-using-python.969906/
Thank you for your help.
Definitely, there are better ways:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
points = 50
x = np.linspace(0, 2 * np.pi, points)
y = np.sin(x)
fig, ax = plt.subplots()
ax.set_xlim(-0.3, 2 * np.pi + 0.3)
ax.set_ylim(-1.2, 1.2)
def animate(i):
if i == 0:
# fig.clear()
ax.plot(x[i], y[i], 'ro')
else:
# fig.clear()
ax.plot(x[i-1], y[i-1], 'bo')
ax.plot(x[i], y[i], 'ro')
anim = FuncAnimation(fig, animate, frames=points, repeat=False, interval=150)
plt.show()
I am trying to implement a live graph, however, my x and y axis are not showing up. Ive tried placing it in multiple areas of the code, however, none of those methods were successful.
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import style
style.use('fivethirtyeight')
fig = plt.figure()
plt.xlabel('Time (s)')
plt.ylabel('Temperature (F)')
plt.title("Your drink's current temperature")
plt.xlabel('xlabel', fontsize=10)
plt.ylabel('ylabel', fontsize=10)
ax1 = fig.add_subplot(1,1,1)
def animate(i):
plt.xlabel('xlabel', fontsize=10)
plt.ylabel('ylabel', fontsize=10)
graph_data = open('plot.txt', 'r').read()
lines = graph_data.split('\n')
xs = []
ys = []
for line in lines:
if len(line) > 1:
x, y = line.split(',')
xs.append(x)
ys.append(y)
ax1.clear()
ax1.plot(xs,ys)
ani = animation.FuncAnimation(fig, animate, interval=1000)
plt.show()
Here is the data file that I am reading from (plot.txt):
0,27.00
1,68.85
2,69.30
3,69.30
4,69.30
5,69.75
6,70.20
7,69.75
8,69.75
9,69.30
10,69.75
11,69.75
12,69.75
13,69.75
14,70.20
15,69.75
16,69.75
17,69.75
18,69.75
19,68.85
20,69.75
21,69.75
22,69.75
23,69.30
The problem is that you are calling clear in your animation function. You want to just update an existing artist (and let the animation code take care of re-drawing it as needed)
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as manimation
fig, ax = plt.subplots()
ax.set_xlabel('Time (s)')
ax.set_ylabel('Temperature (F)')
ax.set_title("Your drink's current temperature")
xs = np.linspace(0, 2*np.pi, 512)
ys = np.sin(xs)
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(-1, 1)
ln, = ax.plot([], [], lw=3)
def init(*args, **kwargs):
ln.set_data([], [])
return ln,
def animate(i):
ln.set_data(xs[:i], ys[:i])
return ln,
ani = manimation.FuncAnimation(fig, animate,
frames=512, blit=True,
init_func=init)
plt.show()
if you need to read in from another data source (ex, your file) just read it and then set the data on your line.