From 0e2f047dca9976258f9605fe701e1943135c9004 Mon Sep 17 00:00:00 2001 From: David Stansby Date: Fri, 19 May 2023 10:36:55 +0100 Subject: [PATCH] Factor out layer selecton and MPL figure creation --- docs/changelog.rst | 5 ++ src/napari_matplotlib/base.py | 144 ++++++++++++++++++---------------- 2 files changed, 82 insertions(+), 67 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index e0c8da34..be0ea082 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -4,6 +4,11 @@ Changelog 0.3.0 ----- +New features +~~~~~~~~~~~~ +- Added `MPLWidget` as a widget containing just a Matplotlib canvas + without any association with a napari viewer. + Visual improvements ~~~~~~~~~~~~~~~~~~~ - The background of ``napari-matplotlib`` figures and axes is now transparent. diff --git a/src/napari_matplotlib/base.py b/src/napari_matplotlib/base.py index 1480fdca..d6a39f4c 100644 --- a/src/napari_matplotlib/base.py +++ b/src/napari_matplotlib/base.py @@ -17,10 +17,10 @@ # Icons modified from # https://github.com/matplotlib/matplotlib/tree/main/lib/matplotlib/mpl-data/images ICON_ROOT = Path(__file__).parent / "icons" -__all__ = ["NapariMPLWidget"] +__all__ = ["MPLWidget", "NapariMPLWidget"] -class NapariMPLWidget(QWidget): +class MPLWidget(QWidget): """ Widget containing a Matplotlib canvas and toolbar. @@ -28,30 +28,14 @@ class NapariMPLWidget(QWidget): `~matplotlib.figure.Figure`, and an associated toolbar. It is not responsible for creating any Axes, because different widgets may want to implement different subplot layouts. - - This class also handles callbacks to automatically update figures when - the layer selection or z-step is changed in the napari viewer. To take - advantage of this sub-classes should implement the ``clear()`` and - ``draw()`` methods. - - Attributes - ---------- - viewer : `napari.Viewer` - Main napari viewer. - canvas : matplotlib.backends.backend_qt5agg.FigureCanvas - Matplotlib canvas. - layers : `list` - List of currently selected napari layers. """ def __init__( self, - napari_viewer: napari.viewer.Viewer, parent: Optional[QWidget] = None, ): super().__init__(parent=parent) - self.viewer = napari_viewer self.canvas = FigureCanvas() self.canvas.figure.patch.set_facecolor("none") @@ -65,6 +49,81 @@ def __init__( self.layout().addWidget(self.toolbar) self.layout().addWidget(self.canvas) + @property + def figure(self) -> Figure: + """Matplotlib figure.""" + return self.canvas.figure + + def add_single_axes(self) -> None: + """ + Add a single Axes to the figure. + + The Axes is saved on the ``.axes`` attribute for later access. + """ + self.axes = self.figure.subplots() + self.apply_napari_colorscheme(self.axes) + + @staticmethod + def apply_napari_colorscheme(ax: Axes) -> None: + """Apply napari-compatible colorscheme to an Axes.""" + # changing color of axes background to transparent + ax.set_facecolor("none") + + # changing colors of all axes + for spine in ax.spines: + ax.spines[spine].set_color("white") + + ax.xaxis.label.set_color("white") + ax.yaxis.label.set_color("white") + + # changing colors of axes labels + ax.tick_params(axis="x", colors="white") + ax.tick_params(axis="y", colors="white") + + def _replace_toolbar_icons(self) -> None: + # Modify toolbar icons and some tooltips + for action in self.toolbar.actions(): + text = action.text() + if text == "Pan": + action.setToolTip( + "Pan/Zoom: Left button pans; Right button zooms; " + "Click once to activate; Click again to deactivate" + ) + if text == "Zoom": + action.setToolTip( + "Zoom to rectangle; Click once to activate; " + "Click again to deactivate" + ) + if len(text) > 0: # i.e. not a separator item + icon_path = os.path.join(ICON_ROOT, text + ".png") + action.setIcon(QIcon(icon_path)) + + +class NapariMPLWidget(MPLWidget): + """ + Widget containing a Matplotlib canvas and toolbar. + + In addition to `BaseNapariMPLWidget`, this class handles callbacks + to automatically update figures when the layer selection or z-step + is changed in the napari viewer. To take advantage of this sub-classes + should implement the ``clear()`` and ``draw()`` methods. + + Attributes + ---------- + viewer : `napari.Viewer` + Main napari viewer. + layers : `list` + List of currently selected napari layers. + """ + + def __init__( + self, + napari_viewer: napari.viewer.Viewer, + parent: Optional[QWidget] = None, + ): + super().__init__(parent=parent) + + self.viewer = napari_viewer self._setup_callbacks() self.layers: List[napari.layers.Layer] = [] @@ -73,11 +132,6 @@ def __init__( #: Type of layer taken as input input_layer_types: Tuple[napari.layers.Layer, ...] = (napari.layers.Layer,) - @property - def figure(self) -> Figure: - """Matplotlib figure.""" - return self.canvas.figure - @property def n_selected_layers(self) -> int: """ @@ -139,32 +193,6 @@ def draw(self) -> None: This is a no-op, and is intended for derived classes to override. """ - def add_single_axes(self) -> None: - """ - Add a single Axes to the figure. - - The Axes is saved on the ``.axes`` attribute for later access. - """ - self.axes = self.figure.subplots() - self.apply_napari_colorscheme(self.axes) - - @staticmethod - def apply_napari_colorscheme(ax: Axes) -> None: - """Apply napari-compatible colorscheme to an Axes.""" - # changing color of axes background to transparent - ax.set_facecolor("none") - - # changing colors of all axes - for spine in ax.spines: - ax.spines[spine].set_color("white") - - ax.xaxis.label.set_color("white") - ax.yaxis.label.set_color("white") - - # changing colors of axes labels - ax.tick_params(axis="x", colors="white") - ax.tick_params(axis="y", colors="white") - def _on_update_layers(self) -> None: """ Function is called when self.layers is updated via @@ -173,24 +201,6 @@ def _on_update_layers(self) -> None: This is a no-op, and is intended for derived classes to override. """ - def _replace_toolbar_icons(self) -> None: - # Modify toolbar icons and some tooltips - for action in self.toolbar.actions(): - text = action.text() - if text == "Pan": - action.setToolTip( - "Pan/Zoom: Left button pans; Right button zooms; " - "Click once to activate; Click again to deactivate" - ) - if text == "Zoom": - action.setToolTip( - "Zoom to rectangle; Click once to activate; " - "Click again to deactivate" - ) - if len(text) > 0: # i.e. not a separator item - icon_path = os.path.join(ICON_ROOT, text + ".png") - action.setIcon(QIcon(icon_path)) - class NapariNavigationToolbar(NavigationToolbar2QT): """Custom Toolbar style for Napari.""" pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy