class LassoSelection(PolygonToolBase): def __init__(self, ax, on_move=None, on_release=None, on_enter=None, useblit=True, line_props=None): super(LassoSelection, self).__init__(ax, on_move=on_move, on_release=on_release, on_enter=on_enter, useblit=useblit, line_props=line_props) self.shape = 'lasso' self.mode = 'lasso' self._prev_angle = 1e6 self._indicator = Rectangle((0, 0), 0, 0) self._indicator.set_visible(False) ax.add_patch(self._indicator) self._artists.append(self._indicator) def on_move(self, event): if self.verts is None or not self._busy: return if self.mode == 'polygon': self.verts[-1] = (event.xdata, event.ydata) else: # see if we are moving in the same direction point2 = (event.xdata, event.ydata) point1 = np.asarray(self.verts[-1], dtype=float) point2 = np.asarray(point2, dtype=float) dx, dy = point2 - point1 theta = np.arctan2(dy, dx) if theta == self._prev_angle: self.verts[-1] = (event.xdata, event.ydata) else: self.verts.append((event.xdata, event.ydata)) self._prev_angle = theta try: self._show_indicator() except TypeError: pass self.update() def on_mouse_release(self, event): self.mode = 'polygon' def on_mouse_press(self, event): if self._indicator.get_visible() or event.dblclick: self.verts = self.verts[:-1] self.finalize() return if not self._busy: self.start(event) self.mode = 'lasso' self.verts.append((event.xdata, event.ydata)) self.update() def start(self, event): super(LassoSelection, self).start(event) self._prev_angle = 1e6 def finalize(self): self.verts.append(self.verts[0]) self._indicator.set_visible(False) super(LassoSelection, self).finalize() def _show_indicator(self): if not self.verts: return bounds = self.ax.dataLim.bounds wid = float(bounds[2] - bounds[0]) hgt = float(bounds[3] - bounds[1]) orig = self.verts[0] curr = self.verts[-1] # see if we are within 2% in x and y if (abs(curr[0] - orig[0]) / wid < 0.02 and abs(curr[1] - orig[1]) / hgt < 0.02): wid /= 100. hgt /= 100. self._indicator.set_xy((orig[0] - wid / 2., orig[1] - hgt / 2.)) self._indicator.set_width(wid * 2) self._indicator.set_height(hgt * 2) if not self._indicator.get_visible(): self._indicator.set_visible(True) self.redraw() elif self._indicator.get_visible(): self._indicator.set_visible(False) self.redraw() @property def geometry(self): return self.verts @geometry.setter def geometry(self, verts): self.verts = verts self.update()