Simple animation with Qt4 backend

Hi all,

Following a discussion with a Spyder user regarding simple animations
with Matplotlib, I took a very quick look at the Qt4's backend source
code to see if it was possible to make the following code work (which
is working with the TkAgg backend but not the Qt4 backend):
http://www.scipy.org/Cookbook/Matplotlib/Animations#head-e50abcca4333d3d76b3f2bb66ef00f15c6b4dbbc

Apparently, to make it work with the Qt4 backend, one simply has to add:
QtGui.QApplication.processEvents()
to the method 'FigureCanvasQt.draw_idle' (matplotlib/backends/backend_qt4.py).

I did not look further to see if this QApplication.processEvents call
is affecting Matplotlib's performance in any way, but I guess that it
won't make a big difference.

Cheers,
Pierre

PS: I know that this example of animation is clearly not the most
efficient way to animate a Matplotlib figure (and that it's very ugly
from a GUI programming point of view!): the 'animation_blit_qt4.py'
example is probably the recommended way but the simple example above
is some much simpler for beginners.

, discussion of why processEvents was originally removed from draw():

"that line can not be added back in. When that line
is in place, the backend attempts to process queued events before it
is finished processing the current event. It was leading to segfaults
in some cases. processEvents should not be called in the middle of
processing an event."

I am not familiar with draw_idle, and the documentation isn't helpful.
Adding processEvents to that call looks similar to adding it to the
end of the draw method itself. I'll argue strongly against such a
change until it can be shown that the call to processEvents will never
occur while processing a current event (I don't want to reintroduce
segfaults in the programs I use at work.)

Darren

···

On Sun, Nov 21, 2010 at 10:36 AM, Pierre Raybaut <pierre.raybaut@...287...> wrote:

Hi all,

Following a discussion with a Spyder user regarding simple animations
with Matplotlib, I took a very quick look at the Qt4's backend source
code to see if it was possible to make the following code work (which
is working with the TkAgg backend but not the Qt4 backend):
http://www.scipy.org/Cookbook/Matplotlib/Animations#head-e50abcca4333d3d76b3f2bb66ef00f15c6b4dbbc

Apparently, to make it work with the Qt4 backend, one simply has to add:
QtGui.QApplication.processEvents()
to the method 'FigureCanvasQt.draw_idle' (matplotlib/backends/backend_qt4.py).

I did not look further to see if this QApplication.processEvents call
is affecting Matplotlib's performance in any way, but I guess that it
won't make a big difference.

From http://www.mail-archive.com/matplotlib-devel@lists.sourceforge.net/msg05606.html

Yes, I can confirm that adding processEvents in places to facilitate
redraws is a good way to lead to segfaults. I have seen this in many
places other than matplotlib. The reason Tk does not have this problem is
that it deals with event loops in a fundementally different way that Wx
or Qt. I am not sure what the difference is exactly, but I seem to
remember that the Tk event loop is more or less hard-wired in Python, and
(maybe ?) lives in a different C-level thread.

The problem with animations in the example linked by Pierre is that there
is no redraw triggered, because the redraw needs to be done in the event
loop. The question that needs to be answered to make it easier for people
doing animations outside of the mainloop is rather: is there a way to
force a redraw without returning in the mainloop. Chances are that there
isn't, because the toolkit (Qt) is not thread safe.

But the problem really boils down to the fact that the example is not the
right way to write animations in GUI programming. However people do not
want to learn event loop programming (I can understand them) and want to
write for loops. In Mayavi, we provide a helper function that enables to
put such a for loop in a generator and pass the generator to the event
loop framework without having to worry about timer:
http://code.enthought.com/projects/mayavi/docs/development/html/mayavi/auto/mlab_other_functions.html#animate
While this function should work out of the box in Spyder, if the
ETS_TOOLKIT variable is well set for Mayavi/Traits to use the Qt backend,
it would also be fairly easy to port the main idea out of Mayavi and
Traits, in matplotlib or spyder:
https://svn.enthought.com/enthought/browser/Mayavi/trunk/enthought/mayavi/tools/animator.py

My 2 cents,

Gaël

···

On Sun, Nov 21, 2010 at 11:58:42AM -0500, Darren Dale wrote:

> Apparently, to make it work with the Qt4 backend, one simply has to add:
> QtGui.QApplication.processEvents()
> to the method 'FigureCanvasQt.draw_idle' (matplotlib/backends/backend_qt4.py).

, discussion of why processEvents was originally removed from draw():

"that line can not be added back in. When that line
is in place, the backend attempts to process queued events before it
is finished processing the current event. It was leading to segfaults
in some cases. processEvents should not be called in the middle of
processing an event."

wx has "Yield()" which sounds a lot like QT's processEvents. But it also has "SafeYield()" which can (in theory, anyway) be called safetly within an event handler.

Does QT have anything similar?

-Chris

···

On 11/21/10 9:43 AM, Gael Varoquaux wrote:

Yes, I can confirm that adding processEvents in places to facilitate
redraws is a good way to lead to segfaults. I have seen this in many
places other than matplotlib. The reason Tk does not have this problem is
that it deals with event loops in a fundementally different way that Wx
or Qt.

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@...259...