[SciPy-user] pyqwt or matplotlib

Zachary Pincus zachary.pincus at yale.edu
Wed Aug 27 12:00:01 EDT 2008


Hi Fernando,

>> It's quite hackable, too -- I rigged up a very simple system to run
>> pyglet windows in a background thread, so I could control the
>> microscope from an interactive python interpreter, while still being
>> able to programmatically interact with pyglet window objects. (Happy
>> to share this code with anyone who desires. It's much cleaner, IMO,
>> than the gyrations that ipython has to go through to support
>> nonblocking QT, Tk, etc. windows. This is becase the pyglet mainloop
>> is in python, and is easy to subclass and otherwise mess with.)
>
> Does your code work as-is inside ipython?  Would you want to
> contribute it to ipython?  We'd love to ship an
> out-of-the-box-pyglet-shell, just let us know.

I'd be happy to provide this code. There are a few caveats to its use,  
though -- perhaps you could help me come up with an easier interface.

Out of the box, pyglet ships with a main-loop that uses platform- 
specific code to sleep until a GUI event happens, or after a certain  
time elapses (to enforce a user-specified minimum framerate). Every  
time the loop wakes up, it sends repaint (in pyglet: on_draw) events  
to all of the windows.

Now, Pyglet works fine if all the calls to it are made from one thread  
only. So what I do is run a subclass of the default event loop in a  
background thread. This subclassed event loop checks a "message  
queue" (basically, a list of callback functions) every time it wakes  
up, and if the queue is non-empty, calls a few of the callbacks. This  
way, code that calls pyglet functions can be added to the message  
queue so that it will be called in the context of the pyglet thread.  
(I've added a few bells and whistles, like proxy objects that "look"  
like pyglet windows, but route method calls and getattr/setattr  
through the event loop, so that interaction is seamless.)

Here comes the caveat, though: to keep latency down for tending the  
message queue, the main loop needs to wake up frequently (at least 20  
Hz). However, sending repaint events to every window that often is  
pretty inefficient in most cases. So I elected to not send the repaint  
events by default. Instead, a pyglet window needs to call it's on_draw  
method after every event that requires a redraw (e.g. a clock tick, a  
GUI interaction).

This sort of event loop is a more efficient than the default pyglet  
loop in general, but unfortunately, the coding style is a bit  
different. As such, my code doesn't work with any old pyglet window  
class out of the box -- some very minor changes need to be made. I  
could perhaps fix things so this isn't necessary -- figure out a way  
for the main-loop to distinguish between being awoken to tend the  
message queue, and being awoken on GUI events or for "minimum  
framerate" reasons. But perhaps the issue is un-fixable...

Another caveat is that this approach is almost completely backwards to  
that taken by the rest of the interactive windowing code in ipython.  
(That code essentially feeds an embedded python interpreter, which  
runs as a callback from the GIU mainloop, line-by-line input from  
stdin.) As such, my code might be a bit out-of-place and harder to  
maintain. I suspect that the original ipython approach will work fine  
for pyglet too, and perhaps without the above caveat; however it might  
be a bit more processor-intensive.

Zach





More information about the SciPy-User mailing list