Skip to content

Commit

Permalink
Merge pull request #3140 from CSSFrancis/widget_plot
Browse files Browse the repository at this point in the history
Horizontal Plotting using widgets
  • Loading branch information
jlaehne committed Jun 21, 2023
2 parents 1db9d1d + 3e7a7e0 commit 2ee7f4f
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 13 deletions.
6 changes: 6 additions & 0 deletions doc/user_guide/visualisation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,12 @@ The same example with the feature disabled:

.. _plot.customize_navigator:

.. versionadded:: 2.0.0
``plot_style`` keyword argument to allow for "horizontal" or "vertical" alignment of subplots (e.g. navigator
and signal) when using the `ipympl` or `widget` backends. A default value can also be set using the
:ref:`HyperSpy plot preferences <configuring-hyperspy-label>`.


Customizing the "navigator"
===========================

Expand Down
3 changes: 3 additions & 0 deletions hyperspy/defaults_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ class PlotConfig(t.HasTraits):
# Don't use t.Enum to list all possible matplotlib colormap to
# avoid importing matplotlib and building the list of colormap
# when importing hyperpsy
widget_plot_style = t.Enum(
['horizontal', 'vertical'],
label='Widget plot style: (only with ipympl)')
cmap_navigator = t.Str('gray',
label='Color map navigator',
desc='Set the default color map for the navigator.',
Expand Down
54 changes: 42 additions & 12 deletions hyperspy/drawing/mpl_he.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@
import logging

from traits.api import Undefined
import matplotlib as mpl

from hyperspy.drawing import widgets, signal1d, image
from hyperspy.defaults_parser import preferences

import warnings

_logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -180,17 +181,46 @@ def plot(self, **kwargs):
for key in ['power_spectrum', 'fft_shift']:
if key in kwargs:
self.signal_data_function_kwargs[key] = kwargs.pop(key)
if self.pointer is None:
pointer = self.assign_pointer()
if pointer is not None:
self.pointer = pointer(self.axes_manager)
self.pointer.color = 'red'
self.pointer.connect_navigate()
self.plot_navigator(**kwargs.pop('navigator_kwds', {}))
if pointer is not None:
self.navigator_plot.events.closed.connect(
self.pointer.disconnect, [])
self.plot_signal(**kwargs)
backend = mpl.get_backend()
if not "ipympl" in backend and "plot_style" in kwargs:
warnings.warn("The `plot_style` keyword is only used when the `ipympl` or `widget`"
"plotting backends are used.")
plot_style = kwargs.pop("plot_style", None)
# matplotlib plotting backend
def plot_sig_and_nav(plot_style):
if self.pointer is None:
pointer = self.assign_pointer()
if pointer is not None:
self.pointer = pointer(self.axes_manager)
self.pointer.color = 'red'
self.pointer.connect_navigate()
self.plot_navigator(**kwargs.pop('navigator_kwds', {}))
if pointer is not None:
self.navigator_plot.events.closed.connect(
self.pointer.disconnect, [])
self.plot_signal(**kwargs)
if "ipympl" in backend:
if plot_style not in ["vertical", "horizontal", None]:
raise ValueError("plot_style must be one of ['vertical', 'horizontal', None]")
if plot_style is None:
plot_style = preferences.Plot.widget_plot_style
# If widgets do not already exist, we will `display` them at the end
from ipywidgets.widgets import HBox, VBox
from IPython.display import display
if not self.navigator_plot:
display(self.signal_plot.figure.canvas)
elif plot_style == "horizontal":
display(HBox([self.navigator_plot.figure.canvas,self.signal_plot.figure.canvas]))
else: # plot_style == "vertical":
display(VBox([self.navigator_plot.figure.canvas, self.signal_plot.figure.canvas]))
if "ipympl" in backend:
import matplotlib.pyplot as plt
with plt.ioff():
plot_sig_and_nav(plot_style)
else:
plot_sig_and_nav(plot_style)



def assign_pointer(self):
if self.navigator_data_function is None:
Expand Down
58 changes: 58 additions & 0 deletions hyperspy/tests/drawing/test_horizontal_plotting.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Copyright 2007-2022 The HyperSpy developers
#
# This file is part of HyperSpy.
#
# HyperSpy 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.
#
# HyperSpy 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 HyperSpy. If not, see <https://www.gnu.org/licenses/#GPL>.
import pytest

import hyperspy.api as hs
import numpy as np
import matplotlib

ipympl = pytest.importorskip("ipympl")
ipywidgets = pytest.importorskip("ipywidgets")

class TestIPYMPL:
def test_horizontal(self, capsys):
matplotlib.use("module://ipympl.backend_nbagg")
s = hs.signals.Signal2D(np.random.random((4, 4, 2, 2)))
s.plot(plot_style="horizontal")
captured = capsys.readouterr()
assert("HBox(children=(Canvas(" in captured.out)

def test_vertical(self,capsys):
matplotlib.use("module://ipympl.backend_nbagg")
s = hs.signals.Signal2D(np.random.random((4, 4, 2, 2)))
s.plot(plot_style="vertical")
captured = capsys.readouterr()

assert("VBox(children=(Canvas(" in captured.out)

def test_only_signal(self,capsys):
matplotlib.use("module://ipympl.backend_nbagg")
s = hs.signals.Signal2D(np.random.random(( 2, 2)))
s.plot()
captured = capsys.readouterr()
assert("Canvas(toolbar=Toolbar(" in captured.out)

def test_warnings(self,):
with pytest.warns(UserWarning):
s = hs.signals.Signal2D(np.random.random(( 4, 2, 2)))
s.plot(plot_style="vertical")

def test_misspelling(self, ):
matplotlib.use("module://ipympl.backend_nbagg")
with pytest.raises(ValueError):
s = hs.signals.Signal2D(np.random.random((4, 2, 2)))
s.plot(plot_style="Vert")
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@

extras_require = {
"learning": ["scikit-learn>=1.0.1"],
"gui-jupyter": ["hyperspy_gui_ipywidgets>=1.1.0"],
"gui-jupyter": ["hyperspy_gui_ipywidgets>=1.1.0", "ipympl"],
# UPDATE BEFORE RELEASE
"gui-traitsui": ["hyperspy_gui_traitsui @ git+https://github.com/hyperspy/hyperspy_gui_traitsui#egg=hyperspy_gui_traitsui"],
#"gui-traitsui": ["hyperspy_gui_traitsui>=1.1.0"],
Expand Down
3 changes: 3 additions & 0 deletions upcoming_changes/3140.new.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Changes to :meth:`~.api.signals.BaseSignal.plot`:
- Allow Horizontal plotting using the `ipympl` or `widget` backends
- Add in gui preferences to set a default to horizontal or vertical plotting

0 comments on commit 2ee7f4f

Please sign in to comment.