如何阻止matplotlib GUI线程冻结?

时间:2011-08-01 08:17:38

标签: python multithreading user-interface matplotlib

from matplotlib import pyplot as p
from scipy import zeros
from Queue import Queue
import random

w,h = 320,200

black = zeros((h,w,3), dtype='uint8')
red = black.copy(); red[:,:,0] = 255
green = black.copy(); green[:,:,1] = 255
blue = black.copy(); blue[:,:,2] = 255

def ants():
  from scipy import rand, dstack
  return dstack([(255*rand(h,w)).astype('uint8')]*3)

fig = p.figure()
axs = [fig.add_subplot(1,3,i) for i in xrange(3)]
[ax.imshow(black) for ax in axs]

q = Queue()

def update_image(ax):
  ## this takes some time
  import time
  time.sleep(3)
  ax.images[0].set_data(random.choice([red, green, blue]))

def hit(event):
  if event.inaxes in axs:
    update_axs = [event.inaxes]
  else:
    update_axs = axs
  for ax in update_axs:
    ax.images[0].set_data(ants())
  p.draw()
#  for ax in update_axs:
#    update_image(ax)
#  p.draw()

cid = fig.canvas.mpl_connect('button_press_event', hit)
p.show()

这是我的代码,所有代码都按预期工作。但是,当我在事件处理程序中取消注释这3行时,有一些我没想到的问题。首先,当update_image正在工作时,GUI会冻结,其次第一次调用draw()似乎没有机会画画,因为我在{{1}时没有看到蚂蚁} 工作中。什么是在matplotlib中设置此类事物的更好方法,以便它可以顺利运行?

1 个答案:

答案 0 :(得分:2)

为避免冻结GUI,您需要在单独的线程或进程中运行update_image。使用threading,您可以执行以下操作:

import matplotlib
matplotlib.use('TkAgg')
from matplotlib import pyplot as p
from scipy import zeros
import random
import threading


w,h = 320,200

black = zeros((h,w,3), dtype='uint8')
red = black.copy(); red[:,:,0] = 255
green = black.copy(); green[:,:,1] = 255
blue = black.copy(); blue[:,:,2] = 255

def ants():
    from scipy import rand, dstack
    return dstack([(255*rand(h,w)).astype('uint8')]*3)

fig = p.figure()
axs = [fig.add_subplot(1,3,i) for i in xrange(3)]
[ax.imshow(black) for ax in axs]

def update_image(ax):
    ## this takes some time
    import time
    time.sleep(3)
    ax.images[0].set_data(random.choice([red, green, blue]))
    ax.figure.canvas.draw()

def hit(event):
    if event.inaxes in axs:
        update_axs = [event.inaxes]
    else:
        update_axs = axs
    for ax in update_axs:
        ax.images[0].set_data(ants())
    p.draw()
    for ax in update_axs:
        t=threading.Thread(target=update_image,args=(ax,))
        t.daemon=True
        t.start()

cid = fig.canvas.mpl_connect('button_press_event', hit)
p.show()