FuncAnimation with numpy array is not updated - python

Working example:
import numpy as np
import matplotlib as mpl
mpl.use("TKAgg")
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def animate(i, line, xs, ys):
ys.append(i)
ys = ys[-10:]
line.set_data(xs, ys)
return line,
fig = plt.figure()
ax = plt.axes(xlim=(0, 10), ylim=(0, 200))
line, = ax.plot([], [], lw=2)
xs = [val for val in range(10)]
ys = [0 for _ in range(10)]
anim = animation.FuncAnimation(fig, animate, fargs=(line, xs, ys), interval=10, blit=True)
Not working:
def animate(i, line, npx, npy):
npy = np.roll(npy, -1)
npy[-1] = i
line.set_data(npx, npy)
return line,
fig = plt.figure()
ax = plt.axes(xlim=(0, 10), ylim=(0, 200))
line, = ax.plot([], [], lw=2)
npx = np.linspace(0, 9, 10)
npy = np.zeros(10)
anim = animation.FuncAnimation(fig, animate, fargs=(line, npx, npy), interval=10, blit=True)
I tested this:
for i in range(10):
npy = np.roll(npy, -1)
npy[-1] = i
and it shows an array with the values as expected.
It's like npy is passed by value because at each iteration it resets to an array of zeroes as only the last value is non-zero. I don't understand why it works using a list and not a numpy array.
Edit: managed to make it "work" using this approach:
def animate(i, line, x):
y = line.get_ydata(orig=True)
y = np.roll(y, -1)
y[-1] = np.cos(np.pi*i*.1)
line.set_data(x, y)
return line,
fig = plt.figure()
ax = plt.axes(xlim=(0, 100), ylim=(-2, 2))
xs = [val for val in range(100)]
ys = np.zeros(100)
line, = ax.plot(xs, ys, lw=2)
anim = animation.FuncAnimation(fig, animate, fargs=(line, xs, ys), interval=10, blit=True)

Related

Why does my graph not plot the points generated by linspace? (animation)

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)

Generating multiple lines with subplot and FuncAnimation

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

TypeError: 'MovieWriterRegistry' object is not an iterator

I was trying to create an animation of a sin wave using the FuncAnimation function from matplotlib, but it keeps throwing an error. I am a little new to it, but I read that there is a bug in the latest version? Anyone that can help me is welcome.
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
plt.style.use('seaborn-pastel')
fig = plt.figure()
ax = plt.axes(xlim=(0, 4), ylim=(-2, 2))
line, = ax.plot([], [], lw=3)
def init():
line.set_data([], [])
return line,
def animate(i):
x = np.linspace(0, 4, 1000)
y = np.sin(2 * np.pi * (x - 0.01 * i))
line.set_data(x, y)
return line,
anim = FuncAnimation(fig, animate, init_func=init,
frames=200, interval=20, blit=True)
anim.save('sine_wave.gif', writer='imagemagick')

Plotting animations to Jupyter Notebook: why does HTML(animator.to_html()) not work when called in an inner scope (i.e in a function)?

The following source shows how to plot animations inline to Jupyter Notebook (with matplotlib of course):
http://louistiao.me/posts/notebooks/embedding-matplotlib-animations-in-jupyter-as-interactive-javascript-widgets/
Running the code, it works when I run it directly in a cell (i.e like a script):
from matplotlib import animation, rc
from IPython.display import HTML
fig, ax = plt.subplots()
ax.set_xlim((0, 2))
ax.set_ylim((-2, 2))
line, = ax.plot([], [], lw=2)
def init():
line.set_data([], [])
return (line,)
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,)
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=100, interval=20,
blit=True)
#HTML(anim.to_html5_video())
HTML(anim.to_jshtml())
However, when I try to run this within a function, it does not plot an inline figure:
from matplotlib import animation, rc
from IPython.display import HTML
def plot_anim_funct():
fig, ax = plt.subplots()
ax.set_xlim((0, 2))
ax.set_ylim((-2, 2))
line, = ax.plot([], [], lw=2)
def init():
line.set_data([], [])
return (line,)
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,)
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=100, interval=20,
blit=True)
#HTML(anim.to_html5_video())
HTML(anim.to_jshtml())
plot_anim_funct()
It doesn't plot anything actually (well there is a static non-animated figure, but that always shows up, I think from running anim = animation.FuncAnimation(fig, animate, init_func=init, frames=100, interval=20, blit=True).
Of course, returning the animator object from the function, and then running HTML(anim.to_jshtml()) works as before.
Is there a way to get this working inside a function or do I just need to return the animator every time?
HTML(..) creates a html string from an object. If this is not the last line of the cell it will not be shown. To be on the safe side, you may use IPython.display.display
display(HTML(anim.to_jshtml()))
Complete working code:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation, rc
from IPython.display import HTML, display
def plot_anim_funct():
fig, ax = plt.subplots()
ax.set_xlim((0, 2))
ax.set_ylim((-2, 2))
line, = ax.plot([], [], lw=2)
def init():
line.set_data([], [])
return (line,)
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,)
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=100, interval=20,
blit=True)
display(HTML(anim.to_jshtml()))
plot_anim_funct()

How do I show x and y labels to a live graph in Python?

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.

Categories

Resources