Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix drawstyle plot_histogram #2810

Merged
merged 8 commits into from
Oct 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Bug Fixes
- Fix parsing EELS aperture label with unexpected value, for example 'Imaging' instead of '5 mm' (`#2772 <https://github.com/hyperspy/hyperspy/issues/2772>`_)
- Lazy datasets can now be saved out as blockfiles (blo) (`#2774 <https://github.com/hyperspy/hyperspy/issues/2774>`_)
- ComplexSignals can now be rebinned without error (`#2789 <https://github.com/hyperspy/hyperspy/issues/2789>`_)
- Method `estimate_parameters` in `Polynomial` component now supports order
- Method :py:meth:`~._components.polynomial.Polynomial.estimate_parameters` of the :py:class:`~._components.polynomial.Polynomial` component now supports order
greater than 10 (`#2790 <https://github.com/hyperspy/hyperspy/issues/2790>`_)
- Update minimal requirement of dependency importlib_metadata from
>= 1.6.0 to >= 3.6 (`#2793 <https://github.com/hyperspy/hyperspy/issues/2793>`_)
Expand Down Expand Up @@ -48,7 +48,7 @@ Bug Fixes
- Fix :py:meth:`~._signals.signal1d.Signal1D.shift1D`, :py:meth:`~._signals.signal1d.Signal1D.align1D` and :py:meth:`~._signals.eels.EELSSpectrum.align_zero_loss_peak` regression with navigation dimension larger than one (`#2729 <https://github.com/hyperspy/hyperspy/issues/2729>`_)
- Fix disconnecting events when closing figure and :py:meth:`~._signals.signal1d.Signal1D.remove_background` is active (`#2734 <https://github.com/hyperspy/hyperspy/issues/2734>`_)
- Fix :py:meth:`~.signal.BaseSignal.map` regression of lazy signal with navigation chunks of size of 1 (`#2748 <https://github.com/hyperspy/hyperspy/issues/2748>`_)
- Fix unclear error message when reading a hspy file saved using blosc compression and `hdf5plugin` hasn't been imported previously (`#2760 <https://github.com/hyperspy/hyperspy/issues/2760>`_)
- Fix unclear error message when reading a hspy file saved using blosc compression and ``hdf5plugin`` hasn't been imported previously (`#2760 <https://github.com/hyperspy/hyperspy/issues/2760>`_)
- Fix saving ``navigator`` of lazy signal (`#2763 <https://github.com/hyperspy/hyperspy/issues/2763>`_)


Expand Down
4 changes: 2 additions & 2 deletions doc/user_guide/visualisation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -818,9 +818,9 @@ and provide the legend labels:
>>> import scipy.misc
>>> s = hs.signals.Signal1D(scipy.misc.ascent()[100:160:10])
>>> color_list = ['red', 'red', 'blue', 'blue', 'red', 'red']
>>> line_style_list = ['-','--','steps','-.',':','-']
>>> linestyle_list = ['-', '--', '-.', ':', '-']
>>> hs.plot.plot_spectra(s, style='cascade', color=color_list,
>>> line_style=line_style_list,legend='auto')
>>> linestyle=linestyle_list, legend='auto')

.. figure:: images/plot_spectra_color.png
:align: center
Expand Down
135 changes: 70 additions & 65 deletions hyperspy/drawing/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,52 +403,46 @@ def set_xaxis_lims(mpl_ax, hs_axis):
mpl_ax.set_xlim(x_axis_lower_lim, x_axis_upper_lim)


def _make_overlap_plot(spectra, ax, color="blue", line_style='-'):
if isinstance(color, str):
color = [color] * len(spectra)
if isinstance(line_style, str):
line_style = [line_style] * len(spectra)
for spectrum_index, (spectrum, color, line_style) in enumerate(
zip(spectra, color, line_style)):
def _make_overlap_plot(spectra, ax, color, linestyle, **kwargs):
for spectrum_index, (spectrum, color, linestyle) in enumerate(
zip(spectra, color, linestyle)):
x_axis = spectrum.axes_manager.signal_axes[0]
spectrum = _transpose_if_required(spectrum, 1)
ax.plot(x_axis.axis, spectrum.data, color=color, ls=line_style)
ax.plot(x_axis.axis, spectrum.data, color=color, ls=linestyle,
**kwargs)
set_xaxis_lims(ax, x_axis)
_set_spectrum_xlabel(spectra if isinstance(spectra, hs.signals.BaseSignal)
else spectra[-1], ax)
ax.set_ylabel('Intensity')
ax.autoscale(tight=True)


