请考虑直接从Matplotlib文档中获取的以下代码:
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,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()
这在我的系统上工作正常.现在,尝试将以下代码附加到上面的代码中:
while True: #I have tried any of these 3 commands,without success: pass #time.sleep(1) #cv2.waitKey(10)
结果是该程序冻结了.显然,Matplotlib的“Animation”类在一个单独的线程中运行动画.所以我有以下两个问题:
1)如果进程在一个单独的线程中运行,为什么它会受到后续循环的干扰?
2)如何对python说等到动画结束?
解决方法
对我来说,复制到ipython按预期工作(动画首先播放然后是无限循环)但是在运行脚本时它会冻结.
1)我不确定cpython究竟是如何处理多线程的,特别是当与特定的matplotlib后端结合使用时,它似乎在这里失败了.一种可能性是通过使用来明确你想如何使用线程
import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation import multiprocessing as mp fig = plt.figure() def f(x,#A function to set thread number 0 to animate and the rest to loop def worker(num): if num == 0: ani = animation.FuncAnimation(fig,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()
它定义了两个线程并设置一个用于动画,一个用于循环.
2)为了解决这个问题,正如@Mitesh Shah所建议的那样,你可以使用plt.show(block = True).对我来说,脚本然后按照预期的方式运行动画然后循环.完整代码:
import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation fig = plt.figure() def f(x,blit=True) plt.show(block=True) while True: print("in loop") pass
更新:替代方案是简单地使用交互模式,
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,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)