Patch for making SpanSelector usable in embedded matplotlib

I've been working on an application that uses matplotlib as its
plotting library, and I've been noticing a steady decrease in
performance over time. I figured out the cause as coming from the
matplotlib SpanSelector widget - I had to create a new widget every
time the axes were cleared, as the SpanSelector would not draw
correctly afterwards. The event processing calls were still being
made though, so over time I collected hundreds of SpanSelectors,
rendering the app unusable after a while. This patch adds a new_axes
method to the SpanSelector that can be called to simply re-assign the
spanselector to a new axes so I only need one. Below is a diff
against the latest svn.

Also, is it better practice to submit patches like this to this
mailing list, or the sourceforge tracker? I've seen some people do
both, and it seems like the tracker isn't kept up very well...

Index: lib/matplotlib/widgets.py

···

===================================================================
--- lib/matplotlib/widgets.py (revision 4950)
+++ lib/matplotlib/widgets.py (working copy)
@@ -829,12 +829,9 @@

         self.ax = ax
         self.visible = True
- self.canvas = ax.figure.canvas
- self.canvas.mpl_connect('motion_notify_event', self.onmove)
- self.canvas.mpl_connect('button_press_event', self.press)
- self.canvas.mpl_connect('button_release_event', self.release)
- self.canvas.mpl_connect('draw_event', self.update_background)
-
+ self.cids=[]
+ self.canvas = None
+
         self.rect = None
         self.background = None

@@ -847,12 +844,30 @@
         # Needed when dragging out of axes
         self.buttonDown = False
         self.prev = (0, 0)
+
+ self.new_axes(ax)
+
+ def new_axes(self,ax):
+ self.ax = ax
+ if self.canvas is not ax.figure.canvas:
+ for i,cid in enumerate(self.cids[:]):
+ try:
+ self.canvas.mpl_disconnect(cid)
+ except: #if the old canvas is dead or anything else unexpected
+ pass
+ self.cids.remove(cid)
+
+ self.canvas = ax.figure.canvas
+ self.cids.append(self.canvas.mpl_connect('motion_notify_event', self.onmove))
+ self.cids.append(self.canvas.mpl_connect('button_press_event', self.press))
+ self.cids.append(self.canvas.mpl_connect('button_release_event',
self.release))
+ self.cids.append(self.canvas.mpl_connect('draw_event',
self.update_background))

         if self.direction == 'horizontal':
- trans = blended_transform_factory(self.ax.transData,
self.ax.transAxes)
+ trans = blend_xy_sep_transform(self.ax.transData,
self.ax.transAxes)
             w,h = 0,1
         else:
- trans = blended_transform_factory(self.ax.transAxes,
self.ax.transData)
+ trans = blend_xy_sep_transform(self.ax.transAxes,
self.ax.transData)
             w,h = 1,0
         self.rect = Rectangle( (0,0), w, h,
                                transform=trans,

It looks like there is some confusion in your patch vis-a-vis the
migration from the old matplotlib transformation architecture (no on a
branch) to the new (now in the trunk). I'm attaching the migration
document. For example, your patch removes
blended_transform_factory lines (new transforms call on the trunk) and
adds blend_xy_sep_transform lines (old transforms call on the 0.91
maintenance branch).

You can patch either the maintenance branch or the trunk or both, but
I think the patch as submitted is a little mixed up if I am reading
this correctly.

JDH

MIGRATION.txt (3.39 KB)

API_CHANGES (43.7 KB)

···

On Feb 10, 2008 5:12 PM, Erik Tollerud <erik.tollerud@...149...> wrote:

I've been working on an application that uses matplotlib as its
plotting library, and I've been noticing a steady decrease in

You're absolutely correct - I wrote the original patch against 91.2,
and forgot to test it against the new trunk. Below is a new patch
that HAS been tested against the trunk version. It includes another
fix for some API changes in the Rectangle object. Note that there's
also a fix in the RectangleSelector to prevent it from raising an
exception under the new API.

I've also noticed that both the SpanSelector and RectangleSelector
don't seem to draw the rectangle with useblit=False on my machine -
I'm only using useblit=True, though, and it works fine there with the
alterations in this patch.

Index: widgets.py

erikspansel3.diff (3.26 KB)

···

===================================================================
--- widgets.py (revision 4953)
+++ widgets.py (working copy)
@@ -827,16 +827,14 @@
         assert direction in ['horizontal', 'vertical'], 'Must choose
horizontal or vertical for direction'
         self.direction = direction

- self.ax = ax
+ self.ax = None
+ self.canvas = None
         self.visible = True
- self.canvas = ax.figure.canvas
- self.canvas.mpl_connect('motion_notify_event', self.onmove)
- self.canvas.mpl_connect('button_press_event', self.press)
- self.canvas.mpl_connect('button_release_event', self.release)
- self.canvas.mpl_connect('draw_event', self.update_background)
+ self.cids=[]

         self.rect = None
         self.background = None
+ self.pressv = None

         self.rectprops = rectprops
         self.onselect = onselect
@@ -847,8 +845,23 @@
         # Needed when dragging out of axes
         self.buttonDown = False
         self.prev = (0, 0)
-
- if self.direction == 'horizontal':
+
+ self.new_axes(ax)
+
+
+ def new_axes(self,ax):
+ self.ax = ax
+ if self.canvas is not ax.figure.canvas:
+ for cid in self.cids:
+ self.canvas.mpl_disconnect(cid)
+
+ self.canvas = ax.figure.canvas
+
+ self.cids.append(self.canvas.mpl_connect('motion_notify_event',
self.onmove))
+ self.cids.append(self.canvas.mpl_connect('button_press_event',
self.press))
+ self.cids.append(self.canvas.mpl_connect('button_release_event',
self.release))
+ self.cids.append(self.canvas.mpl_connect('draw_event',
self.update_background))
+ if self.direction == 'horizontal':
             trans = blended_transform_factory(self.ax.transData,
self.ax.transAxes)
             w,h = 0,1
         else:
@@ -859,9 +872,8 @@
                                visible=False,
                                **self.rectprops
                                )