def _make_cascade_subplot(
spectra, ax, color="blue", line_style='-', padding=1):
def _make_cascade_subplot(spectra, ax, color, linestyle, padding=1, **kwargs):
max_value = 0
for spectrum in spectra:
spectrum_yrange = (np.nanmax(spectrum.data) -
np.nanmin(spectrum.data))
if spectrum_yrange > max_value:
max_value = spectrum_yrange
if isinstance(color, str):
color = [color] * len(spectra)
if isinstance(line_style, str):
line_style = [line_style] * len(spectra)
for spectrum_index, (spectrum, color, line_style) in enumerate(
zip(spectra, color, line_style)):
for spectrum_index, (spectrum, color, linestyle) in enumerate(
zip(spectra, color, linestyle)):
x_axis = spectrum.axes_manager.signal_axes[0]
spectrum = _transpose_if_required(spectrum, 1)
data_to_plot = ((spectrum.data - spectrum.data.min()) /
float(max_value) + spectrum_index * padding)
ax.plot(x_axis.axis, data_to_plot, color=color, ls=line_style)
ax.plot(x_axis.axis, data_to_plot, color=color, ls=linestyle,
**kwargs)
set_xaxis_lims(ax, x_axis)
_set_spectrum_xlabel(spectra if isinstance(spectra, hs.signals.BaseSignal)
else spectra[-1], ax)
ax.set_yticks([])
ax.autoscale(tight=True)


def _plot_spectrum(spectrum, ax, color="blue", line_style='-'):
def _plot_spectrum(spectrum, ax, color="blue", linestyle='-', **kwargs):
x_axis = spectrum.axes_manager.signal_axes[0]
ax.plot(x_axis.axis, spectrum.data, color=color, ls=line_style)
ax.plot(x_axis.axis, spectrum.data, color=color, ls=linestyle,
**kwargs)
set_xaxis_lims(ax, x_axis)


