matplotlib, GTK and Threads

I have run into a problem with matplotlib, GTK and Threading.

The program basically gets data over RS232 and if a certain command is sent the data is plotted
So far the program is pretty mature and data can be read via RS232 and written to RS232 and the
GUI is updated (text-widgets) accordingly

The problem I have with with the non-GUI thread calling the “plot” function.

Within the GTK-GUI class I added a method that basically plots a SINE-wave
when a button is pressed it plots another SINE-wave, basically just proof-of-concept before I got onto the date via RS232

The thread-code to extract data (for plotting) via RS232 works fine but when the thread calls a GUI method to update the
graph it locks up

CODE-SNIPPITS

class low_level(threading.Thread):
def init(self,Reg,GUI):

    super(low_level, self).__init__()
    self.timer = threading.Timer(3.0,self.__SetTimerState)

    self.Reg = Reg
    self.GUI = GUI
    self.RUN = True
    self.timer_exp = False    
    self.LOCAL_LIST = []
    self.WRITELIST = []

def __Capture(self):
    DATA = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]
    self.__Write(self.Reg.MON_Addr,self.Reg.MON

[-1])
tmp = [x for x in self.Reg.CAPTURE_REQ if x >0 and x not in locals()["_[1]"]]
tmp.insert(0,0)

    for i in range(int(self.Reg.CAPTURE_SAMPLES)):
        self.__Write(127)
        for x in tmp:
            t = self.__ReadData(

self.Reg.MON_MASK[x][1])
if t == ‘::ERROR::’:
print “Plotting data fault!!”

                break
            DATA[x].append(t)

    DAT = [DATA[0]]
    for x in self.Reg.CAPTURE_REQ:
        if x <1: DAT.append(None)
        else: DAT.append(DATA[x])

    gtk.threads_enter()#updating GUI section
    try:
        self.GUI.ThreadGraph(DAT)

    finally:
        gtk.threads_leave()
    self.Reg.CAPTURE = False



gtk.gdk.threads_init
()
class appgui(object):
def init(self,Reg):
super(appgui, self).init()
self.Reg = Reg
self.gladefile=GLADE_FILE
self.windowname=‘ESC’
self.wTree=gtk.glade.XML
(self.gladefile,self.windowname)

    dic = {'on_quit_button_clicked' : self.QuitClicked,##callback dictionary

    'on_connect_button_clicked' : self.Connect,
    'on_save_conf_clicked' : self.Save
···

,
‘on_load_conf_clicked’ : self.Load,
‘on_upload_clicked’ : self.Upload
,#GetRW,
‘on_capture_clicked’ : self.Capture,
‘on_startstop_clicked’ : self.StartStop,
‘on_window_destroy’ : (gtk.main_quit)}

    self.wTree.signal_autoconnect(dic)
    self.f =  self.wTree.get_widget

    self.GraphData(INIT_G)


def GraphData(self,DATA):
COLOUR = [‘b’,‘g’,‘r’,‘c’,‘m’,‘y’,‘k’]

    try:
        self.canvas.destroy()
        self.toolbar.destroy()
    except:pass

    self.figure = Figure(figsize=(6,3), dpi=100)#{{{
    self.axis = self.figure.add_subplot

(111)
self.axis.grid(True)
self.axis.set_xlabel(‘Time (s)’)

    for x in range(1,len(DATA)):
        if DATA[x] == None: continue

        self.axis.plot(DATA[0],DATA[x],COLOUR[x-1],linewidth=2.0)
 

        self.canvas = FigureCanvas(self.figure) # a gtk.DrawingArea
        self.canvas.show

()
self.graphview = self.wTree.get_widget(‘vboxgraph’)
self.graphview.pack_start
(self.canvas, True, True)
self.toolbar = NavigationToolbar(self.canvas,self.wTree.get_widget(‘ESC’))
self.graphview.pack_start(self.toolbar, False, False)#}}}


if name == ‘main’:
Reg = Register()
app=appgui(Reg)
LL = low_level(Reg,app)
LL.start()

gtk.threads_enter()
gtk.main()
gtk.threads_leave()

LL.stop

()

As it stands with this locks up, if I change the code such that when I press the widget that starts the “Capture” fn from the thread, BUT that doesn’t update the plot
and if I add another button and in pressing that (NOTE that button’s code would be part of the GUI-class) calls the GraphData function then it works.

It seems even using the gtk.threads_enter and gtk.threads_leave with a matplotlib embedded into a GTK windows does not work and any graph modifications MUST
be called directly from the GUI-Class.

Any idea how to make matplotlib work well with GTK & Threads?

Jon Roadley-Battin wrote:

The problem I have with with the non-GUI thread calling the "plot"
function.

That's your problem -- you should only call the GUI code (including
matplotlib, which eventually calls GTK) from a single thread. I suggest
looking at the Queue module to pass your data to the GUI thread if it's
not too much. If it's more, you could use threading.Lock() to regulate
access to a giant array or something.

-Andrew