如何在 wxpython 上使用线程和 matplotlib

How to use thread with matplotlib on wxpython

我想为 matplotlib 使用另一个线程。但是当我 运行 下面的脚本时,它给出了一个错误 timer can only be started from the main thread。 任何帮助将不胜感激。

import wx
from threading import Thread
import serial
import threading
import time
import matplotlib.pyplot as plt
import matplotlib.animation as animation

fig, ax1 = plt.subplots( )  
def runA():
    print("THREAD")
    while True:
        def mix(i)
            x=[1,3,5]
            y=[13,5,23]
            plt.plot(x,y)
            time.sleep(1)
        ani =animation. FuncAnimation(fig,mix)
        plt.show()

class MyFrame1 ( wx.Frame ):
    def __init__ (self, parent):
        wx.Frame.__init__(self, parent)
        self.SetSizeHints( wx.Defaultsize, wx.DefaultSize)
        bSizer3= wx.BoxSizer(wx.VERTICAL)

        self.button1= wx.Button( self, wx.ID_ANY, "mybutton1", wx.DefaultPosition, wx.DefaultSize, 0)

        bsizer3.Add( self.button1, 1, wx.ALL|wx.EXPAND, 5)

        self.button2= wx.Button( self, wx.ID_ANY, "mybutton2", wx.DefaultPosition, wx.DefaultSize, 0)

        bsizer3.Add( self.button2, 1, wx.ALL|wx.EXPAND, 5)
        self SetSizer( bsizer3)
        self.Layout ()
        self.Centre( wx. BOTH )
# Connect Events
        self.button1.Bind(wx.EVT_BUTTON, self.b1_f )
        self.button2.Bind(wx.EVT_BUTTON, self.b2_f )

    def b1_f( self, event ):
        t2=Thread (target =runA)
        t2.start()

    def b2_f( self, event):
        print("heLLo")

if __name__ == "__main__":
    app = wx.App(False)
    frame=MyFrame1 (None)
    frame.Show(True)
    app.MainLoop()

注:其实wxpython有自己的绘图库。但是我无法成功读取图像并在其上绘制数据。

您问题中的代码存在多个问题。以下行在 wxPython 4.0.4 中不起作用,self.SetSizeHints( wx.Defaultsize, wx.DefaultSize) 并且您为 wx.BoxSizer 使用了不同的名称。关于这个问题,我无法重现你的错误,但我认为问题在于你需要将绘图代码移动到 class MyFrame1。一种方法是:

import wx
from threading import Thread
import serial
import threading
import time
import matplotlib.pyplot as plt
import matplotlib.animation as animation

class MyFrame1(wx.Frame):
    def __init__ (self, parent):
        wx.Frame.__init__(self, parent)
        #self.SetSizeHints(wx.Defaultsize, wx.DefaultSize)
        bSizer3= wx.BoxSizer(wx.VERTICAL)

        self.button1 = wx.Button(self, wx.ID_ANY, "mybutton1", 
                                 wx.DefaultPosition, wx.DefaultSize, 0)

        bSizer3.Add(self.button1, 1, wx.ALL|wx.EXPAND, 5)

        self.button2 = wx.Button(self, wx.ID_ANY, "mybutton2", 
                                 wx.DefaultPosition, wx.DefaultSize, 0)

        bSizer3.Add(self.button2, 1, wx.ALL|wx.EXPAND, 5)
        self.SetSizer(bSizer3)
        self.Layout()
        self.Centre(wx.BOTH)
# Connect Events
        self.button1.Bind(wx.EVT_BUTTON, self.b1_f)
        self.button2.Bind(wx.EVT_BUTTON, self.b2_f)

    def b1_f( self, event ):
        print('Hello2')
        t2=Thread(target = self.runA)
        t2.start()

    def b2_f( self, event):
        print("heLLo")


    def runA(self):
        fig, ax1 = plt.subplots( )  
        print("THREAD")
        while True:
            def mix(i):
                x=[1,3,5]
                y=[13,5,23]
                plt.plot(x,y)
                time.sleep(1)
            ani = animation.FuncAnimation(fig,mix)
            plt.show()

if __name__ == "__main__":
    app = wx.App()
    frame=MyFrame1(None)
    frame.Show()
    app.MainLoop()

现在这项工作但是:

1 - 您应该考虑为 matplotlib. The backend you are using now gives a non-fatal error when you make a plot, close it and plot again. Also, it works in Win10 and Linux(Fedora 30) but it does not work on macOS 10.14.4. Here is an example.

使用 wxAgg 后端

2 - 您需要找到 deactivate/activate button1 的方法,因为使用当前的 matplotlib 后端,您不能同时拥有两个绘图。因此,在显示绘图时单击按钮会使 GUI 无响应。

3 - 绘图功能中的计时器使绘图无响应。也许matplotlib有另一种方法来控制动画的速度。