Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/0.8.x'
Browse files Browse the repository at this point in the history
  • Loading branch information
francisco-dlp committed Aug 10, 2015
2 parents 8065137 + 3656fa9 commit aa9b0ba
Show file tree
Hide file tree
Showing 19 changed files with 285 additions and 119 deletions.
Binary file added doc/user_guide/images/divergent_cmap.png
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.
209 changes: 129 additions & 80 deletions doc/user_guide/visualisation.rst

Large diffs are not rendered by default.

19 changes: 13 additions & 6 deletions hyperspy/_signals/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,11 @@ def plot(self,
scalebar_color="white",
axes_ticks=None,
auto_contrast=True,
saturated_pixels=0.2,
saturated_pixels=0,
vmin=None,
vmax=None,
no_nans=False,
centre_colormap="auto",
**kwargs
):
"""Plot image.
Expand Down Expand Up @@ -117,14 +118,19 @@ def plot(self,
If True, the contrast is stretched for each image using the
`saturated_pixels` value. Default True.
saturated_pixels: scalar
The percentage of pixels that are left out of the bounds. For example,
the low and high bounds of a value of 1 are the 0.5% and 99.5%
percentiles. It must be in the [0, 100] range.
The percentage of pixels that are left out of the bounds.
For example, the low and high bounds of a value of 1 are the 0.5%
and 99.5% percentiles. It must be in the [0, 100] range.
vmin, vmax : scalar, optional
`vmin` and `vmax` are used to normalize luminance data. If at least one of them is given
`auto_contrast` is set to False and any missing values are calculated automatically.
`vmin` and `vmax` are used to normalize luminance data. If at
least one of them is given `auto_contrast` is set to False and any
missing values are calculated automatically.
no_nans : bool, optional
If True, set nans to zero for plotting.
centre_colormap : {"auto", True, False}
If True the centre of the color scheme is set to zero. This is
specially useful when using diverging color schemes. If "auto"
(default), diverging color schemes are automatically centred.
**kwargs, optional
Additional key word arguments passed to matplotlib.imshow()
Expand All @@ -139,5 +145,6 @@ def plot(self,
vmin=vmin,
vmax=vmax,
no_nans=no_nans,
centre_colormap=centre_colormap,
**kwargs
)
5 changes: 5 additions & 0 deletions hyperspy/drawing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,8 @@
#
# You should have received a copy of the GNU General Public License
# along with HyperSpy. If not, see <http://www.gnu.org/licenses/>.


import matplotlib

matplotlib.rcParams["image.cmap"] = "gray"
29 changes: 25 additions & 4 deletions hyperspy/drawing/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
from hyperspy.gui.tools import ImageContrastEditor
from hyperspy.misc import math_tools
from hyperspy.misc import rgb_tools
from hyperspy.misc.image_tools import contrast_stretching
from hyperspy.misc.image_tools import (contrast_stretching,
MPL_DIVERGING_COLORMAPS,
centre_colormap_values)
from hyperspy.drawing.figure import BlittedFigure


Expand Down Expand Up @@ -61,6 +63,10 @@ class ImagePlot(BlittedFigure):
The percentage of pixels that are left out of the bounds. For example,
the low and high bounds of a value of 1 are the 0.5% and 99.5%
percentiles. It must be in the [0, 100] range.
centre_colormap : {"auto", True, False}
If True the centre of the color scheme is set to zero. This is
specially useful when using diverging color schemes. If "auto"
(default), diverging color schemes are automatically centred.
"""

Expand Down Expand Up @@ -95,6 +101,7 @@ def __init__(self):
self._user_axes_ticks = None
self._auto_axes_ticks = True
self.no_nans = False
self.centre_colormap = "auto"

@property
def axes_ticks(self):
Expand Down Expand Up @@ -265,6 +272,16 @@ def add_marker(self, marker):
self.ax_markers.append(marker)

