The object returned by :py:func:`~.io.load`, a :py:class:`~.signal.BaseSignal` instance, has a :py:meth:`~.signal.BaseSignal.plot` method that is powerful and flexible to visualize n-dimensional data. In this chapter, the visualisation of multidimensional data is exemplified with two experimental datasets: an EELS spectrum image and an EDX dataset consisting of a secondary electron emission image stack and a 3D hyperspectral image, both simultaneously acquired by recording two signals in parallel in a FIB/SEM.
>>> s = hs.load('YourDataFilenameHere')
>>> s.plot()
if the object is single spectrum or an image one window will appear when calling the plot method.
If the object is a 1D or 2D spectrum-image (i.e. with 2 or 3 dimensions when including energy) two figures will appear, one containing a plot of the spectrum at the current coordinates and the other an image of the data summed over its spectral dimension if 2D or an image with the spectral dimension in the x-axis if 1D:
.. versionadded:: 1.4 Customizable keyboard shortcuts to navigate multi-dimensional datasets.
To change the current coordinates, click on the pointer (which will be a line or a square depending on the dimensions of the data) and drag it around. It is also possible to move the pointer by using the numpad arrows when numlock is on and the spectrum or navigator figure is selected. When using the numpad arrows the PageUp and PageDown keys change the size of the step.
The current coordinates can be either set by navigating the
:py:meth:`~.signal.BaseSignal.plot`, or specified by pixel indices
in s.axes_manager.indices
or as calibrated coordinates in
s.axes_manager.coordinates
.
An extra cursor can be added by pressing the e
key. Pressing e
once
more will disable the extra cursor:
In matplotlib, left and right arrow keys are by default set to navigate the
"zoom" history. To avoid the problem of changing zoom while navigating,
Ctrl
+ arrows can be used instead. Navigating without using the modifier keys
will be deprecated in version 2.0.
To navigate navigation dimensions larger than 2, modifier keys can be used.
The defaults are Shift
+ left
/right
and Shift
+ up
/down
,
(Alt
+ left
/right
and Alt
+ up
/down
)
for navigating dimensions 2 and 3 (4 and 5) respectively. Modifier keys do not work with the numpad.
Hotkeys and modifier keys for navigating the plot can be set in the :ref:`HyperSpy plot preferences <configuring-hyperspy-label>`. Note that some combinations will not work for all platforms, as some systems reserve them for other purposes.
Sometimes the default size of the rectangular cursors used to navigate images
can be too small to be dragged or even seen. It
is possible to change the size of the cursors by pressing the +
and -
keys when the navigator window is selected.
The following keyboard shortcuts are available when the 1D signal figure is in focus:
key | function |
---|---|
e | Switch second pointer on/off |
Ctrl + Arrows | Change coordinates for dimensions 0 and 1 (typically x and y) |
Shift + Arrows | Change coordinates for dimensions 2 and 3 |
Alt + Arrows | Change coordinates for dimensions 4 and 5 |
PageUp | Increase step size |
PageDown | Decrease step size |
+ |
Increase pointer size when the navigator is an image |
- |
Decrease pointer size when the navigator is an image |
l |
switch the scale of the y-axis between logarithmic and linear |
To close all the figures run the following command:
>>> import matplotlib.pyplot as plt
>>> plt.close('all')
Note
plt.close('all')
is a matplotlib command.
Matplotlib is the library that HyperSpy uses to produce the plots. You can
learn how to pan/zoom and more in the matplotlib documentation
Note
Plotting float16
images is currently not supported by matplotlib; however, it is
possible to convert the type of the data by using the
:py:meth:`~.signal.BaseSignal.change_dtype` method, e.g. s.change_dtype('float32')
.
Equivalently, if the object is a 1D or 2D image stack two figures will appear, one containing a plot of the image at the current coordinates and the other a spectrum or an image obtained by summing over the image dimensions:
.. versionadded:: 1.4 ``l`` keyboard shortcut
The following keyboard shortcuts are availalbe when the 2D signal figure is in focus:
key | function |
---|---|
Ctrl + Arrows | Change coordinates for dimensions 0 and 1 (typically x and y) |
Shift + Arrows | Change coordinates for dimensions 2 and 3 |
Alt + Arrows | Change coordinates for dimensions 4 and 5 |
PageUp | Increase step size |
PageDown | Decrease step size |
+ |
Increase pointer size when the navigator is an image |
- |
Decrease pointer size when the navigator is an image |
h |
Launch the contrast adjustment tool |
l |
switch the norm of the intensity between logarithmic and linear |
The image plot can be customised by passing additional arguments when plotting. Colorbar, scalebar and contrast controls are HyperSpy-specific, however :py:meth:`matplotlib.axes.Axes.imshow` arguments are supported as well:
>>> import scipy
>>> img = hs.signals.Signal2D(scipy.misc.ascent())
>>> img.plot(colorbar=True, scalebar=False,
... axes_ticks=True, cmap='RdYlBu_r')
.. versionadded:: 1.4 ``norm`` keyword argument
The norm
keyword argument can be used to select between linear, logarithmic
or custom (using a matplotlib norm) intensity scale. The default, "auto",
automatically selects a logarithmic scale when plotting a power spectrum.
.. versionadded:: 1.6 ``autoscale`` keyword argument
The autoscale
keyword argument can be used to specify which axis limits are
reset when the data or navigation indices change. It can take any combinations
of the following characters:
'x'
: to reset the horizontal axes'y'
: to reset the vertical axes'v'
: to reset the contrast of the image according tovmin
andvmax
By default (autoscale='v'
), only the contrast of the image will be reset
automatically. For example, to reset the extent of the image (x and y) to their
maxima but not the contrast, use autoscale='xy'
; To reset all limits,
including the contrast of the image, use autoscale='xyv'
:
>>> import numpy as np
>>> img = hs.signals.Signal2D(np.arange(10*10*10).reshape(10, 10, 10))
>>> img.plot(autoscale='xyv')
When plotting using divergent colormaps, if centre_colormap
is True
(default) the contrast is automatically adjusted so that zero corresponds to
the center of the colormap (usually white). This can be useful e.g. when
displaying images that contain pixels with both positive and negative values.
The following example shows the effect of centring the color map:
>>> x = np.linspace(-2 * np.pi, 2 * np.pi, 128)
>>> xx, yy = np.meshgrid(x, x)
>>> data1 = np.sin(xx * yy)
>>> data2 = data1.copy()
>>> data2[data2 < 0] /= 4
>>> im = hs.signals.Signal2D([data1, data2])
>>> hs.plot.plot_images(im, cmap="RdBu", tight_layout=True)
The same example with the feature disabled:
>>> x = np.linspace(-2 * np.pi, 2 * np.pi, 128)
>>> xx, yy = np.meshgrid(x, x)
>>> data1 = np.sin(xx * yy)
>>> data2 = data1.copy()
>>> data2[data2 < 0] /= 4
>>> im = hs.signals.Signal2D([data1, data2])
>>> hs.plot.plot_images(im, centre_colormap=False,
... cmap="RdBu", tight_layout=True)
.. versionadded:: 1.1.2 Passing keyword arguments to the navigator plot.
The navigator can be customised by using the navigator_kwds
argument. For
example, in case of a image navigator, all image plot arguments mentioned in
the section :ref:`plot.customize_images` can be passed as a dictionary to the
navigator_kwds
argument:
>>> import numpy as np
>>> import scipy
>>> im = hs.signals.Signal2D(scipy.misc.ascent())
>>> ims = hs.signals.BaseSignal(np.random.rand(15,13)).T * im
>>> ims.metadata.General.title = 'My Images'
>>> ims.plot(colorbar=False,
... scalebar=False,
... axes_ticks=False,
... cmap='viridis',
... navigator_kwds=dict(colorbar=True,
... scalebar_color='red',
... cmap='Blues',
... axes_ticks=False)
... )
Data files used in the following examples can be downloaded using
>>> #Download the data (130MB)
>>> from urllib.request import urlretrieve, urlopen
>>> from zipfile import ZipFile
>>> files = urlretrieve("https://www.dropbox.com/s/s7cx92mfh2zvt3x/"
... "HyperSpy_demos_EDX_SEM_files.zip?raw=1",
... "./HyperSpy_demos_EDX_SEM_files.zip")
>>> with ZipFile("HyperSpy_demos_EDX_SEM_files.zip") as z:
>>> z.extractall()
Note
See also the SEM EDS tutorials .
Note
The sample and the data used in this chapter are described in P. Burdet, et al., Acta Materialia, 61, p. 3090-3098 (2013) (see abstract).
Stack of 2D images can be imported as an 3D image and plotted with a slider instead of the 2D navigator as in the previous example.
>>> img = hs.load('Ni_superalloy_0*.tif', stack=True)
>>> img.plot(navigator='slider')
A stack of 2D spectrum images can be imported as a 3D spectrum image and plotted with sliders.
>>> s = hs.load('Ni_superalloy_0*.rpl', stack=True).as_signal1D(0)
>>> s.plot()
If the 3D images has the same spatial dimension as the 3D spectrum image, it can be used as an external signal for the navigator.
>>> im = hs.load('Ni_superalloy_0*.tif', stack=True)
>>> s = hs.load('Ni_superalloy_0*.rpl', stack=True).as_signal1D(0)
>>> dim = s.axes_manager.navigation_shape
>>> #Rebin the image
>>> im = im.rebin([dim[2], dim[0], dim[1]])
>>> s.plot(navigator=im)
The 3D spectrum image can be transformed in a stack of spectral images for an alternative display.
>>> imgSpec = hs.load('Ni_superalloy_0*.rpl', stack=True)
>>> imgSpec.plot(navigator='spectrum')
An external signal (e.g. a spectrum) can be used as a navigator, for example the "maximum spectrum" for which each channel is the maximum of all pixels.
>>> imgSpec = hs.load('Ni_superalloy_0*.rpl', stack=True)
>>> specMax = imgSpec.max(-1).max(-1).max(-1).as_signal1D(0)
>>> imgSpec.plot(navigator=specMax)
Lastly, if no navigator is needed, "navigator=None" can be used.
Data files used in the following examples can be downloaded using
>>> from urllib.request import urlretrieve
>>> url = 'http://cook.msm.cam.ac.uk/~hyperspy/EDS_tutorial/'
>>> urlretrieve(url + 'Ni_La_intensity.hdf5', 'Ni_La_intensity.hdf5')
Note
See also the EDS tutorials .
Although HyperSpy does not currently support plotting when signal_dimension is greater than 2, Mayavi can be used for this purpose.
In the following example we also use scikit-image for noise reduction. More details about :py:meth:`~._signals.eds.EDSSpectrum.get_lines_intensity` method can be found in :ref:`EDS lines intensity<get_lines_intensity>`.
>>> from mayavi import mlab
>>> ni = hs.load('Ni_La_intensity.hdf5')
>>> mlab.figure()
>>> mlab.contour3d(ni.data, contours=[85])
>>> mlab.outline(color=(0, 0, 0))
Note
See also the SEM EDS tutorials .
Note
The sample and the data used in this chapter are described in P. Burdet, et al., Ultramicroscopy, 148, p. 158-167 (2015).
HyperSpy provides three functions to plot multiple signals (spectra, images or
other signals): :py:func:`~.drawing.utils.plot_images`,
:py:func:`~.drawing.utils.plot_spectra`, and
:py:func:`~.drawing.utils.plot_signals` in the utils.plot
package.
:py:func:`~.drawing.utils.plot_images` is used to plot several images in the
same figure. It supports many configurations and has many options available
to customize the resulting output. The function returns a list of
:py:class:`matplotlib.axes.Axes`,
which can be used to further customize the figure. Some examples are given
below. Plots generated from another installation may look slightly different
due to matplotlib
GUI backends and default font sizes. To change the
font size globally, use the command matplotlib.rcParams.update({'font
.size': 8})
.
.. versionadded:: 1.5 Add support for plotting :py:class:`~.signal.BaseSignal` with navigation dimension 2 and signal dimension 0.
A common usage for :py:func:`~.drawing.utils.plot_images` is to view the different slices of a multidimensional image (a hyperimage):
>>> import scipy
>>> image = hs.signals.Signal2D([scipy.misc.ascent()]*6)
>>> angles = hs.signals.BaseSignal(range(10,70,10))
>>> image.map(scipy.ndimage.rotate, angle=angles.T, reshape=False)
>>> hs.plot.plot_images(image, tight_layout=True)
This example is explained in :ref:`Signal iterator<signal.iterator>`.
By default, :py:func:`~.drawing.utils.plot_images` will attempt to auto-label the images based on the Signal titles. The labels (and title) can be customized with the suptitle and label arguments. In this example, the axes labels and the ticks are also disabled with axes_decor:
>>> import scipy
>>> image = hs.signals.Signal2D([scipy.misc.ascent()]*6)
>>> angles = hs.signals.BaseSignal(range(10,70,10))
>>> image.map(scipy.ndimage.rotate, angle=angles.T, reshape=False)
>>> hs.plot.plot_images(
... image, suptitle='Turning Ascent', axes_decor='off',
... label=['Rotation {}$^\degree$'.format(angles.data[i]) for
... i in range(angles.data.shape[0])], colorbar=None)
:py:func:`~.drawing.utils.plot_images` can also be used to easily plot a list of Images, comparing different Signals, including RGB images. This example also demonstrates how to wrap labels using labelwrap (for preventing overlap) and using a single colorbar for all the Images, as opposed to multiple individual ones:
>>> import scipy
>>> import numpy as np
>>>
>>> # load red channel of raccoon as an image
>>> image0 = hs.signals.Signal2D(scipy.misc.face()[:,:,0])
>>> image0.metadata.General.title = 'Rocky Raccoon - R'
>>>
>>> # load ascent into a length 6 hyper-image
>>> image1 = hs.signals.Signal2D([scipy.misc.ascent()]*6)
>>> angles = hs.signals.BaseSignal(np.arange(10,70,10)).T
>>> image1.map(scipy.ndimage.rotate, angle=angles,
... show_progressbar=False, reshape=False)
>>> image1.data = np.clip(image1.data, 0, 255) # clip data to int range
>>>
>>> # load green channel of raccoon as an image
>>> image2 = hs.signals.Signal2D(scipy.misc.face()[:,:,1])
>>> image2.metadata.General.title = 'Rocky Raccoon - G'
>>>
>>> # load rgb image of the raccoon
>>> rgb = hs.signals.Signal1D(scipy.misc.face())
>>> rgb.change_dtype("rgb8")
>>> rgb.metadata.General.title = 'Raccoon - RGB'
>>>
>>> images = [image0, image1, image2, rgb]
>>> for im in images:
... ax = im.axes_manager.signal_axes
... ax[0].name, ax[1].name = 'x', 'y'
... ax[0].units, ax[1].units = 'mm', 'mm'
>>> hs.plot.plot_images(images, tight_layout=True,
... colorbar='single', labelwrap=20)
Data files used in the following example can be downloaded using (These data are described in :ref:`[Rossouw2015] <Rossouw2015>`.
>>> #Download the data (1MB)
>>> from urllib.request import urlretrieve, urlopen
>>> from zipfile import ZipFile
>>> files = urlretrieve("https://www.dropbox.com/s/ecdlgwxjq04m5mx/"
... "HyperSpy_demos_EDS_TEM_files.zip?raw=1",
... "./HyperSpy_demos_EDX_TEM_files.zip")
>>> with ZipFile("HyperSpy_demos_EDX_TEM_files.zip") as z:
>>> z.extractall()
Another example for this function is plotting EDS line intensities see :ref:`EDS chapter <get_lines_intensity>`. One can use the following commands to get a representative figure of the X-ray line intensities of an EDS spectrum image. This example also demonstrates changing the colormap (with cmap), adding scalebars to the plots (with scalebar), and changing the padding between the images. The padding is specified as a dictionary, which is passed to :py:meth:`matplotlib.figure.Figure.subplots_adjust`.
>>> si_EDS = hs.load("core_shell.hdf5")
>>> im = si_EDS.get_lines_intensity()
>>> hs.plot.plot_images(im,
... tight_layout=True, cmap='RdYlBu_r', axes_decor='off',
... colorbar='single', vmin='1th', vmax='99th', scalebar='all',
... scalebar_color='black', suptitle_fontsize=16,
... padding={'top':0.8, 'bottom':0.10, 'left':0.05,
... 'right':0.85, 'wspace':0.20, 'hspace':0.10})
Using :py:func:`~.drawing.utils.plot_images` to plot the output of :py:meth:`~._signals.eds.EDSSpectrum.get_lines_intensity`.
Note
This padding can also be changed interactively by clicking on the button in the GUI (button may be different when using different graphical backends).
Finally, the cmap
option of :py:func:`~.drawing.utils.plot_images`
supports iterable types, allowing the user to specify different colormaps
for the different images that are plotted by providing a list or other
generator:
>>> si_EDS = hs.load("core_shell.hdf5")
>>> im = si_EDS.get_lines_intensity()
>>> hs.plot.plot_images(im,
>>> tight_layout=True, cmap=['viridis', 'plasma'], axes_decor='off',
>>> colorbar='multi', vmin='1th', vmax='99th', scalebar=[0],
>>> scalebar_color='white', suptitle_fontsize=16)
Using :py:func:`~.drawing.utils.plot_images` to plot the output of :py:meth:`~._signals.eds.EDSSpectrum.get_lines_intensity` using a unique colormap for each image.
The cmap
argument can also be given as 'mpl_colors'
, and as a result,
the images will be plotted with colormaps generated from the default
matplotlib
colors, which is very helpful when plotting multiple spectral
signals and their relative intensities (such as the results of a
:py:func:`~.learn.mva.decomposition` analysis). This example uses
:py:func:`~.drawing.utils.plot_spectra`, which is explained in the
next section.
>>> si_EDS = hs.load("core_shell.hdf5")
>>> si_EDS.change_dtype('float')
>>> si_EDS.decomposition(True, algorithm='NMF', output_dimension=3)
>>> factors = si_EDS.get_decomposition_factors()
>>>
>>> # the first factor is a very strong carbon background component, so we
>>> # normalize factor intensities for easier qualitative comparison
>>> for f in factors:
>>> f.data /= f.data.max()
>>>
>>> loadings = si_EDS.get_decomposition_loadings()
>>>
>>> hs.plot.plot_spectra(factors.isig[:14.0], style='cascade',
>>> padding=-1)
>>>
>>> # add some lines to nicely label the peak positions
>>> plt.axvline(6.403, c='C2', ls=':', lw=0.5)
>>> plt.text(x=6.503, y=0.85, s='Fe-K$_\\alpha$', color='C2')
>>> plt.axvline(9.441, c='C1', ls=':', lw=0.5)
>>> plt.text(x=9.541, y=0.85, s='Pt-L$_\\alpha$', color='C1')
>>> plt.axvline(2.046, c='C1', ls=':', lw=0.5)
>>> plt.text(x=2.146, y=0.85, s='Pt-M', color='C1')
>>> plt.axvline(8.040, ymax=0.8, c='k', ls=':', lw=0.5)
>>> plt.text(x=8.14, y=0.35, s='Cu-K$_\\alpha$', color='k')
>>>
>>> hs.plot.plot_images(loadings, cmap='mpl_colors',
>>> axes_decor='off', per_row=1,
>>> label=['Background', 'Pt core', 'Fe shell'],
>>> scalebar=[0], scalebar_color='white',
>>> padding={'top': 0.95, 'bottom': 0.05,
>>> 'left': 0.05, 'right':0.78})
Using :py:func:`~.drawing.utils.plot_images` with cmap='mpl_colors'
together with :py:func:`~.drawing.utils.plot_spectra` to visualize the
output of a non-negative matrix factorization of the EDS data.
Note
Because it does not make sense, it is not allowed to use a list or
other iterable type for the cmap
argument together with 'single'
for the colorbar
argument. Such an input will cause a warning and
instead set the colorbar
argument to None
.
It is also possible to plot multiple images overlayed on the same figure by
passing the argument overlay=True
to the
:py:func:`~.drawing.utils.plot_images` function. This should only be done when
images have the same scale (eg. for elemental maps from the same dataset).
Using the same data as above, the Fe and Pt signals can be plotted using
different colours. Any color can be input via matplotlib color characters or
hex values.
>>> si_EDS = hs.load("core_shell.hdf5")
>>> im = si_EDS.get_lines_intensity()
>>> hs.plot.plot_images(im,scalebar='all', overlay=True, suptitle=False,
>>> axes_decor='off')
:py:func:`~.drawing.utils.plot_spectra` is used to plot several spectra in the same figure. It supports different styles, the default being "overlap".
.. versionadded:: 1.5 Add support for plotting :py:class:`~.signal.BaseSignal` with navigation dimension 1 and signal dimension 0.
In the following example we create a list of 9 single spectra (gaussian functions with different sigma values) and plot them in the same figure using :py:func:`~.drawing.utils.plot_spectra`. Note that, in this case, the legend labels are taken from the individual spectrum titles. By clicking on the legended line, a spectrum can be toggled on and off.
>>> s = hs.signals.Signal1D(np.zeros((200)))
>>> s.axes_manager[0].offset = -10
>>> s.axes_manager[0].scale = 0.1
>>> m = s.create_model()
>>> g = hs.model.components1D.Gaussian()
>>> m.append(g)
>>> gaussians = []
>>> labels = []
>>> for sigma in range(1, 10):
... g.sigma.value = sigma
... gs = m.as_signal()
... gs.metadata.General.title = "sigma=%i" % sigma
... gaussians.append(gs)
...
>>> hs.plot.plot_spectra(gaussians,legend='auto')
<matplotlib.axes.AxesSubplot object at 0x4c28c90>
Another style, "cascade", can be useful when "overlap" results in a plot that is too cluttered e.g. to visualize changes in EELS fine structure over a line scan. The following example shows how to plot a cascade style figure from a spectrum, and save it in a file:
>>> import scipy.misc
>>> s = hs.signals.Signal1D(scipy.misc.ascent()[100:160:10])
>>> cascade_plot = hs.plot.plot_spectra(s, style='cascade')
>>> cascade_plot.figure.savefig("cascade_plot.png")
The "cascade" style has a padding option. The default value, 1, keeps the individual plots from overlapping. However in most cases a lower padding value can be used, to get tighter plots.
Using the color argument one can assign a color to all the spectra, or specific colors for each spectrum. In the same way, one can also assign the line style 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']
>>> linestyle_list = ['-', '--', '-.', ':', '-']
>>> hs.plot.plot_spectra(s, style='cascade', color=color_list,
>>> linestyle=linestyle_list, legend='auto')
A simple extension of this functionality is to customize the colormap that is used to generate the list of colors. Using a list comprehension, one can generate a list of colors that follows a certain colormap:
>>> import scipy.misc
>>> fig, axarr = plt.subplots(1,2)
>>> s1 = hs.signals.Signal1D(scipy.misc.ascent()[100:160:10])
>>> s2 = hs.signals.Signal1D(scipy.misc.ascent()[200:260:10])
>>> hs.plot.plot_spectra(s1,
... style='cascade',
... color=[plt.cm.RdBu(i/float(len(s1)-1))
... for i in range(len(s1))],
... ax=axarr[0],
... fig=fig)
>>> hs.plot.plot_spectra(s2,
... style='cascade',
... color=[plt.cm.summer(i/float(len(s1)-1))
... for i in range(len(s1))],
... ax=axarr[1],
... fig=fig)
>>> axarr[0].set_xlabel('RdBu (colormap)')
>>> axarr[1].set_xlabel('summer (colormap)')
>>> fig.canvas.draw()
There are also two other styles, "heatmap" and "mosaic":
>>> import scipy.misc
>>> s = hs.signals.Signal1D(scipy.misc.ascent()[100:160:10])
>>> hs.plot.plot_spectra(s, style='heatmap')
>>> import scipy.misc
>>> s = hs.signals.Signal1D(scipy.misc.ascent()[100:120:10])
>>> hs.plot.plot_spectra(s, style='mosaic')
For the "heatmap" style, different matplotlib color schemes can be used:
>>> import matplotlib.cm
>>> import scipy.misc
>>> s = hs.signals.Signal1D(scipy.misc.ascent()[100:120:10])
>>> ax = hs.plot.plot_spectra(s, style="heatmap")
>>> ax.images[0].set_cmap(matplotlib.cm.plasma)
Figure generated by :py:func:`~.drawing.utils.plot_spectra` using the heatmap style showing how to customise the color map.
Any parameter that can be passed to matplotlib.pyplot.figure can also be used with plot_spectra() to allow further customization (when using the "overlap", "cascade", or "mosaic" styles). In the following example, dpi, facecolor, frameon, and num are all parameters that are passed directly to matplotlib.pyplot.figure as keyword arguments:
>>> import scipy.misc
>>> s = hs.signals.Signal1D(scipy.misc.ascent()[100:160:10])
>>> legendtext = ['Plot 0', 'Plot 1', 'Plot 2', 'Plot 3',
... 'Plot 4', 'Plot 5']
>>> cascade_plot = hs.plot.plot_spectra(
... s, style='cascade', legend=legendtext, dpi=60,
... facecolor='lightblue', frameon=True, num=5)
>>> cascade_plot.set_xlabel("X-axis")
>>> cascade_plot.set_ylabel("Y-axis")
>>> cascade_plot.set_title("Cascade plot")
>>> plt.draw()
The function returns a matplotlib ax object, which can be used to customize the figure:
>>> import scipy.misc
>>> s = hs.signals.Signal1D(scipy.misc.ascent()[100:160:10])
>>> cascade_plot = hs.plot.plot_spectra(s)
>>> cascade_plot.set_xlabel("An axis")
>>> cascade_plot.set_ylabel("Another axis")
>>> cascade_plot.set_title("A title!")
>>> plt.draw()
A matplotlib ax and fig object can also be specified, which can be used to put several subplots in the same figure. This will only work for "cascade" and "overlap" styles:
>>> import scipy.misc
>>> fig, axarr = plt.subplots(1,2)
>>> s1 = hs.signals.Signal1D(scipy.misc.ascent()[100:160:10])
>>> s2 = hs.signals.Signal1D(scipy.misc.ascent()[200:260:10])
>>> hs.plot.plot_spectra(s1, style='cascade',
... color='blue', ax=axarr[0], fig=fig)
>>> hs.plot.plot_spectra(s2, style='cascade',
... color='red', ax=axarr[1], fig=fig)
>>> fig.canvas.draw()
Spectra or line profile can be plotted interactively on the same figure using the :py:func:`~.drawing.utils.plot_spectra` function. For example, profiles obtained from different Signal2D using the :py:class:`~.roi.Line2DROI` ROI can be plotted interactively:
>>> im0 = hs.datasets.example_signals.reference_hologram()
>>> im1 = hs.datasets.example_signals.object_hologram()
>>> im0.plot()
>>> im1.plot()
>>> # Create the ROI
>>> line_profile = hs.roi.Line2DROI(400, 250, 220, 600)
>>> # Obtain the signals to plot by "slicing" the signals with the ROI
>>> line0 = line_profile.interactive(im0)
>>> line1 = line_profile.interactive(im1)
>>> # Plotting the profile on the same figure
>>> hs.plot.plot_spectra([line0, line1])
:py:func:`~.drawing.utils.plot_signals` is used to plot several signals at the same time. By default the navigation position of the signals will be synced, and the signals must have the same dimensions. To plot two spectra at the same time:
>>> import scipy.misc
>>> s1 = hs.signals.Signal1D(scipy.misc.face()).as_signal1D(0).inav[:,:3]
>>> s2 = s1.deepcopy()*-1
>>> hs.plot.plot_signals([s1, s2])
The :py:func:`~.drawing.utils.plot_signals` plots several signals with optional synchronized navigation.
The navigator can be specified by using the navigator argument, where the different options are "auto", None, "spectrum", "slider" or Signal. For more details about the different navigators, see :ref:`the navigator options<plot.customize_navigator>`. To specify the navigator:
>>> import scipy.misc
>>> s1 = hs.signals.Signal1D(scipy.misc.face()).as_signal1D(0).inav[:,:3]
>>> s2 = s1.deepcopy()*-1
>>> hs.plot.plot_signals([s1, s2], navigator="slider")
Navigators can also be set differently for different plots using the navigator_list argument. Where the navigator_list be the same length as the number of signals plotted, and only contain valid navigator options. For example:
>>> import scipy.misc
>>> s1 = hs.signals.Signal1D(scipy.misc.face()).as_signal1D(0).inav[:,:3]
>>> s2 = s1.deepcopy()*-1
>>> s3 = hs.signals.Signal1D(np.linspace(0,9,9).reshape([3,3]))
>>> hs.plot.plot_signals([s1, s2], navigator_list=["slider", s3])
Several signals can also be plotted without syncing the navigation by using sync=False. The navigator_list can still be used to specify a navigator for each plot:
>>> import scipy.misc
>>> s1 = hs.signals.Signal1D(scipy.misc.face()).as_signal1D(0)[:,:3]
>>> s2 = s1.deepcopy()*-1
>>> hs.plot.plot_signals([s1, s2], sync=False,
... navigator_list=["slider", "slider"])
HyperSpy provides an easy access to the main marker of matplotlib. The markers can be used in a static way
>>> import scipy.misc
>>> im = hs.signals.Signal2D(scipy.misc.ascent())
>>> m = hs.plot.markers.rectangle(x1=150, y1=100,
... x2=400, y2=400, color='red')
>>> im.add_marker(m)
By providing an array of positions, the marker can also change position when navigating the signal. In the following example, the local maxima are displayed for each R, G and B channel of a colour image.
>>> from skimage.feature import peak_local_max
>>> import scipy.misc
>>> ims = hs.signals.BaseSignal(scipy.misc.face()).as_signal2D([1,2])
>>> index = np.array([peak_local_max(im.data, min_distance=100,
... num_peaks=4)
... for im in ims])
>>> for i in range(4):
... m = hs.plot.markers.point(x=index[:, i, 1],
... y=index[:, i, 0], color='red')
... ims.add_marker(m)
The markers can be added to the navigator as well. In the following example, each slice of a 2D spectrum is tagged with a text marker on the signal plot. Each slice is indicated with the same text on the navigator.
>>> s = hs.signals.Signal1D(np.arange(100).reshape([10,10]))
>>> s.plot(navigator='spectrum')
>>> for i in range(s.axes_manager.shape[0]):
... m = hs.plot.markers.text(y=s.sum(-1).data[i]+5,
... x=i, text='abcdefghij'[i])
... s.add_marker(m, plot_on_signal=False)
>>> x = s.axes_manager.shape[-1]/2 #middle of signal plot
>>> m = hs.plot.markers.text(x=x, y=s.isig[x].data+2,
... text=[i for i in 'abcdefghij'])
>>> s.add_marker(m)
.. versionadded:: 1.2 Permanent markers.
These markers can also be permanently added to a signal, which is saved in
metadata.Markers
:
>>> s = hs.signals.Signal2D(np.arange(100).reshape(10, 10))
>>> marker = hs.markers.point(5, 9)
>>> s.add_marker(marker, permanent=True)
>>> s.metadata.Markers
└── point = <marker.Point, point (x=5,y=9,color=black,size=20)>
>>> s.plot()
Markers can be removed by deleting them from the metadata
>>> s = hs.signals.Signal2D(np.arange(100).reshape(10, 10))
>>> marker = hs.markers.point(5, 9)
>>> s.add_marker(marker, permanent=True)
>>> s.metadata.Markers
└── point = <marker.Point, point (x=5,y=9,color=black,size=20)>
>>> del s.metadata.Markers.point
>>> s.metadata.Markers # Returns nothing
To suppress plotting of permanent markers, use plot_markers=False when calling s.plot:
>>> s = hs.signals.Signal2D(np.arange(100).reshape(10, 10))
>>> marker = hs.markers.point(5, 9)
>>> s.add_marker(marker, permanent=True, plot_marker=False)
>>> s.plot(plot_markers=False)
If the signal has a navigation dimension, the markers can be made to change as a function of the navigation index. For a signal with 1 navigation axis:
>>> s = hs.signals.Signal2D(np.arange(300).reshape(3, 10, 10))
>>> marker = hs.markers.point((5, 1, 2), (9, 8, 1), color='red')
>>> s.add_marker(marker, permanent=True)
Or for a signal with 2 navigation axes:
>>> s = hs.signals.Signal2D(np.arange(400).reshape(2, 2, 10, 10))
>>> marker = hs.markers.point(((5, 1), (1, 2)), ((2, 6), (9, 8)))
>>> s.add_marker(marker, permanent=True)
This can be extended to 4 (or more) navigation dimensions:
>>> s = hs.signals.Signal2D(np.arange(1600).reshape(2, 2, 2, 2, 10, 10))
>>> x = np.arange(16).reshape(2, 2, 2, 2)
>>> y = np.arange(16).reshape(2, 2, 2, 2)
>>> marker = hs.markers.point(x=x, y=y, color='red')
>>> s.add_marker(marker, permanent=True)
.. versionadded:: 1.2 ``markers`` keyword arguments can take an iterable in addition to single marker.
If you want to add a large amount of markers at the same time we advise to add them as an iterable (list, tuple, ...), which will be much faster:
>>> from numpy.random import random
>>> s = hs.signals.Signal2D(np.arange(300).reshape(3, 10, 10))
>>> markers = (hs.markers.point(tuple(random()*10 for i in range(3)),
... tuple(random()*10 for i in range(3)),
... size=30, color=np.random.rand(3,1))
... for i in range(500))
>>> s.add_marker(markers, permanent=True)
This can also be done using different types of markers
>>> from numpy.random import random
>>> s = hs.signals.Signal2D(np.arange(300).reshape(3, 10, 10))
>>> markers = []
>>> for i in range(200):
... markers.append(hs.markers.horizontal_line(
... tuple(random()*10 for i in range(3)),
... color=np.random.rand(3,1)))
... markers.append(hs.markers.vertical_line(
... tuple(random()*10 for i in range(3)),
... color=np.random.rand(3,1)))
... markers.append(hs.markers.point(
... tuple(random()*10 for i in range(3)),
... tuple(random()*10 for i in range(3)),
... color=np.random.rand(3,1)))
... markers.append(hs.markers.text(
... x=tuple(random()*10 for i in range(3)),
... y=tuple(random()*10 for i in range(3)),
... text=tuple("sometext" for i in range(3))))
>>> s.add_marker(markers, permanent=True)
Permanent markers are stored in the HDF5 file if the signal is saved:
>>> s = hs.signals.Signal2D(np.arange(100).reshape(10, 10))
>>> marker = hs.markers.point(2, 1, color='red')
>>> s.add_marker(marker, plot_marker=False, permanent=True)
>>> s.metadata.Markers
└── point = <marker.Point, point (x=2,y=1,color=red,size=20)>
>>> s.save("storing_marker.hdf5")
>>> s1 = hs.load("storing_marker.hdf5")
>>> s1.metadata.Markers
└── point = <hyperspy.drawing._markers.point.Point object at 0x7efcfadb06d8>
The markers currently supported in HyperSpy are:
The optional parameters (**kwargs
, keyword arguments) can be used for extra parameters used in matplotlib.
(The color
property in rectangle marker is an alias of edgecolor
for backward compatibility)