运行实时matplotlib draw()函数时,wxpython接口无响应

时间:2014-07-10 18:29:24

标签: python multithreading matplotlib wxpython python-multithreading

所以我使用wxpython为程序制作GUI。我也在这个程序中嵌入了matplotlib图。

我的问题是当我尝试使用draw()连续更新绘图时,我的程序变得不负责任,但matplotlib图仍在更新。

以下是我的代码的一部分,以及我如何执行所有这些,

def update(self, e):
    if self.liveMode:
        self.tune.plot();  # new plot
    self.canvas.draw();
    self.startLive(e);

def startLive(self, e):
    self.liveMode = False;
    refFreq = 500e6 / 80;
    qx = self.pv1.get();
    qy = self.pv2.get();
    self.tune.newWorkingpoint(refFreq/qx, refFreq/qy);
    self.tune.liveUpdate();
    time.sleep(0.3);
    self.update(e);

当我的程序中按下“实时模式”按钮时,会调用“更新”方法。 我绘制所有背景线,然后从其他地方重复获取新的点值,并将其绘制为图形上的圆圈,并使用draw()方法进行更新。当然,因为我基本上处于一个连续的循环中,所以在此过程完成之前没有其他任何工作。我的目标是只需要一个“停止”按钮来停止这个实时绘图循环,但是因为当matplotlib绘图时一切都变得没有响应,所以没有按钮可点击,我必须停止编译以停止程序。

这周围有吗?我已经研究过线程,但是我遇到了同样的问题。

编辑:--------------------------------------------- -------------------------------------------------- -----------------------------我使用this页面作为指南。但是,几秒钟后我得到了这个致命的错误,我的程序崩溃了。 'python2.7:X服务器上的致命IO错误11(资源暂时不可用):0.0。'

这是我实施的方法。按下开始按钮时,“startlive”开始,按下停止按钮时,“stoplive”开始。一切正常,我的matplotlib图表得到了正确更新,而我的wxpython GUI没有响应。

问题是几秒钟后我收到了致命错误,我的程序崩溃了。我相信这很可能与在线程中更新matplotlib的canvas.draw()方法有关。关于如何解决这个问题的任何想法?

def startLive(self, e):
    self.livemode.change(True);
    self.worker = CountingThread(self.panel,self.tune,self.canvas,self.livemode, self.pv1, self.pv2);
    self.worker.start();

def stopLive(self, evt):
    self.livemode.change(False);

class CountingThread(threading.Thread):
    def __init__(self, parent, tune, canvas, livemode, pv1, pv2):
        threading.Thread.__init__(self)
        self._parent = parent;
        self._tune = tune;
        self._canvas = canvas;
        self._livemode = livemode;
        self._pv1 = pv1;
        self._pv2 = pv2;

    def run(self):
        refFreq = 500e6 / 80;
        i=0;
        while self._livemode.get():
            self._tune.newWorkingpoint(refFreq / self._pv1.get(), refFreq / self._pv2.get());
            self._tune.liveUpdate();
            self._canvas.draw();
            time.sleep(0.2);
            i+=1;
            print(i)
class livemode:
    livemode=False;

    def __init__(self):
        self.livemode = False;

    def change(self, livemode):
        self.livemode = livemode;

    def get(self):
        return self.livemode;

-------------------------------- EDIT -------------- ------------------- 如果有人有兴趣,我解决了这个问题,

在线程运行方法中,我删除了循环并只有一个“更新”实例。更新之后,调用wx.PostEvent,它在包含wx.App的主类中调用一个方法,该方法通过调用draw()来更新绘图。在此之后,再次重新启动线程并重复相同的过程。我的GUI继续工作,绘图速度仍然非常快。重要的方法如下,

调用Threading.start(),以及下面的exectures

    def run(self):
        refFreq = 500e6 / 80;
        self._tune.newWorkingpoint(refFreq / self._pv1.get(), refFreq /self._pv2.get());
        self._tune.liveUpdate();
        evt = CountEvent(myEVT_PLOT, -1);
        wx.PostEvent(self._parent, evt);

wx.PostEvent在主wx.App类中调用以下新方法,

    def continueLive(self, evt):
        if self.livemode.get():
            self.canvas.draw();
            self.startLive(evt)

图表已更新,整个过程重新开始。

此方法可保持GUI响应,绘图速度不会减慢。

1 个答案:

答案 0 :(得分:0)

我认为这可能是一个堆栈问题。您的更新循环是递归的,并且堆栈的大小有限(每次函数调用都会被推送到堆栈并在函数返回后被删除)。

您应该将其更改为迭代版本。

def update(self, e):
    if self.liveMode:
        self.tune.plot();  # new plot
    self.canvas.draw();
    #self.startLive(e); # causes endless recursion

def startLive(self, e):
    while (self.isInLiveMode): # some flag here that gets set to False once the mode is deactivated
        self.liveMode = False;
        refFreq = 500e6 / 80;
        qx = self.pv1.get();
        qy = self.pv2.get();
        self.tune.newWorkingpoint(refFreq/qx, refFreq/qy);
        self.tune.liveUpdate();
        time.sleep(0.3);
        self.update(e);

我认为self.liveMode应该是那个标志。

希望这有帮助,LG 丹尼尔