def update(self, auto_contrast=None, **kwargs):
# Turn on centre_colormap if a diverging colormap is used.
if self.centre_colormap == "auto":
if "cmap" in kwargs:
cmap = kwargs["cmap"]
else:
cmap = plt.cm.get_cmap().name
if cmap in MPL_DIVERGING_COLORMAPS:
self.centre_colormap = True
else:
self.centre_colormap = False
ims = self.ax.images
redraw_colorbar = False
data = rgb_tools.rgbx2regular_array(
Expand Down Expand Up @@ -303,9 +320,13 @@ def format_coord(x, y):
self._text.set_text(self.axes_manager.indices)
if self.no_nans:
data = np.nan_to_num(data)
if self.centre_colormap:
vmin, vmax = centre_colormap_values(self.vmin, self.vmax)
else:
vmin, vmax = self.vmin, self.vmax
if ims:
ims[0].set_data(data)
ims[0].norm.vmax, ims[0].norm.vmin = self.vmax, self.vmin
ims[0].norm.vmax, ims[0].norm.vmin = vmax, vmin
if redraw_colorbar is True:
ims[0].autoscale()
self._colorbar.draw_all()
Expand All @@ -320,8 +341,8 @@ def format_coord(x, y):
self.figure.canvas.draw()
else:
new_args = {'interpolation': 'nearest',
'vmin': self.vmin,
'vmax': self.vmax,
'vmin': vmin,
'vmax': vmax,
'extent': self._extent,
'aspect': self._aspect,
'animated': True}
Expand Down
2 changes: 2 additions & 0 deletions hyperspy/drawing/mpl_hie.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def plot_signal(self,
vmin=None,
vmax=None,
no_nans=False,
centre_colormap="auto",
**kwargs
):
"""Plot image.
Expand Down Expand Up @@ -81,6 +82,7 @@ def plot_signal(self,
imf.no_nans = no_nans
imf.scalebar_color = scalebar_color
imf.auto_contrast = auto_contrast
imf.centre_colormap = centre_colormap
imf.plot(**kwargs)
self.signal_plot = imf

Expand Down
24 changes: 21 additions & 3 deletions hyperspy/drawing/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
import matplotlib.pyplot as plt
import matplotlib as mpl

from hyperspy.misc.image_tools import contrast_stretching
from hyperspy.misc.image_tools import (contrast_stretching,
MPL_DIVERGING_COLORMAPS,
centre_colormap_values)
from hyperspy.defaults_parser import preferences


Expand Down Expand Up @@ -356,7 +358,8 @@ def plot_images(images,
suptitle=None,
suptitle_fontsize=18,
colorbar='multi',
saturated_pixels=0.2,
centre_colormap="auto",
saturated_pixels=0,
scalebar=None,
scalebar_color='white',
axes_decor='all',
Expand Down Expand Up @@ -414,6 +417,10 @@ def plot_images(images,
(non-RGB) image
If 'single', all (non-RGB) images are plotted on the same scale,
and one colorbar is shown for all
centre_colormap : {"auto", True, False}
If True the centre of the color scheme is set to zero. This is
specially useful when using diverging color schemes. If "auto"
(default), diverging color schemes are automatically centred.
saturated_pixels: scalar
The percentage of pixels that are left out of the bounds. For example,
the low and high bounds of a value of 1 are the 0.5% and 99.5%
Expand Down Expand Up @@ -500,7 +507,14 @@ def plot_images(images,

# Get default colormap from pyplot:
if cmap is None:
cmap = plt.get_cmap()
cmap = plt.get_cmap().name
elif isinstance(cmap, mpl.colors.Colormap):
cmap = cmap.name
if centre_colormap == "auto":
if cmap in MPL_DIVERGING_COLORMAPS:
centre_colormap = True
else:
centre_colormap = False

# If input is >= 1D signal (e.g. for multi-dimensional plotting),
# copy it and put it in a list so labeling works out as (x,y) when plotting
Expand Down Expand Up @@ -652,6 +666,8 @@ def plot_images(images,
global_max = max([i.data.max() for i in non_rgb])
global_min = min([i.data.min() for i in non_rgb])
g_vmin, g_vmax = contrast_stretching(i.data, saturated_pixels)
if centre_colormap:
g_vmin, g_vmax = centre_colormap_values(g_vmin, g_vmax)

# Check if we need to add a scalebar for some of the images
if isinstance(scalebar, list) and all(isinstance(x, int)
Expand Down Expand Up @@ -682,6 +698,8 @@ def plot_images(images,
data = im.data
# Find min and max for contrast
l_vmin, l_vmax = contrast_stretching(data, saturated_pixels)
if centre_colormap:
l_vmin, l_vmax = centre_colormap_values(l_vmin, l_vmax)

# Remove NaNs (if requested)
if no_nans:
Expand Down
26 changes: 21 additions & 5 deletions hyperspy/gui/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
OurResetButton = tu.Action(name="Reset",
action="reset")

OurCloseButton = tu.Action(name="Close",
action="close_directly")

OurFindButton = tu.Action(name="Find next",
action="find",)

Expand Down Expand Up @@ -67,6 +70,10 @@ def close(self, info, is_ok):

return True

def close_directly(self, info):
if (info.ui.owner is not None) and self.close(info, False):
info.ui.owner.close()

def apply(self, info, *args, **kwargs):
"""Handles the **Apply** button being clicked.
Expand Down Expand Up @@ -771,23 +778,28 @@ def close(self):

class ComponentFit(SpanSelectorInSpectrum):
fit = t.Button()
only_current = t.List(t.Bool(True))

view = tu.View(
tu.Item('fit', show_label=False),
buttons=[OKButton, CancelButton],
tu.Item('only_current', show_label=False, style='custom',
editor=tu.CheckListEditor(values=[(True, 'Only current')])),
buttons=[OurCloseButton],
title='Fit single component',
handler=SpanSelectorInSpectrumHandler,
)

def __init__(self, model, component, signal_range=None,
estimate_parameters=True, fit_independent=False, **kwargs):
estimate_parameters=True, fit_independent=False,
only_current=True, **kwargs):
if model.spectrum.axes_manager.signal_dimension != 1:
raise SignalDimensionError(
model.spectrum.axes_manager.signal_dimension, 1)

