Problems plotting/closing figures within a thread

I am writing a GUI application in wxPython and using MPL that plots figures,
saves them to image files, and then closes them all from within a thread to
keep the GUI responsive. Using the Enthought 2.3 install I would
sporatically have crashes that were hard to reproduce, but now that I've
upgrade to Enthought 2.5 (Python 2.5 and MPL 0.91.2.0001) it started
throwing exceptions when attempting to close a figure that I don't
understand. I've created an example script that excites the exception. I'm
not sure if the syptoms are a combination of problems caused by my use of
threads but this problem does not occur if threading is removed from the
script. I've read of others experiencing memory leaks and such when closing
figures, but no situations quite like this.

I am working from a desktop in Windows XP and I use the WXAgg backend.

Does anyone have any ideas, or any feedback on my use of threads? Thanks,
Josh

···

-------------------------------------------------------------------------------------------
#!/usr/bin/python

import wx
import time
from threading import Thread

import matplotlib
matplotlib.interactive(False)
matplotlib.use('WXAgg')
import matplotlib.pylab

class TestThread(Thread):
    def __init__(self, notify_window):
        Thread.__init__(self)

    def run(self):
        while True: # Continuous loop that plots and destroys a figure
            matplotlib.pylab.figure(1)
            matplotlib.pylab.plot(range(0,5), range(0,5))
            matplotlib.pylab.show()
            time.sleep(1)
            matplotlib.pylab.close(1) ### ERROR OCCURS HERE

class MainPanel(wx.Panel):
    def __init__(self, *args, **kwargs):
        wx.Panel.__init__(self, *args, **kwargs)
        self.test_thread = None

        # GUI objects and bindings
        self.run_test_button = wx.Button(self, -1, "Run")
        self.top_sizer = wx.BoxSizer(wx.VERTICAL)
        self.top_sizer.Add(self.run_test_button, 0, wx.EXPAND|wx.ALL,
border=2)
        self.SetSizer(self.top_sizer)
        self.Bind(wx.EVT_BUTTON, self.run_test_button_bind, id =
self.run_test_button.GetId())

    ### Binding Methods
    def run_test_button_bind(self, event):
        self.test_thread = TestThread(self)
        self.test_thread.start()
        #self.test_thread.run()
        
class MainFrame(wx.Frame):
    def __init__(self, *args, **kwargs):
        mFrame = wx.Frame.__init__(self, *args, **kwargs)
        self.mPanel = MainPanel(self, -1)
    
class mainApp(wx.App):
    def OnInit(self):
        self.frame = MainFrame(None, title="Test", size=wx.Size(100, 100))
        self.frame.Show()
        self.SetTopWindow(self.frame)
        return True

if __name__ == "__main__":
    app = mainApp()
    app.MainLoop()

--------------------------------------------------------------------------------------------------

Exception in thread Thread-1:
Traceback (most recent call last):
  File "C:\Python25\lib\threading.py", line 486, in __bootstrap_inner
    self.run()
  File ".\test.py", line 22, in run
    matplotlib.pylab.close(1) ### ERROR OCCURS HERE
  File
"C:\python25\lib\site-packages\matplotlib-0.91.2.0001-py2.5-win32.egg\matplotlib\pyplot.py",
line 245, in close
    _pylab_helpers.Gcf.destroy(arg)
  File
"C:\python25\lib\site-packages\matplotlib-0.91.2.0001-py2.5-win32.egg\matplotlib\_pylab_helpers.py",
line 28, in destroy
    figManager.destroy()
  File
"C:\python25\lib\site-packages\matplotlib-0.91.2.0001-py2.5-win32.egg\matplotlib\backends\backend_wx.py",
line 1406, in destroy
    self.frame.Destroy()
  File
"C:\python25\lib\site-packages\matplotlib-0.91.2.0001-py2.5-win32.egg\matplotlib\backends\backend_wx.py",
line 1365, in Destroy
    wxapp.Yield()
  File
"C:\python25\lib\site-packages\wxpython-2.8.4.0.0003_s-py2.5-win32.egg\wx\_core.py",
line 7119, in Yield
    return _core_.PyApp_Yield(*args, **kwargs)
PyAssertionError: C++ assertion "wxThread::IsMain()" failed at
..\..\src\msw\evtloop.cpp(244) in wxEventLoop::Dispatch(): only the main
thread can process Windows messages
--
View this message in context: http://www.nabble.com/Problems-plotting-closing-figures-within-a-thread-tp19789227p19789227.html
Sent from the matplotlib - users mailing list archive at Nabble.com.

jcarnes schrieb:

I am writing a GUI application in wxPython and using MPL that plots figures,
saves them to image files, and then closes them all from within a thread to
keep the GUI responsive. Using the Enthought 2.3 install I would
sporatically have crashes that were hard to reproduce, but now that I've
upgrade to Enthought 2.5 (Python 2.5 and MPL 0.91.2.0001) it started
throwing exceptions when attempting to close a figure that I don't
understand. I've created an example script that excites the exception. I'm
not sure if the syptoms are a combination of problems caused by my use of
threads but this problem does not occur if threading is removed from the
script. I've read of others experiencing memory leaks and such when closing
figures, but no situations quite like this.

I am working from a desktop in Windows XP and I use the WXAgg backend.

Does anyone have any ideas, or any feedback on my use of threads? Thanks,
Josh
  
wxPython and multithreading don't go well together. Have a look at the wxWidgets docs about multithreading. Changes to the GUI (this includes closing a window) should only be done from the main thread.

Continously creating and destroying a figure window seems not necessary in your application. Create it once in the main thread ((have a look at the embedding_in_wx examples of matplotlib) and only clear/replot it in your thread. In my experience replotting from the main thread is fast enough, saving to a file takes more time, this is worth to be done in another thread.

Gregor