Source code for mpl_qt_viz.roiSelection._utilityClasses.adjustableSelector

# 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 .._modifierWidgets import PolygonModifier
if typing.TYPE_CHECKING:
    from matplotlib.image import AxesImage
    from mpl_qt_viz.roiSelection import AxManager
    from .._creatorWidgets._base import CreatorWidgetBase


[docs]class AdjustableSelector: """This class manages an roi selector. By setting `adjustable` true then when the selector calls its `onselect` function the results will be passed on to a PolygonInteractor for further tweaking. Tweaking can be confirmed by pressing enter. at the end the selector will pass a set of coordinates to the `onfinished` function if it has been set. Args: ax: A matplotlib `Axes` to interact with. image: A matplotlib `AxesImage`. Some selectors use the data in this image for their selection. selectorClass: A class that implements `SelectorWidgetBase`. This will be the intial selector used. onfinished: a callback function when the selection finished. The function should accept a single input argument which is a list of the 2d coordinated outlining the selected polygon. """ def __init__(self, axManager: AxManager, image: AxesImage, selectorClass: typing.Type[CreatorWidgetBase], onfinished: typing.Optional[typing.Callable] = None, onPolyTuningCancelled: typing.Optional[typing.Callable] = None): self.axMan = axManager self.image = image self.selector: CreatorWidgetBase = selectorClass(self.axMan, self.image, onselect=self._goPoly) self.selector.active = False self.adjuster = PolygonModifier(self.axMan, onselect=self.finish, onCancelled=onPolyTuningCancelled) self.adjuster.active = False self.adjustable = False self.onfinished = onfinished
[docs] def reset(self): """Clear all artists used by the selector. :todo: Shouldn't this check if the `adjuster` is active and reset it as well?""" self.selector.reset()
@property def adjustable(self) -> bool: """Determines whether or not the polygon interactor will be used to adjust the selection at the end of the initial selection.""" return self._adjustable @adjustable.setter def adjustable(self, enabled: bool): self._adjustable = enabled if enabled: self.selector.onselect = self._goPoly else: self.selector.onselect = self.finish
[docs] def setActive(self, active: bool): """This activates the selector. for a looping selection you should call this method from the onfinished function.""" if active: self.selector.set_active(True) self.selector.set_visible(True) else: self.adjuster.set_active(False) self.adjuster.set_visible(False) self.selector.set_visible(False) self.selector.set_active(False)
[docs] def setSelector(self, selectorClass: typing.Type): """Remove the current selector and replace it with a new type of selector. Args: selectorClass: A class the implements `SelectorWidgetBase`. """ self.selector.removeArtists() self.selector.set_active(False) self.selector = selectorClass(self.axMan, self.image) self.adjustable = self.adjustable
def _goPoly(self, verts: typing.Sequence[typing.Tuple[float, float]], handles: typing.Sequence[typing.Tuple[float, float]]): """This callback is registered with the selectorWidget when we are in adjustable mode. Upon completion of the initial selection this callback passes the handles to the polygon adjuster.""" self.selector.set_active(False) self.selector.set_visible(False) self.adjuster.set_active(True) self.adjuster.initialize([handles]) # It's important that this happens after `set_active` otherwise we get weird drawing issues
[docs] def finish(self, verts, handles): """This callback is registered with the selectorWidget when we are not in adjustable mode. In adjustable mode it is instead registered with the polygon adjuster. It deactivates the class and calls the `onfinished` callback.""" self.setActive(False) if self.onfinished is not None: if self.adjustable: self.onfinished(verts[0]) # The polygon interactor has a slightly different signature than the `creatorwidgets` else: self.onfinished(verts)