additions to lasso_demo.py

Hello. In case it is of use to anyone, here is a
revised lasso_demo.py that draws a polygon around
selected points, deletes points with a click of the
middle mouse button, and adds points with a right
click. Thanks John H for the help getting started.

I am just learning and do have a couple of questions.
Why is the lock on lasso needed in the original demo.
For my revised version, it works better without it (a
right click without dragging caused an infinite lock).

Also, I would have expected the callback function to
be executed directly on execution of the self.lasso =
Lasso(...) line in the onpress function, but instead
it is executed after the last line of the onpress
function. Why is this?

"""
draws a polygon around points selected with the mouse
deletes points selected with a middle click
adds points selected with a right click
"""
import os
from numpy import *
import glob

from matplotlib.widgets import Lasso
import matplotlib.mlab
from matplotlib.nxutils import points_inside_poly
from matplotlib.colors import colorConverter
from matplotlib.collections import
RegularPolyCollection
from matplotlib.patches import Polygon
from pylab import figure, show, nx
import pdb

class Datum:
  colorin = colorConverter.to_rgba('red')
  colorout = colorConverter.to_rgba('green')
  def __init__(self, x, y, include=False):
    self.x = x
    self.y = y
    if include:
      self.color = self.colorin
    else:
      self.color = self.colorout

class LassoManager:
  def __init__(self, ax, data):
    #self.flag = flag
    self.axes = ax
    self.canvas = ax.figure.canvas
    self.data = data

    self.Nxy = len(data)

    self.facecolors = [d.color for d in data]
    self.xys = [(d.x, d.y) for d in data]

    self.collection = RegularPolyCollection(
    fig.dpi, 6, sizes=(100,),
    facecolors=self.facecolors,
    offsets = self.xys,
    transOffset = ax.transData)

    ax.add_collection(self.collection)

    self.cid =
self.canvas.mpl_connect('button_press_event',
self.onpress)
    
  def callback(self, verts):
    ind = nx.nonzero(points_inside_poly(self.xys,
verts))
    if len(ind) == 0:
      return
    for i in range(self.Nxy):
      if i in ind:
        self.facecolors[i] = Datum.colorin
      else:
        self.facecolors[i] = Datum.colorout

    self.canvas.draw_idle()
    self.canvas.widgetlock.release(self.lasso)

    # draw polygon
    if len(self.axes.patches) > 0:
      self.axes.patches.pop()
    xyo=list()
    for i in ind:
      xyo.append(self.xys[i])
    rect = Polygon(xyo, facecolor='red', alpha=0.5)
    
    self.axes.add_patch(rect)
    self.canvas.draw_idle()
    
    del self.lasso
    
  def onpress(self, event):
    if self.canvas.widgetlock.locked():
      return
    if event.inaxes is None:
      return
    if event.button == 3:
     
ax.collections[0]._offsets.append((event.xdata,event.ydata))
     
ax.collections[0]._facecolors.append(colorConverter.to_rgba('blue'))
      self.canvas.draw_idle()
      return
    if event.button == 2:
      d = list()
      for i in ax.collections[0]._offsets:
       dis = sqrt( (event.xdata - i[0])**2 +
(event.ydata - i[1])**2 )
       d.append(dis)
      minn = min(d)
      minID = d.index(minn)
      ax.collections[0]._offsets.pop(minID)
      ax.collections[0]._facecolors.pop(minID)
      self.canvas.draw_idle()
      self.Nxy = self.Nxy-1
      return
    
    self.lasso = Lasso(event.inaxes,(event.xdata,
event.ydata), self.callback)
    # acquire a lock on the widget drawing
    # self.canvas.widgetlock(self.lasso)

data = [Datum(*xy) for xy in nx.mlab.rand(100,2)]

fig = figure()
ax = fig.add_subplot(111, xlim=(0,1), ylim=(0,1),
autoscale_on=False)
flag = 0
lman = LassoManager(ax, data)
ax.grid('on')
show()

···

____________________________________________________________________________________
Bored stiff? Loosen up...
Download and play hundreds of games for free on Yahoo! Games.
http://games.yahoo.com/games/front

I am just learning and do have a couple of questions.
Why is the lock on lasso needed in the original demo.
For my revised version, it works better without it (a
right click without dragging caused an infinite lock).

The locking is designed to prevent conflict with other resources that
may be competing with you to draw to the screen. Ie, if you enable
zoom to rect mode and the matplotlib backend is drawing a zoom
rectangle and you are drawing a lasso. In this case you'll get an
exception which should remind you that the resources are already
taken. There may be a better way to enable resource sharing, though..

I'm not sure about the lock you experienced right now.....

Also, I would have expected the callback function to
be executed directly on execution of the self.lasso =
Lasso(...) line in the onpress function, but instead
it is executed after the last line of the onpress
function. Why is this?

Well, the callback is triggered after the mouse us released, ie after
the lasso is complete.
The onpress sets up the lasso widget, which in turn connects to the
mouse move and mouse release events. When you are done with the lasso
and release the mouse, it triggers your callback. You could change
this behavior by subclassing Lasso -- it's a pretty small class that
lives in matplotlib.widgets. One could do everything on mouse motion,
which could be computationally expensive but might be what you are
looking for. I'm not quite sure what you are expecting to happen.

JDH

···

On 2/5/07, JJ <josh8912@...9...> wrote: