matplotlib, GTK and Threads

is there any thread_init for matplotlib. short of having a

    > timer within the GUI class that checks if any new data is
    > present I cant see a way around this. It has to be done this

There isn't any such method. Would it work for you to update your
line data / plot data and run canvas.draw_idle in a gtk timer, eg
every second? Since you are only polling your RS232 every second or
so, it seems like you could update your graph in a timer on roughly
the same time scale w/o too much pain.

I don't know mcuh about threading, but trying to make threads play
nice with all the GUIs mpl supports seems daunting, and I prefer to
offload that to external apps -- eg ipython in pylab mode. But if
there is something we can add that will make your use case work better
if the timer route doesn't work, feel free to suggest something...

JDH

I have a solution that works.
The problem is in 1/2 GTK and threads. unfortunetly threads are needed in this instance, idle timers [orig tried with them] have their issues which added their own problems, threads gave alot more benefits then they then problems they solved (I have a forum-thread on a python forum about three methods I tried, for this instance threading is the only solution)

Basically GTK can work with threads, the problem arrises when the thread want’s to change the GUI (say a txt lable). GTK can be made “thread-safe” via calling gtk.gdk.threads_init() before gtk.main(). THEN every time the thread wants to change something, put it between

gtk.threads_enter()

gtk.threads_leave()

calls.
THIS only works for default GTK widgets and since a matplotlib window isn’t a standard GTK widget it hard-locks the GUI.
I have a solution to it, it is quite neat (it could be a fn wrapper, but don’t know much abt fn wrappers)

#!/usr/bin/env python

import threading

import time

import math

import sys

import os

import pygtk

if sys.platform == ‘win32’:

os.environ['PATH'] += ';lib;'

else:

pygtk.require('2.0')

import gtk

import gobject

assert gtk.pygtk_version >= (1,99,16), ‘pygtk should be >= 1.99.16’

#import gtk.glade

from pylab import *

rcParams[‘numerix’] = ‘numpy’

import matplotlib

matplotlib.use(‘GTK’)

from matplotlib.figure import Figure

from matplotlib.axes import Subplot

from matplotlib.backends.backend_gtk import FigureCanvasGTK as FigureCanvas

TIME = range(360)

VOLT = [math.sin(math.radians(x)) for x in TIME]

VOLT2 = [2]*360

VOLT3 = [x for x in range(360)]

def do_gui(fn,*args,**kw):

def idle_func():

    print "idle"

    gtk.threads_enter()

    try:

        fn(*args,**kw)

    finally:

        gtk.threads_leave()

gobject.idle_add(idle_func)

class my_thread(threading.Thread):

def __init__(self,GUI):

    super(my_thread, self).__init__()

    self.GUI = GUI


def run(self):

    time.sleep(10)

    #gtk.threads_enter()

    #try:

    #    self.GUI.Graph([TIME,VOLT3])

    #finally:

    #    gtk.threads_leave()

    do_gui(self.GUI.Graph,[TIME,VOLT3])

gtk.gdk.threads_init()

class GUI(object):

def GUI_Plot(self,widget,event,data=None):

    self.Graph([TIME,VOLT2])


def delete_event(self,widget,event,data=None):

    return False


def destroy(self,widget,data=None):

    gtk.main_quit()



def __init__(self):

    super(GUI,self).__init__()

     
    self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)

    self.window.set_title("Matplotlib GTK test")

    self.window.connect("delete_event",self.delete_event)

    self.window.connect("destroy",self.destroy)


    self.window.set_border_width(10)

    self.box1 = gtk.VBox(False,0)

    self.window.add(self.box1)


    self.button = gtk.Button("GUI Plot")

    self.button.connect("clicked",self.GUI_Plot,None)

    self.box1.pack_start(self.button,True,True,0)

     
     
    self.button.show()

    self.box1.show()

    self.window.show()


    self.Graph([TIME,VOLT])



def Graph(self,DATA):

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



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

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

        self.canvas.show()

        self.graphview = self.box1

        self.graphview.pack_start(self.canvas, True, True)


 

def main(self):

    gtk.main()

if name == “main”:

A = GUI()

B = my_thread(A)

B.start()


gtk.threads_enter()

A.main()

gtk.threads_leave()

basically another fn is created that has the threads_enter and threads_leave called, BUT they themselves are called within a gtk-idle call, this stops the GUI from hard-locking.

I don’t know if it is the best solution, but it is a solution.
thanks

···

On 9/5/06, John Hunter < jdhunter@…4…> wrote:

“Jon” == Jon Roadley-Battin <
jon.roadleybattin@…287…> writes:
is there any thread_init for matplotlib. short of having a
timer within the GUI class that checks if any new data is

> present I cant see a way around this. It has to be done this

There isn’t any such method. Would it work for you to update your
line data / plot data and run canvas.draw_idle in a gtk timer, eg

every second? Since you are only polling your RS232 every second or
so, it seems like you could update your graph in a timer on roughly
the same time scale w/o too much pain.

I don’t know mcuh about threading, but trying to make threads play

nice with all the GUIs mpl supports seems daunting, and I prefer to
offload that to external apps – eg ipython in pylab mode. But if
there is something we can add that will make your use case work better
if the timer route doesn’t work, feel free to suggest something…

JDH