[matplotlib-devel] Alternate lasso: click to form polygon

2008-07-29 Thread Eric Bruning
I wanted something more precise (and easier on the carpal tunnel) than
the included Lasso widget. Inspired by the existing Lasso, I forked
out an alternate approach that creates a polygon with mouse clicks and
returns a list of vertices to a callback function.

See the attached for a demo. It's been tested with WxAgg running off
recent svn. I'm using idle_event, which isn't mentioned in the docs
for the released version.

If there's interest, I'll put together a patch to add this to widgets.py.

Thanks,
Eric B
from matplotlib.lines import Line2D
from matplotlib.widgets import Widget

class PolyLasso(Widget):
 
A lasso widget that allows the user to define a lasso region by
clicking to form a polygon.


def __init__(self, ax, callback=None, 
 line_to_next=True, 
 useblit=True):

Create a new lasso.

*ax* is the axis on which to draw

*callback* is a function that will be called with arguments (*ax*, *line*, *verts*).
*verts* is a list of (x,y) pairs that define the polygon, with the first and 
last entries equal.

*line_to_next* controls whether or not a line is drawn to the current 
cursor position as the polygon is created

*useblit* = *True* is the only thorougly tested option.


self.axes = ax
self.figure = ax.figure
self.canvas = self.figure.canvas
self.useblit = useblit
self.line_to_next = line_to_next
if useblit:
self.background = self.canvas.copy_from_bbox(self.axes.bbox)


self.verts = []
self.line = None
self.callback = callback
self.cids = []
self.cids.append(self.canvas.mpl_connect('button_release_event', self.onrelease))
self.cids.append(self.canvas.mpl_connect('motion_notify_event', self.onmove))
self.cids.append(self.canvas.mpl_connect('draw_event', self.ondraw))

def ondraw(self, event):
 draw_event callback, to take care of some blit artifacts 
self.background = self.canvas.copy_from_bbox(self.axes.bbox)
if self.line:
self.axes.draw_artist(self.line)
self.canvas.blit(self.axes.bbox)

def do_callback(self, event):
 idle_event callback after polygon is finalized. 
# Clear out callbacks. 
for cid in self.cids:
self.canvas.mpl_disconnect(cid)
self.callback(self.axes, self.line, self.verts)
self.cleanup()

def cleanup(self):
 Remove the lasso line. 
# Clear out callbacks
for cid in self.cids:
self.canvas.mpl_disconnect(cid)
self.axes.lines.remove(self.line)
self.canvas.draw()

def finalize(self):
 Called when user makes the final right click 
# all done with callbacks pertaining to adding verts to the polygon
for cid in self.cids:
self.canvas.mpl_disconnect(cid)
self.cids = []

# Greater than three verts, since a triangle
# has a duplicate point to close the poly.
if len(self.verts)3:
# Matplotlib will not draw the closed polygon until we step completely
# out of this routine. It is desirable to see the closed polygon on screen
# in the event that *callback* takes a long time. So, delay callback until
# we get an idle event, which will signal that the closed polygon has also
# been drawn. 
self.cids.append(self.canvas.mpl_connect('idle_event', self.do_callback))
else:
print 'Need at least three vertices to make a polygon'
self.cleanup()

def draw_update(self):
 Adjust the polygon line, and blit it to the screen 
self.line.set_data(zip(*self.verts))
if self.useblit:
self.canvas.restore_region(self.background)
self.axes.draw_artist(self.line)
self.canvas.blit(self.axes.bbox)
else:
self.canvas.draw_idle()

def onmove(self, event):
 Update the next vertex position 
if self.line == None: return
self.verts[-1] = ((event.xdata, event.ydata))
if self.line_to_next:
self.draw_update()

def onrelease(self, event):
 User clicked the mouse. Add a vertex or finalize depending on mouse button. 
if self.verts is None: return
if event.inaxes != self.axes: return

if event.button == 3:
# Right click - close the polygon
# Set the dummy point to the first point
self.verts[-1] = self.verts[0]
self.draw_update()
self.finalize()
return

# The rest pertains to left click only
if event.button != 1: return

if self.line == None:
# Deal with the first 

Re: [matplotlib-devel] Alternate lasso: click to form polygon

2008-07-29 Thread Eric Firing
Eric Bruning wrote:
 I wanted something more precise (and easier on the carpal tunnel) than
 the included Lasso widget. Inspired by the existing Lasso, I forked
 out an alternate approach that creates a polygon with mouse clicks and
 returns a list of vertices to a callback function.
 
 See the attached for a demo. It's been tested with WxAgg running off
 recent svn. I'm using idle_event, which isn't mentioned in the docs
 for the released version.
 
 If there's interest, I'll put together a patch to add this to widgets.py.

Yes, there is interest--we should have this functionality if it can work 
on all interactive backends.

I gave it a quick try with gtk backend.  The polygon is drawn based on 
clicks, but nothing gets printed.  Is this expected?

Eric

 
 Thanks,
 Eric B
 
 
 
 
 -
 This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
 Build the coolest Linux based applications with Moblin SDK  win great prizes
 Grand prize is a trip for two to an Open Source event anywhere in the world
 http://moblin-contest.org/redirect.php?banner_id=100url=/
 
 
 
 
 ___
 Matplotlib-devel mailing list
 Matplotlib-devel@lists.sourceforge.net
 https://lists.sourceforge.net/lists/listinfo/matplotlib-devel


-
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK  win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100url=/
___
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel