Matplotlib-users digest, Vol 1 #521 - 2 msgs

I ran the script with GTKCairo and it looks fine to me.

    > Perhaps you are using GTKAgg which looks like it has the
    > problem. My guess is that its caused by using
    > gtk.idle_add() which results in asynchronous expose_event
    > updates.

I looked at this briefly and am a little confused by something. The
base class FigureCanvasGTK.expose_event has this in the doc string

        """Expose_event for all GTK backends
        Should not be overridden.

but then the derived class

  class FigureCanvasGTKAgg(FigureCanvasGTK, FigureCanvasAgg):

does in fact override it.

I inserted a debug print statement into
FigureCanvasGTKAgg.expose_event and it is not called until the loop is
over. I think this is because the call to sleep is preventing the
idle handler from ever getting engaged.

Perhaps Joachim would be better off using a gtk timer to handle his
animation. Basically, matplotlib tries to provide a GUI neutral way
to do animation (eg anim.py) but if you want to do something
semi-sophisticated like alter the timing between draws, you should use
the GUI specific functionality for this, eg gtk timers.

Here is an example

# animate increasing terms in fourier expansion of y=x
import pygtk
pygtk.require('2.0')
import gtk
import matplotlib
matplotlib.use('GTKAgg')

from matplotlib.numerix import arange, pi, sin, zeros, Float
import pylab

class Animator:
    
    def __init__(self, samples=1000, max_k=30):
        self.samples = samples
        self.max_k = max_k
        self.fig = pylab.figure()
        self.ax = self.fig.add_subplot(111)
        x = arange(0.0, 1.0, 1.0/self.samples)

        self.s = zeros((self.max_k,samples), Float)

        for k in range(1,self.max_k):
            self.s[k] = self.s[k-1]+(-1)**(k+1)*sin(pi*x*k)/k

        self.line, = self.ax.plot(x, x*1.3, linewidth=1.0)
        self.ax.grid(True)
        self.k = 1

    def draw(self, *args):
        
        self.line.set_ydata(2./pi*self.s[self.k])
        self.ax.set_title('k = '+str(self.k))
        pylab.draw()
        self.k += 1
        return self.k<self.max_k

anim = Animator()
gtk.timeout_add(100,anim.draw)
pylab.show()

I looked at this briefly and am a little confused by something. The
base class FigureCanvasGTK.expose_event has this in the doc string

        """Expose_event for all GTK backends
        Should not be overridden.

but then the derived class

  class FigureCanvasGTKAgg(FigureCanvasGTK, FigureCanvasAgg):

does in fact override it.

A while ago I started updating the GTK backends to be more consistent
(by using the same draw(), expose_event() etc methods) and also so they
create just one Renderer instance and reuse it for all drawing. I
completed doing this for GTK and GTKCairo. With GTKAgg, it looked a bit
more complicated, and seeing that GTKAgg was already working quite well
I decided to leave it and come back to it later.
So my intention was to have all GTK backends using a standard draw() and
expose_event() from the base class and just have a specific
_renderer_init() to set their own renderer. To make this work by reusing
one Renderer instance I needed to add new methods to each Renderer:
    def _set_pixmap(self, pixmap):
    def _set_width_height(self, width, height):
which are called by _render_figure().

I still think this approach is a good idea, but it may need to be
modified to allow it to work with GTKAgg.
The patch I committed to CVS does the first part (using standard draw()
and expose()), but not the second part - GTKAgg still uses multiple
Renderer instances.

The patch also fixes another little problem that GTKAgg has. If you
display a figure, then obscure the window and expose the window (without
resizing it), GTKAgg will completely redraw the window, which may give a
flicker in the obscured/exposed area for a complicated figure, whereas
GTK and GTKCairo will redraw the original figure from the double-
buffered memory, which is much faster and flicker-free.

I inserted a debug print statement into
FigureCanvasGTKAgg.expose_event and it is not called until the loop is
over. I think this is because the call to sleep is preventing the
idle handler from ever getting engaged.

I think Joachim just used the sleep call just to make the problem
obvious, and that the problem is there even if sleep is not called,
except that it may flash so quickly you can not be sure what you saw.

Perhaps Joachim would be better off using a gtk timer to handle his
animation. Basically, matplotlib tries to provide a GUI neutral way
to do animation (eg anim.py) but if you want to do something
semi-sophisticated like alter the timing between draws, you should use
the GUI specific functionality for this, eg gtk timers.

Here is an example
[...]

Thats works OK, but requires that users write their own animation draw()
routines, whereas using double-buffering for GTKAgg makes it available
to all GTKAgg users for free. I think double-buffering is generally what
you want to use for flicker-free drawing, and there does not seem to be
any performance penalty from the few tests I made.

Steve

···

On Wed, 2005-03-16 at 09:00 -0600, John Hunter wrote: