Consider the following code directly taken from the Matplotlib documentation:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import time # optional for testing only
import cv2 # optional for testing only
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()
This work fine on my system. Now, try to append the following piece of code to the above code:
while True:
#I have tried any of these 3 commands, without success:
pass
#time.sleep(1)
#cv2.waitKey(10)
What happens is that the program freezes. Apparently, the "Animation" class of Matplotlib runs the animation in a separate thread. So I have the 2 following questions:
1) If the process runs in a separate thread, why is it disturbed by the subsequent loop ?
2) How to say to python to wait until the animation has ended ?
interval: It is an optional integer value that represents the delay between each frame in milliseconds. Its default is 100. repeat_delay: It is an optional integer value that adds a delay in milliseconds before repeating the animation.
Alternatively you may stop the animation with anim. event_source. stop() . In order to have access to the animation inside the animating function one may use a class and make the animation a class variable.
The pause() function in pyplot module of matplotlib library is used to pause for interval seconds. Parameters: This method does not accepts any parameters.
For me, copying into ipython works as expected (animation plays first then the infinite loop) but when running the script it freezes.
1) I'm not sure exactly how cpython handles multi-threading, especially when combined with a particular matplotlib backend but it seems to be failing here. One possibility is to be explicit about how you want to use threads, by using
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import multiprocessing as mp
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,
#A function to set thread number 0 to animate and the rest to loop
def worker(num):
if num == 0:
ani = animation.FuncAnimation(fig, updatefig, interval=50, blit=True)
plt.show()
else:
while True:
print("in loop")
pass
return
# Create two threads
jobs = []
for i in range(2):
p = mp.Process(target=worker, args=(i,))
jobs.append(p)
p.start()
Which defines two threads and sets one to work on animation, one to loop.
2) To fix this, as suggested by @Mitesh Shah, you can use plt.show(block=True)
. For me, the script then behaves as expected with animation and then loop. Full code:
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)
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(block=True)
while True:
print("in loop")
pass
UPDATE: Alternative is to simply use interactive mode,
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig = plt.figure()
plt.ion()
plt.show()
def f(x, y):
return np.sin(x) + np.cos(y)
def updatefig(*args):
global x, 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))
for i in range(500):
x += np.pi / 15.
y += np.pi / 20.
im.set_array(f(x, y))
plt.draw()
plt.pause(0.0000001)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With