self.signal = model.spectrum
self.axis = self.signal.axes_manager.signal_axes[0]
self.span_selector = None
self.only_current = [True] if only_current else [] # CheckListEditor
self.model = model
self.component = component
self.signal_range = signal_range
Expand Down Expand Up @@ -831,6 +843,7 @@ def _fit_fired(self):

# Setting reasonable initial value for parameters through
# the components estimate_parameters function (if it has one)
only_current = len(self.only_current) > 0 # CheckListEditor
if self.estimate_parameters:
if hasattr(self.component, 'estimate_parameters'):
if (self.signal_range != "interactive" and
Expand All @@ -839,15 +852,18 @@ def _fit_fired(self):
self.signal,
self.signal_range[0],
self.signal_range[1],
only_current=True)
only_current=only_current)
elif self.signal_range == "interactive":
self.component.estimate_parameters(
self.signal,
self.ss_left_value,
self.ss_right_value,
only_current=True)
only_current=only_current)

self.model.fit(**self.fit_kwargs)
if only_current:
self.model.fit(**self.fit_kwargs)
else:
self.model.multifit(**self.fit_kwargs)

# Restore the signal range
if self.signal_range is not None:
Expand Down
35 changes: 35 additions & 0 deletions hyperspy/misc/image_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,38 @@ def contrast_stretching(data, saturated_pixels):
vmin = np.percentile(data, saturated_pixels / 2.)
vmax = np.percentile(data, 100 - saturated_pixels / 2.)
return vmin, vmax

MPL_DIVERGING_COLORMAPS = [
"BrBG",
"bwr",
"coolwarm",
"PiYG",
"PRGn",
"PuOr",
"RdBu",
"RdGy",
"RdYIBu",
"RdYIGn",
"seismic",
"Spectral", ]
# Add reversed colormaps
MPL_DIVERGING_COLORMAPS += [cmap + "_r" for cmap in MPL_DIVERGING_COLORMAPS]


def centre_colormap_values(vmin, vmax):
"""Calculate vmin and vmax to set the colormap midpoint to zero.
Parameters
----------
vmin, vmax : scalar
The range of data to display.
Returns
-------
cvmin, cvmax : scalar
The values to obtain a centre colormap.
"""

absmax = max(abs(vmin), abs(vmax))
return -absmax, absmax
4 changes: 3 additions & 1 deletion hyperspy/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -1850,6 +1850,7 @@ def fit_component(
signal_range="interactive",
estimate_parameters=True,
fit_independent=False,
only_current=True,
**kwargs):
"""Fit just the given component in the given signal range.
Expand Down Expand Up @@ -1888,7 +1889,8 @@ def fit_component(
"""
component = self._get_component(component)
cf = ComponentFit(self, component, signal_range,
estimate_parameters, fit_independent, **kwargs)
estimate_parameters, fit_independent,
only_current, **kwargs)
if signal_range == "interactive":
cf.edit_traits()
else:
Expand Down
7 changes: 7 additions & 0 deletions hyperspy/signal.py
Original file line number Diff line number Diff line change
Expand Up @@ -4791,6 +4791,13 @@ def add_marker(self, marker, plot_on_signal=True, plot_marker=True):
marker.plot()

def create_model(self):
"""Create a model for the current signal
Returns
-------
A Model class
"""
from hyperspy.model import Model
return Model(self)

Expand Down
2 changes: 1 addition & 1 deletion hyperspy/tests/io/test_hdf5.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ class TestSavingMetadataContainers:
def setUp(self):
self.s = Signal([0.1])

@nt.timed(0.01)
@nt.timed(0.1)
def test_save_long_list(self):
s = self.s
s.metadata.set_item('long_list', range(10000))
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import nose.tools
import numpy as np

from .. import math_tools
from hyperspy.misc import math_tools


def test_isfloat_float():
Expand Down
2 changes: 1 addition & 1 deletion hyperspy/tests/model/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ def test_fit_bounded(self):
self.m[0].centre.bmin = 0.5
self.m[0].bounded = True
self.m.fit(fitter="mpfit", bounded=True)
nose.tools.assert_almost_equal(self.m[0].A.value, 9991.65422046, 5)
nose.tools.assert_almost_equal(self.m[0].A.value, 9991.65422046, 4)
nose.tools.assert_almost_equal(self.m[0].centre.value, 0.5)
nose.tools.assert_almost_equal(self.m[0].sigma.value, 2.08398236966)

Expand Down

0 comments on commit aa9b0ba

Please sign in to comment.