Running matplotlib from an interactive python shell with wxPython

I was trying to setup matplotlib to use interactively with wxPython as the backend. I run into the issue that when I call draw(), it blocks the interpreter. Since then I've found out it is a issue with some GUI backend that the mainloop blocks. The suggested solution is to use ipython, which I do not use for various reasons.

I think I have come across the problem stated in the user's guide:

"For other user interface toolkits and their corresponding matplotlib backends, the situation is complicated by the GUI mainloop which takes over the entire process. The solution is to run the GUI in a separate thread, and this is the tricky part that ipython solves for all the major toolkits that matplotlib supports."

http://matplotlib.sourceforge.net/users/shell.html#other-python-interpreters

I end up spending sometime hacking some code. And I think I manage to run the interpreter and GUI mainloop in separate threads. So I'd post my code here for review and perhaps someone may find it useful. I'm very new to matplotlib so I don't know if what I do really make sense.

pylab.py

···

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

""" Run matplotlib interactively with the Python interpreter and the wxPython
backend.

This script launches the interpreter in a second thread while keeping matplotlib
and the wxPython mainloop on the main thread. It resolves the issue that calling
draw() starts the GUI mainloop and blocks the main thread.

"For other user interface toolkits and their corresponding matplotlib backends,
the situation is complicated by the GUI mainloop which takes over the entire
process. The solution is to run the GUI in a separate thread, and this is the
tricky part that ipython solves for all the major toolkits that matplotlib
supports."
http://matplotlib.sourceforge.net/users/shell.html#other-python-interpreters

To use, just launch this script from command line, e.g

     c:\> python pylab.py
     Python 2.6.1 (r261:67517, Dec 4 2008, 16:51:00) [MSC v.1500 32 bit (Intel)] on win32
     Type "help", "copyright", "credits" or "license" for more information.
     (MatplotlibConsole)
     >>>

Alternatively it is recommended to use the Ipython shell with matplotlib.
"""

import code
import Queue
import sys
import threading

import matplotlib.pyplot as plt
import numpy as np
import wx

BaseConsole = code.InteractiveConsole

class MatplotlibConsole(BaseConsole):
     """
     MatplotlibConsole is an interactive Python console that splits I/O and code
     execution in separate threads. This address the issue that in the Matplotlib
     and wxPython environment, some functions do not work well when called from
     an abitrary thread and should be run from the main thread only. Here code
     are queued instead of executed immediately. execute_queued_code() should be
     called regularly from the main thread.
     """
     def __init__(self, *args):
         self.code_q = Queue.Queue(1)
         self.shutdown = False
         BaseConsole.__init__(self, *args)

     def runcode(self, code):
         # queue the code so that it may run in the main thread
         self.code_q.put(code, block=True)
         self.code_q.join()

     def execute_queued_code(self, event):
         if self.shutdown:
             # make sure shutdown action don't run more than once
             self.shutdown = False
             plt.close()
             return
         try:
             code = self.code_q.get_nowait()
         except Queue.Empty:
             return
         try:
             BaseConsole.runcode(self, code)
         finally:
             self.code_q.task_done()

     def interact(self):
         BaseConsole.interact(self)
         print 'Console Closing...'
         self.shutdown = True

def main(argv):
     # instantiate MatplotlibConsole
     mp_locals = {
         "np":np,
         "plt":plt,
     }
     console = MatplotlibConsole(mp_locals)

     # launch console in a new thread
     shell_thread = threading.Thread(target=console.interact, name='shell_thread')
     shell_thread.start()

     # setup pyplot
     fig = plt.figure(1)

     # setup timer to run the execute_queued_code()
     id = wx.NewId()
     actor = fig.canvas.manager.frame
     timer = wx.Timer(actor, id=id)
     timer.Start(100)
     wx.EVT_TIMER(actor, id, console.execute_queued_code)

# this doesn't work. why?
# plt.ion()

     # show() starts the wx main loop
     plt.show()

if __name__ =='__main__':
     main(sys.argv)

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

There is still some issue I'm trying to solve. For some reason I don't understand I can't run plt.ion() before show(). Also I like to do an import like "from pylab import *" for the console.

Wai Yip