Source code for mpl_qt_viz.roiSelection._creatorWidgets.lasso

# Copyright 2018-2021 Nick Anthony, Backman Biophotonics Lab, Northwestern University
#
# This file is part of mpl_qt_viz.
#
# mpl_qt_viz is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# mpl_qt_viz is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with mpl_qt_viz.  If not, see <https://www.gnu.org/licenses/>.

from __future__ import annotations
import typing
from matplotlib.image import AxesImage
from matplotlib.patches import Polygon
from shapely.geometry import Polygon as shapelyPolygon, LinearRing, MultiPolygon
from ._base import CreatorWidgetBase

if typing.TYPE_CHECKING:
    from mpl_qt_viz.roiSelection import AxManager



[docs]class LassoCreator(CreatorWidgetBase): """Allows the user to select a region with freehand drawing. Args: axMan: A reference to the `AxManager` object used to manage drawing the matplotlib `Axes` that this selector widget is active on. image: A reference to a matplotlib `AxesImage`. Selectors may use this reference to get information such as data values from the image for computer vision related tasks. onselect: A callback function that will be called when the selector finishes a selection. """ def __init__(self, axMan: AxManager, image: AxesImage, onselect=None): super().__init__(axMan, image) self.onselect = onselect self.verts = None self.polygon = Polygon([[0, 0]], facecolor=(0, 0, 1, .1), animated=True, edgecolor=(0, 0, 1, .8)) self.polygon.set_visible(False) self.addArtist(self.polygon) # self.set_active(True) #needed for blitting to work
[docs] @staticmethod def getHelpText(): return "Click and drag to draw a freehand shape."
[docs] def reset(self): self.verts = None self.polygon.set_visible(False)
def _press(self, event): self.verts = [(event.xdata, event.ydata)] self.set_visible(True) def _release(self, event): if event.button == 1: #Left click if (self.verts is not None) and (self.onselect is not None): try: l = shapelyPolygon(LinearRing(self.verts)) except ValueError: return # If the user clicks without dragging there will just be a single coordinate, this will result in an error when trying to convert to a `LinearRing` l = l.buffer(0) l = l.simplify(l.length ** .5 / 5, preserve_topology=False) if isinstance(l, MultiPolygon): # There is a chance for this to be a Multipolygon. l = max(l, key=lambda a: a.area) # To fix this we extract the largest polygon from the multipolygon handles = l.exterior.coords self.onselect(self.verts, handles) def _ondrag(self, event): if self.verts is None: return self.verts.append((event.xdata, event.ydata)) self.polygon.set_xy(self.verts) self.axMan.update()