-
+
         if not self.useblit: self.ax.add_patch(self.rect)
- self.pressv = None

     def update_background(self, event):
         'force an update of the background'
@@ -931,10 +943,10 @@
         minv, maxv = v, self.pressv
         if minv>maxv: minv, maxv = maxv, minv
         if self.direction == 'horizontal':
- self.rect.xy[0] = minv
+ self.rect.set_x(minv)
             self.rect.set_width(maxv-minv)
         else:
- self.rect.xy[1] = minv
+ self.rect.set_y(minv)
             self.rect.set_height(maxv-minv)

         if self.onmove_callback is not None:
@@ -1155,8 +1167,8 @@
             miny, maxy = self.eventpress.ydata, y # click-y and actual mouse-y
             if minx>maxx: minx, maxx = maxx, minx # get them in the right order
             if miny>maxy: miny, maxy = maxy, miny
- self.to_draw.xy[0] = minx # set lower left of box
- self.to_draw.xy[1] = miny
+ self.to_draw.set_x(minx) # set lower left of box
+ self.to_draw.set_y(miny)
             self.to_draw.set_width(maxx-minx) # set width and height of box
             self.to_draw.set_height(maxy-miny)
             self.update()

On Feb 11, 2008 7:48 AM, John Hunter <jdh2358@...149...> wrote:

On Feb 10, 2008 5:12 PM, Erik Tollerud <erik.tollerud@...149...> wrote:
> I've been working on an application that uses matplotlib as its
> plotting library, and I've been noticing a steady decrease in

It looks like there is some confusion in your patch vis-a-vis the
migration from the old matplotlib transformation architecture (no on a
branch) to the new (now in the trunk). I'm attaching the migration
document. For example, your patch removes
blended_transform_factory lines (new transforms call on the trunk) and
adds blend_xy_sep_transform lines (old transforms call on the 0.91
maintenance branch).

You can patch either the maintenance branch or the trunk or both, but
I think the patch as submitted is a little mixed up if I am reading
this correctly.

JDH

--
Erik Tollerud
Graduate Student
Center For Cosmology
Department of Physics and Astronomy
4155B Frederick Reines Hall
University of California, Irvine
Office Phone: (949)824-2996
Cell: (651)307-9409
etolleru@...244...

OK, thanks Erik, I committed this to the trunk as svn r4956. It seems
to be working fine, so thanks for the patch. I'm not sure right now
wha the problem is with useblit=False that you are experiencing, but
if you make any headway on this let us know.

JDH

···

On Feb 12, 2008 7:02 PM, Erik Tollerud <etolleru@...244...> wrote:

You're absolutely correct - I wrote the original patch against 91.2,
and forgot to test it against the new trunk. Below is a new patch
that HAS been tested against the trunk version. It includes another
fix for some API changes in the Rectangle object. Note that there's
also a fix in the RectangleSelector to prevent it from raising an
exception under the new API.

While doing some further testing, I'm getting another bug in the svn
code - whenever I try to right-click and drag to zoom out when using
the toolbar, an Exception is raised complaining about an unbound
local. I traced the problem to what appears to be a typo in
backend_bases.py where someone must have renamed some variables and
didn't go and change them further up or something. Changing the
variable name in a couple places seems to make it all work on my
setup. The diff is attached.

erikbackendbases.diff (799 Bytes)

···

On Feb 12, 2008 6:11 PM, John Hunter <jdh2358@...149...> wrote:

On Feb 12, 2008 7:02 PM, Erik Tollerud <etolleru@...244...> wrote:
> You're absolutely correct - I wrote the original patch against 91.2,
> and forgot to test it against the new trunk. Below is a new patch
> that HAS been tested against the trunk version. It includes another
> fix for some API changes in the Rectangle object. Note that there's
> also a fix in the RectangleSelector to prevent it from raising an
> exception under the new API.

OK, thanks Erik, I committed this to the trunk as svn r4956. It seems
to be working fine, so thanks for the patch. I'm not sure right now
wha the problem is with useblit=False that you are experiencing, but
if you make any headway on this let us know.

JDH

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel

--
Erik Tollerud
Graduate Student
Center For Cosmology
Department of Physics and Astronomy
4155B Frederick Reines Hall
University of California, Irvine
Office Phone: (949)824-2996
Cell: (651)307-9409
etolleru@...244...

Good catch -- applied to r4959.

Thanks,
JDH

···

On Feb 12, 2008 10:31 PM, Erik Tollerud <erik.tollerud@...149...> wrote:

While doing some further testing, I'm getting another bug in the svn
code - whenever I try to right-click and drag to zoom out when using
the toolbar, an Exception is raised complaining about an unbound
local. I traced the problem to what appears to be a typo in
backend_bases.py where someone must have renamed some variables and
didn't go and change them further up or something. Changing the
variable name in a couple places seems to make it all work on my
setup. The diff is attached.