Expand Down Expand Up @@ -1165,7 +1159,8 @@ def plot_spectra(
spectra,
style='overlap',
color=None,
line_style=None,
linestyle=None,
drawstyle='default',
padding=1.,
legend=None,
legend_picking=True,
Expand All @@ -1190,12 +1185,18 @@ def plot_spectra(
For a list, if its length is less than the number of spectra to plot,
the colors will be cycled. If `None`, use default matplotlib color
cycle.
line_style: {None, matplotlib line style, list of line_styles}, optional
linestyle : {None, matplotlib line style, list of linestyles}, optional
Sets the line style of the plots (no action on 'heatmap').
The main line style are '-','--','steps','-.',':'.
The main line style are ``'-'``, ``'--'``, ``'-.'``, ``':'``.
For a list, if its length is less than the number of
spectra to plot, line_style will be cycled. If
If `None`, use continuous lines, eg: ('-','--','steps','-.',':').
spectra to plot, linestyle will be cycled.
If `None`, use continuous lines (same as ``'-'``).
drawstyle : {'default', 'steps', 'steps-pre', 'steps-mid', 'steps-post'},
default 'default'
The drawstyle determines how the points are connected, no action with
``style='heatmap'``. See
:py:meth:`matplotlib.lines.Line2D.set_drawstyle` for more information.
The ``'default'`` value is defined by matplotlib.
padding : float, optional, default 1.0
jlaehne marked this conversation as resolved.
Show resolved Hide resolved
Option for "cascade". 1 guarantees that there is no overlapping.
However, in many cases, a value between 0 and 1 can produce a tighter
Expand Down Expand Up @@ -1243,6 +1244,16 @@ def plot_spectra(

"""
import hyperspy.signal
if 'line_style' in kwargs.keys():
from hyperspy.misc.utils import deprecation_warning
deprecation_warning("`line_style` has been renamed to `linestyle` and "
"will be removed in HyperSpy 2.0.")
if linestyle is None:
linestyle = kwargs.pop('line_style')
else:
raise ValueError("Both argument `line_style` and `linestyle` have "
"been provided and only one should be used: use "
"`linestyle` only.")

def _reverse_legend(ax_, legend_loc_):
"""
Expand Down Expand Up @@ -1279,17 +1290,13 @@ def _reverse_legend(ax_, legend_loc_):
color = itertools.cycle(
plt.rcParams['axes.prop_cycle'].by_key()["color"])

if line_style is not None:
if isinstance(line_style, str):
line_style = itertools.cycle([line_style])
elif hasattr(line_style, "__iter__"):
line_style = itertools.cycle(line_style)
else:
raise ValueError("line_style must be None, a valid matplotlib "
"line_style string or a list of valid matplotlib "
"line_style.")
if linestyle is not None:
if isinstance(linestyle, str):
linestyle = itertools.cycle([linestyle])
elif hasattr(linestyle, "__iter__"):
linestyle = itertools.cycle(linestyle)
else:
line_style = ['-'] * len(spectra)
linestyle = ['-'] * len(spectra)

if legend is not None:
if isinstance(legend, str):
Expand All @@ -1304,39 +1311,38 @@ def _reverse_legend(ax_, legend_loc_):
fig = plt.figure(**kwargs)
if ax is None:
ax = fig.add_subplot(111)
_make_overlap_plot(spectra,
ax,
color=color,
line_style=line_style,)
_make_overlap_plot(spectra, ax, color, linestyle, drawstyle=drawstyle)
if legend is not None:
ax.legend(legend, loc=legend_loc)
_reverse_legend(ax, legend_loc)
if legend_picking is True:
animate_legend(fig=fig, ax=ax)

elif style == 'cascade':
if fig is None:
fig = plt.figure(**kwargs)
if ax is None:
ax = fig.add_subplot(111)
_make_cascade_subplot(spectra,
ax,
color=color,
line_style=line_style,
padding=padding)
_make_cascade_subplot(spectra, ax, color, linestyle, padding=padding,
drawstyle=drawstyle)
if legend is not None:
plt.legend(legend, loc=legend_loc)
_reverse_legend(ax, legend_loc)
if legend_picking is True:
animate_legend(fig=fig, ax=ax)

elif style == 'mosaic':
default_fsize = plt.rcParams["figure.figsize"]
figsize = (default_fsize[0], default_fsize[1] * len(spectra))
fig, subplots = plt.subplots(
len(spectra), 1, figsize=figsize, **kwargs)
if legend is None:
legend = [legend] * len(spectra)
for spectrum, ax, color, line_style, legend in zip(
spectra, subplots, color, line_style, legend):
for spectrum, ax, color, linestyle, legend in zip(
spectra, subplots, color, linestyle, legend):
spectrum = _transpose_if_required(spectrum, 1)
_plot_spectrum(spectrum, ax, color=color, line_style=line_style)
_plot_spectrum(spectrum, ax, color=color, linestyle=linestyle,
drawstyle=drawstyle)
ax.set_ylabel('Intensity')
if legend is not None:
ax.set_title(legend)
Expand Down Expand Up @@ -1439,39 +1445,40 @@ def plot_histograms(signal_list,
bins='fd',
range_bins=None,
color=None,
line_style=None,
linestyle=None,
legend='auto',
fig=None,
**kwargs):
"""Plot the histogram of every signal in the list in one figure.

This function creates a histogram for each signal and plots the list with
the `utils.plot.plot_spectra` function.
the :py:func:`~.drawing.utils.plot_spectra` function.

Parameters
----------
signal_list : iterable
Ordered list of spectra to plot. If `style` is "cascade" or "mosaic",
the spectra can have different size and axes.
Ordered list of spectra to plot. If ``style`` is ``"cascade"`` or
``"mosaic"``, the spectra can have different size and axes.
bins : {int, list, str}, optional
If bins is a string, then it must be one of:
'knuth' : use Knuth's rule to determine bins,
'scott' : use Scott's rule to determine bins,
'fd' : use the Freedman-diaconis rule to determine bins,
'blocks' : use bayesian blocks for dynamic bin widths.

- ``'knuth'`` : use Knuth's rule to determine bins,
- ``'scott'`` : use Scott's rule to determine bins,
- ``'fd'`` : use the Freedman-diaconis rule to determine bins,
- ``'blocks'`` : use bayesian blocks for dynamic bin widths.
range_bins : {None, tuple}, optional
The minimum and maximum range for the histogram. If not specified,
it will be (x.min(), x.max()).
it will be (``x.min()``, ``x.max()``).
color : {None, valid matplotlib color, list of colors}, optional
Sets the color of the lines of the plots. For a list, if its length is
less than the number of spectra to plot, the colors will be cycled.
If `None`, use default matplotlib color cycle.
line_style: {None, valid matplotlib line style, list of line styles},
optional
The main line styles are '-','--','steps','-.',':'.
linestyle: {None, valid matplotlib line style, list of line styles},
optional
The main line styles are ``'-'``, ``'--'``, ``'-.'``, ``':'``.
For a list, if its length is less than the number of
spectra to plot, line_style will be cycled.
If `None`, use continuous lines, eg: ('-','--','steps','-.',':')
spectra to plot, linestyle will be cycled.
If `None`, use continuous lines (same as ``'-'``).
legend: {None, list of str, 'auto'}, optional
Display a legend. If 'auto', the title of each spectra
(metadata.General.title) is used.
Expand All @@ -1490,7 +1497,7 @@ def plot_histograms(signal_list,

>>> img = hs.signals.Signal2D(np.random.chisquare(1,[10,10,100]))
>>> img2 = hs.signals.Signal2D(np.random.chisquare(2,[10,10,100]))
>>> hs.plot.plot_histograms([img,img2],legend=['hist1','hist2'])
>>> hs.plot.plot_histograms([img, img2], legend=['hist1', 'hist2'])

Returns
-------
Expand All @@ -1502,10 +1509,9 @@ def plot_histograms(signal_list,
for obj in signal_list:
hists.append(obj.get_histogram(bins=bins,
range_bins=range_bins, **kwargs))
if line_style is None:
line_style = 'steps'
return plot_spectra(hists, style='overlap', color=color,
line_style=line_style, legend=legend, fig=fig)
linestyle=linestyle, drawstyle='steps-mid',
legend=legend, fig=fig)


def picker_kwargs(value, kwargs={}):
Expand All @@ -1516,4 +1522,3 @@ def picker_kwargs(value, kwargs={}):
kwargs['picker'] = value

return kwargs

Original file line number Diff line number Diff line change
Expand Up @@ -392,9 +392,9 @@
"import scipy.misc\n",
"s = hs.signals.Signal1D(scipy.misc.ascent()[100:160:10])\n",
"color_list = ['red', 'red', 'blue', 'blue', 'red', 'red']\n",
"line_style_list = ['-','--','steps','-.',':','-']\n",
"linestyle_list = ['-', '--', '-.', ':', '-']\n",
"hs.plot.plot_spectra(s, style='cascade', color=color_list,\n",
"line_style=line_style_list,legend='auto')"
"linestyle=linestyle_list, legend='auto')"
]
},
{
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions hyperspy/tests/drawing/test_plot_histograms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copyright 2007-2021 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 <http://www.gnu.org/licenses/>.

import hyperspy.api as hs
import numpy as np


def test_plot_histograms():
img = hs.signals.Signal2D(np.random.chisquare(1,[10,10,100]))
img2 = hs.signals.Signal2D(np.random.chisquare(2,[10,10,100]))
ax = hs.plot.plot_histograms([img, img2], legend=['hist1', 'hist2'])
assert len(ax.lines) == 2
l1 = ax.lines[0]
assert l1.get_drawstyle() == 'steps-mid'
24 changes: 24 additions & 0 deletions hyperspy/tests/drawing/test_plot_signal1d.py
Original file line number Diff line number Diff line change
Expand Up @@ -333,3 +333,27 @@ def test_plot_autoscale(autoscale):
s.axes_manager.events.indices_changed.trigger(s.axes_manager)

return s._plot.signal_plot.figure


@pytest.mark.mpl_image_compare(baseline_dir=baseline_dir,
tolerance=default_tol, style=style_pytest_mpl)
@pytest.mark.parametrize('linestyle', [None, '-', ['-', '--']])
def test_plot_spectra_linestyle(linestyle):
s = hs.signals.Signal1D(np.arange(100).reshape(2, 50))
ax = hs.plot.plot_spectra(s, linestyle=linestyle)

return ax.get_figure()


def test_plot_spectra_linestyle_error():
from hyperspy.exceptions import VisibleDeprecationWarning
s = hs.signals.Signal1D(np.arange(100).reshape(2, 50))
with pytest.warns(VisibleDeprecationWarning):
hs.plot.plot_spectra(s, line_style='--')

with pytest.raises(ValueError):
with pytest.warns(VisibleDeprecationWarning):
hs.plot.plot_spectra(s, linestyle='-', line_style='--')

with pytest.raises(ValueError):
hs.plot.plot_spectra(s, linestyle='invalid')
1 change: 1 addition & 0 deletions upcoming_changes/2810.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix :py:func:`~.drawing.utils.plot_histograms` drawstyle following matplotlib API change
1 change: 1 addition & 0 deletions upcoming_changes/2810.deprecation.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Rename ``line_style`` to ``linestyle`` in :py:func:`~.drawing.utils.plot_spectra` to match matplotlib argument name