简体   繁体   中英

How to use thread with matplotlib on wxpython

I want to use another thread for matplotlib. But when I run below script, it gives an error timer can only be started from the main thread . Any help would be appreciated.

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()

Note: Actually wxpython has its own plot library. But I couldn't succeed image read and plot data on it.

There were several issues with the code in your question. The following line does not work in wxPython 4.0.4, self.SetSizeHints( wx.Defaultsize, wx.DefaultSize) and you used different names for the wx.BoxSizer . Regarding the question, I could not reproduce your error but I think the problem is that you need to move the plotting code to class MyFrame1 . One way to do it is:

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()

Now this work but:

1 - You should consider using the wxAgg backend for 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 .

2 - You need to find a way to deactivate/activate button1 because with the current matplotlib backend you cannot have two plot at the same time. So clicking the button while the plot is shown makes the GUI unresponsive.

3 - The timer in the plotting function makes the plot unresponsive. Perhaps matplotlib has another way to control the speed of the animation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM