Is possible to animate pairs of images in a jupyter notebook?
With two lists of images:
greys = io.imread_collection(path_greys)
grdTru= io.imread_collection(path_grdTru)
The following naïve code fails to generate an animation:
for idx in range(1,900):
plt.subplot(121)
plt.imshow(greys[idx], interpolation='nearest', cmap=plt.cm.gray)
plt.subplot(122)
plt.imshow(grdTru[idx], interpolation='nearest', cmap=plt.cm.,vmin=0,vmax=3)
plt.show()
(It generates a list of subplots)
By the way,the example found in matplotlib doc failed if pasted in a notebook.
In order to make the example work in a jupyter notebook you need to include the
%matplotlib notebook
magic command.
import numpy as np
%matplotlib notebook
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig = plt.figure()
def f(x, y):
return np.sin(x) + np.cos(y)
x = np.linspace(0, 2 * np.pi, 120)
y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
im = plt.imshow(f(x, y), animated=True)
def updatefig(*args):
global x, y
x += np.pi / 15.
y += np.pi / 20.
im.set_array(f(x, y))
return im,
ani = animation.FuncAnimation(fig, updatefig, interval=50, blit=True)
plt.show()
You can then easily adapt it to your list of images.
From matplotlib version 2.1 on you also have the option to create a JavaScript animation inline.
from IPython.display import HTML
HTML(ani.to_jshtml())
Complete example:
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def f(x, y):
return np.sin(x) + np.cos(y)
x = np.linspace(0, 2 * np.pi, 120)
y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
im = plt.imshow(f(x, y), animated=True);
def updatefig(*args):
global x, y
x += np.pi / 15.
y += np.pi / 20.
im.set_array(f(x, y))
return im,
ani = animation.FuncAnimation(fig, updatefig, interval=50, blit=True)
from IPython.display import HTML
HTML(ani.to_jshtml())
Related
I can use the set_xdata and set_ydata functions to update an existing matplotlib plot. But after updating I want to recenter the plot so that all the points fall into the "view" of the plot.
In the below example, the y data keeps getting bigger but the zoom level of the plot remains same so the data points quickly get out of the scope.
import time
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.ion()
figure, ax = plt.subplots(figsize=(10, 8))
(line1,) = ax.plot(x, y)
plt.xlabel("X-axis")
plt.ylabel("Y-axis")
for i in range(1000):
new_y = np.sin(x - 0.5 * i) * i
line1.set_xdata(x)
line1.set_ydata(new_y)
figure.canvas.draw()
figure.canvas.flush_events()
time.sleep(0.1)
Adding ax.relim() and ax.autoscale() fixes the issue
import time
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.ion()
ax: plt.Axes
figure, ax = plt.subplots(figsize=(10, 8))
(line1,) = ax.plot(x, y)
ax.autoscale(True)
plt.xlabel("X-axis")
plt.ylabel("Y-axis")
for i in range(1000):
new_y = np.sin(x - 0.5 * i) * i
line1.set_xdata(x)
line1.set_ydata(new_y)
# Rescale axes limits
ax.relim()
ax.autoscale()
figure.canvas.draw()
figure.canvas.flush_events()
time.sleep(0.1)
np.sin(x - 0.5 * i) has multiplied by i, which can be 1000. One alternative is to make the y-axis have a limit greater than 1000. So, you can include plt.ylim([-1100,1100]):
import time
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.ion()
figure, ax = plt.subplots(figsize=(10, 8))
(line1,) = ax.plot(x, y)
plt.xlabel("X-axis")
plt.ylabel("Y-axis")
plt.ylim([-1100,1100])
for i in range(1000):
new_y = np.sin(x - 0.5 * i) * i
line1.set_xdata(x)
line1.set_ydata(new_y)
figure.canvas.draw()
figure.canvas.flush_events()
time.sleep(0.1)
I have written the following code with function animation with plot_surface which is not drawing, just giving the first picture
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
x = np.outer(np.linspace(-2, 2, 50), np.ones(50))
#print(x)
y = x.copy().T # transpose
fig = plt.figure()
ax = plt.axes(projection='3d')
def animation_frame(i):
z = np.cos(x ** 2 + y ** 2) + np.cos(x ** (2*i) + y ** (2*i))
# print (z)
ax.plot_surface(x, y, z,cmap='viridis', edgecolor='none')
# return ax,
animation = FuncAnimation(fig, func=animation_frame, frames=np.arange(0, 10, 1), interval=1000, blit=False)
#plt.show()
animation
You should call the plt.show() method at the end. Moreover, you should erase the previous plot with ax.cla() at the beginning of the animation_frame.
Whole code
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
x = np.outer(np.linspace(-2, 2, 50), np.ones(50))
y = x.copy().T
fig = plt.figure()
ax = plt.axes(projection = '3d')
def animation_frame(i):
ax.cla()
z = np.cos(x**2 + y**2) + np.cos(x**(2*i) + y**(2*i))
ax.plot_surface(x, y, z, cmap = 'viridis', edgecolor = 'none')
animation = FuncAnimation(fig, func = animation_frame, frames = np.arange(0, 10, 1), interval = 250, blit = False)
plt.show()
I'd like to be able to catch an error while plotting using the matplotlib animation function.
This is necessary for me as I have a program where it can happen that an error occurs in the updatefig function after a couple of loops. I'd like to then continue in the script to save all the data generated up to that point.
Instead of throwing an error, running the code below will just lead to the following output:
Process finished with exit code 1
I tried to put the try except clause at all positions I could think of but was never able to go to the last print().
See this MWE (taken from here):
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig = plt.figure()
def f(x, y):
return np.sin(x) + np.cos(y)
x = np.linspace(0, 2 * np.pi, 120)
y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
counter = 0
im = plt.imshow(f(x, y), animated=True)
def updatefig(*args):
global x, y, counter
x += np.pi / 15.
y += np.pi / 20.
im.set_array(f(x, y))
counter += 1
# do something that might fail at one point (and will fail in this example)
if counter > 10:
b = 0
print('bla ' + b) # error
return im,
ani = animation.FuncAnimation(fig, updatefig, interval=50, blit=True)
plt.show()
print('do other stuff now, e.g. save x and y')
There is an error because you are attempting to concatenate a string with an int:
Option 1:
correct the error:
import matplotlib
matplotlib.use('TkAgg')
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig = plt.figure()
def f(x, y):
return np.sin(x) + np.cos(y)
x = np.linspace(0, 2 * np.pi, 120)
y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
counter = 0
im = plt.imshow(f(x, y), animated=True)
def updatefig(*args):
global x, y, counter
x += np.pi / 15.
y += np.pi / 20.
im.set_array(f(x, y))
counter += 1
# do something that will not fail
if counter > 10:
b = 0
print('bla ' + str(b))
return im,
ani = animation.FuncAnimation(fig, updatefig, interval=50, blit=True)
plt.show()
print('do other stuff now, e.g. save x and y')
option 2:
catch the Error, save the data, and continue:
import matplotlib
matplotlib.use('TkAgg')
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig = plt.figure()
def f(x, y):
return np.sin(x) + np.cos(y)
x = np.linspace(0, 2 * np.pi, 120)
y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
counter = 0
im = plt.imshow(f(x, y), animated=True)
def save_if_error():
print('do other stuff now, e.g. save x and y')
def updatefig(*args):
global x, y, counter
x += np.pi / 15.
y += np.pi / 20.
im.set_array(f(x, y))
counter += 1
# do something that might fail at one point and catch the error, save the data and continue
if counter > 10:
b = 0
try:
print('bla ' + b) # error
except TypeError:
print("save the data here")
save_if_error()
return im,
ani = animation.FuncAnimation(fig, updatefig, interval=50, blit=True)
plt.show()
I am new to coding and have been trying to create an animation in python from a previously generated code in Octave (below). So far I have not had any success, besides plotting an unanimated scatter plot. Any tips or help would be greatly appreciated.
clear;
N = 100;
NT = 200;
for i=1:N
x(i) = 0;
y(i) = 0;
end
plot(x,y,'o');
axis([0 20 -10 10]);
for k = 1 : NT
x = x + normrnd(0.1,0.1,1,N);
y = y + normrnd(0,0.1,1,N);
temp = mod(k,1);
if temp == 0
plot(x,y,'s');
axis([0 20 -10 10]);
drawnow
end
end
Here is one of the many attempts that did not work (below).
import numpy as np
import matplotlib as plt
from pylab import *
from matplotlib import animation
import random
n=100
nt=2000
m=20
mu=0
sigma=0.1
p=100
fig = plt.figure()
ax = plt.axes(xlim=(-10, 10), ylim=(-10, 10))
scat, = ax.plot([], [])
# initialization function: plot the background of each frame
def init():
x = 0
y = 0
return scat,
# animation function. This is called sequentially
def animate(i):
for k in range (1,nt):
x = x+ np.random.normal(mu, sigma, n)
return scat,
for i in range (1,nt):
y = y+ np.random.normal(mu, sigma, n)
return scat,
anim = animation.FuncAnimation(fig, animate,
init_func=init,frames=200, interval=20, blit=True)
plt.show()
you could do the animation using Octave of Python.
For the python script I think that one of the problems was to set a return within a loop, therefore several times for one function def animate. Looking at the animation doc https://matplotlib.org/api/animation_api.html I edited your example and got this which I think might be usefull:
import numpy as np
import matplotlib.pyplot as plt
from pylab import *
from matplotlib.animation import FuncAnimation
import random
n=100
sigma=0.1
nt=2000
fig, ax = plt.subplots()
xdata, ydata = [0.0], [0.0]
ln, = plt.plot([], [], 'ro', animated=True)
def init():
ax.set_xlim( 0, 20)
ax.set_ylim(-10, 10)
return ln,
def update(frame):
global xdata
global ydata
xdata = xdata + np.random.normal(0.1, sigma, n)
ydata = ydata + np.random.normal(0.0, sigma, n)
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()
You could also do the animation using octaves print command to generate several pngs and use gimp to produce a gif or embbed in LaTeX the pngs using animate.
Best,
Jorge
I have a three-variable function myfunc that is generated inside three for loops. I want to draw a contour plot of y vs x and animate this for different times t. However, I've looked at the various matplotlib examples on the webpage, and am still unsure of how to do this.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import animation
def myfunc(x,y,t):
w = 0.5*x + y + 4*np.sin(1.8*t)
return w
xlist = np.linspace(0,10,10)
ylist = np.linspace(-1,1,10)
tlist = np.linspace(0,50,50)
plt.figure()
for t in tlist:
for x in xlist:
for y in ylist:
w = myfunc(x,y,t)
w_vec = np.array(w)
w_contour = w_vec.reshape((xlist.size, ylist.size))
w_plot = plt.contourf(ylist,xlist,w_contour)
plt.xlabel('x', fontsize=16)
plt.ylabel('y', fontsize=16)
plt.show()
Edit: I quite like the look of dynamic_image2.py in this tutorial. This seems to get things moving, but the axes are wrong:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig = plt.figure()
def f(x,y,t):
return 0.5*x + np.sin(y) + 4*np.sin(1.8*t)
x = np.linspace(0, 10, 10)
y = np.linspace(-1, 1, 10).reshape(-1, 1)
tlist = np.linspace(0,50,50)
ims = []
for t in tlist:
x += np.pi / 15.0
y += np.pi / 20.0
im = plt.imshow(f(x,y,t))
ims.append([im])
ani = animation.ArtistAnimation(fig, ims, interval=20, blit=True,
repeat_delay=1000)
plt.show()