Re: [matplotlib-devel] Unnecessary rerendering in wx/wxagg backends

2008-04-14 Thread Gregor Thalhammer
Hi Christopher,

thanks for your valueable feedback. I am proceeding slowly, but steadily.
>
> > backend_qtagg.py seems to contain a proper (more or
>> less, see other postings of Ted Drain) implementation of double 
>> buffered drawing that avoids unnecessary rerendering of the bitmap.
>
> It still feels a bit kludgy to me -- a paint event should simply copy 
> the bitmap to the screen, any re-rendering should be triggered by 
> other events -- either a re-size, or explicitly by 
> figure.canvas.draw() or something. Anyway, given the current 
> structure, this looks like the way to go.
I agree, this is currently more a workaround  for some missing 
rererenderings. It seems to me, that rendering the figure is avoided as 
much as possible. Possibly this is due to the support for the vector 
graphic backends (postscript, pdf, svg)? I guess that with these 
backends rendering means actually creating the output file, but I didn't 
have a look at the source code.
>> self._need_rerender = True
>
> Where does this get set to True again? On a Figure.canvas.draw() call?
Actually nowhere else. In the QtAgg backend, in Figure.canvas.draw this 
is set to True, and then a repaint event is triggered, but no explicit 
rerendering. I didn't get this fact from the beginning. As stated above, 
this command is essentially a workaround for a missing initial 
rerendering after creating the FigureCanvas.
>
>> changed _onPaint(...) to following (note: removed evt.Skip() at end!)
>>def _onPaint(self, evt):
>
>>#repaint only damaged parts of window
>
> I don't know that this is needed, bitting the whole Window is 
> blazingly fast anyway -- but if it works, why not?
Actually, this code repaints the bounding box containing all damaged 
regions. I did it because the QtAgg backend also did it like this. If I 
quickly move another window in front of a matplotlib figure, than I can 
see I small difference.
>> By these change in onPaint a rerendering of the bitmap is done only if
>> needed (in fact, this is needed only once after the figure is shown
>> for the first time).
>
> Well, it's needed whenever the figure changes -- on each 
> figure.canvas.draw() call, I guess.
You are right. To express it more clearly: In my changed code a 
rererendering of the bitmap is done on each figure.canvas.draw() (as 
before). In the onPaint event callback no rerendering is done except the 
very first it's get callad after the figure has been created (changed 
behaviour).
>
> > I moved code from gui_repaint() into
>> _onPaint. Calls to gui_repaint() in other methods (e.g., draw) might 
>> now be
>> replaced by
>>
>> self.Refresh()
>> self.Update() #this is optional, leeds to an immediate repaint
>
> Maybe -- I've found (at least on OS-X) that using a ClientDC is still 
> required sometimes to get instant response. This is key if you're 
> doing anything like animation.
Initially I thought this is optional and might avoid some unnecessary 
repainting. Later I discovered that it is crucial for interactive 
panning. And for animation.
>
>>def draw(self, repaint=True):
>>"""
>>Render the figure using agg.
>>"""
>>DEBUG_MSG("draw()", 1, self)
>>  FigureCanvasAgg.draw(self)
>>self.bitmap = _convert_agg_to_wx_bitmap(self.get_renderer(), 
>> None)
>>if repaint:
>>self.Refresh(eraseBackground = False)
>>self.Update()
>
> I think maybe these should be calls to gui_repaint, which will get you 
> to a ClientDC instead of waiting for a paint event -- Update is not 
> always instant.
Didn't know this. The wxWidgets documentation states about Update(): 
"Calling this method immediately repaints the invalidated area of the 
window..."


>> I had to add some calls to figure.canvas.draw in my mpl-embedded-in-wx
>> application, e.g., after changing a colormap range, to give a
>> immediate change on screen. Before due to the frequent rerendering I
>> didn't notice that these statements were missing.
>
> I agree -- I think I'm going to need to add a few of those too. The 
> problem is that this is a change, and other folks' code is going to 
> break too.
At least for my case I would say that these changes to the wx backend 
didn't break my code, they revealed mistakes in my code (I used 
Refresh() instead of figure.canvas.draw() calls to get a rerendering of 
the matplotlib figure).

>> As Chris Barker noticed, Figure.draw() does not lead to a repainting
>> of the window on screen. This seems to be intended. Instead one should
>> use pylab.draw() or Figure.canvas.draw().
>
> I think you're right -- I should have looked at the pylab.draw code to 
> see what it did. Though I think Figure should have a method that does 
> do an instant update...DrawNow??
For GUI backends I would even expect that Figure.draw() should update 
the figure on screen. However, I don't know how this should be 
implemented for not breaking code which uses other backends.
>> What about the politics of 

Re: [matplotlib-devel] Unnecessary rerendering in wx/wxagg backends

2008-04-14 Thread Ted Drain
Just a note about the speed of blitting:

Generally speaking, blitting on a local machine is VERY fast.  However, if
you log in to a remote machine and display the window locally (remote
machine to local X server), blitting can be the slowest part of the whole
operation.  Profiling of the QtAgg backend shows the following items as the
slowest parts:

