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


------------------------------------------------------------------------------
Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA
-OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise
-Strategies to boost innovation and cut costs with open source participation
-Receive a $600 discount off the registration fee with the source code: SFAD
http://p.sf.net/sfu/XcvMzF8H
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Reply via email to