1) Convert the QImage (agg RGB) to QPixmap (display depth and resolution)
2) blitting the pixmap to the screen
3) Agg drawing calls

Of course the relative speeds here depend a lot on what's being drawn (agg
calls), how many pixels there are (converting and blitting), how fast the
network is (blitting), how close the screen is to the agg buffer in terms of
resolution and depth (RGB conversion) so timings between these components
can vary a lot.

In short: there are definitely cases where blitting the smallest part of the
image that's necessary is a big help.

Ted

> -Original Message-
> From: [EMAIL PROTECTED]
> [mailto:[EMAIL PROTECTED] On Behalf Of
> Gregor Thalhammer
> Sent: Monday, April 14, 2008 1:03 AM
> To: Christopher Barker; matplotlib-devel@lists.sourceforge.net
> Subject: Re: [matplotlib-devel] Unnecessary rerendering in wx/wxagg
> backends
> 
> Hi Christopher,
> 
> thanks for your valueable feedback. I am proceeding slowly, but
> steadily.
> >
> > > backend_qtagg.py seems to contain a proper (more or
> >> less, see other postings of Ted Drain) implementation of double
> >> buffered drawing that avoids unnecessary rerendering of the bitmap.
> >
> > It still feels a bit kludgy to me -- a paint event should simply copy
> > the bitmap to the screen, any re-rendering should be triggered by
> > other events -- either a re-size, or explicitly by
> > figure.canvas.draw() or something. Anyway, given the current
> > structure, this looks like the way to go.
> I agree, this is currently more a workaround  for some missing
> rererenderings. It seems to me, that rendering the figure is avoided as
> much as possible. Possibly this is due to the support for the vector
> graphic backends (postscript, pdf, svg)? I guess that with these
> backends rendering means actually creating the output file, but I
> didn't
> have a look at the source code.
> >> self._need_rerender = True
> >
> > Where does this get set to True again? On a Figure.canvas.draw()
> call?
> Actually nowhere else. In the QtAgg backend, in Figure.canvas.draw this
> is set to True, and then a repaint event is triggered, but no explicit
> rerendering. I didn't get this fact from the beginning. As stated
> above,
> this command is essentially a workaround for a missing initial
> rerendering after creating the FigureCanvas.
> >
> >> changed _onPaint(...) to following (note: removed evt.Skip() at
> end!)
> >>def _onPaint(self, evt):
> >
> >>#repaint only damaged parts of window
> >
> > I don't know that this is needed, bitting the whole Window is
> > blazingly fast anyway -- but if it works, why not?
> Actually, this code repaints the bounding box containing all damaged
> regions. I did it because the QtAgg backend also did it like this. If I
> quickly move another window in front of a matplotlib figure, than I can
> see I small difference.
> >> By these change in onPaint a rerendering of the bitmap is done only
> if
> >> needed (in fact, this is needed only once after the figure is shown
> >> for the first time).
> >
> > Well, it's needed whenever the figure changes -- on each
> > figure.canvas.draw() call, I guess.
> You are right. To express it more clearly: In my changed code a
> rererendering of the bitmap is done on each figure.canvas.draw() (as
> before). In the onPaint event callback no rerendering is done except
> the
> very first it's get callad after the figure has been created (changed
> behaviour).
> >
> > > I moved code from gui_repaint() into
> >> _onPaint. Calls to gui_repaint() in other methods (e.g., draw) might
> >> now be
> >> replaced by
> >>
> >> self.Refresh()
> >> self.Update() #this is optional, leeds to an immediate repaint
> >
> > Maybe -- I've found (at least on OS-X) that using a ClientDC is still
> > required sometimes to get instant response. This is key if you're
> > doing anything like animation.
> Initially I thought this is optional and might avoid some unnecessary
> repainting. Later I discovered that it is crucial for interactive
> panning. And for animation.
> >
> >>def draw(self, repaint=True):
> >>"""
> >>Render the figure using agg.
> >>"""
> >>DEBUG_MSG("draw()", 1, self)
> >>  FigureCanvasAgg.draw(self)
> >>self.bitmap = _convert_agg_to_wx_bitmap(self.get_renderer(),
> >> None)
> >>if repaint:
> >>self.Refresh(eraseBackground = False)
> >>self.Update()
> >
> > I think maybe these should be calls to gui_repaint, which will get
> you
> > to a ClientDC instead of waiting for a paint event -- Update is not
> > always instant.
> Didn't know this. The wxWidgets d

Re: [matplotlib-devel] Unnecessary rerendering in wx/wxagg backends

2008-04-14 Thread Christopher Barker
Ted Drain wrote:
> Just a note about the speed of blitting:

Your points are well taken. I had forgotten about remote X sessions, and 
yes, if you need to convert to a different type of pixmap, that can take 
time too, so keeping it to just what's needed does make sense.

-Chris



-- 
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

[EMAIL PROTECTED]

-
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
Don't miss this year's exciting event. There's still time to save $100. 
Use priority code J8TL2D2. 
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone
___
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel