This notebook shows how to make a publication quality figure of a HyperSpy Signal2D object, where we use the matplotlib figure and subplot object to customize the plot.
HyperSpy 1.3 or later
Matplotlib 2.0 or later
import numpy as np
import hyperspy.api as hs
Firstly, we make a 2D signal by generating a numpy array
image_data = np.arange(10000).reshape(100, 100) + np.random.random(size=(100, 100))*5000
HyperSpy signals can be made by passing a numpy array to a HyperSpy signal class.
s = hs.signals.Signal2D(image_data)
In addition to the pyplot module, we also need to import the size bar, font manager and patheffects. As the three latter modules are not present in the main pyplot module.
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.anchored_artists import AnchoredSizeBar
import matplotlib.font_manager as fm
import matplotlib.patheffects as patheffects
The figsize argument is used to make sure the figure has the same length in both the x- and y-directions.
fig, ax = plt.subplots(figsize=(6, 6))
Image data is normally not plotted with ticks on the axis, so we disable these using set_axis_off
ax.set_axis_off()
Plotting the image data itself is done by directly accessing the numpy array in the signal: s.data
.
The calibrated size of the signal is contained in s.axes_manager.signal_extent, which is needed if we want the scalebar to have the correct size.
cax = ax.imshow(s.data, extent=s.axes_manager.signal_extent, cmap='viridis')
cax can be used to set color limits for the plotted image
cax.set_clim(200, 11000)
In matplotlib, what is normally referred to as a scalebar, is called an AnchoredSizeBar.
This AnchoredSizeBar takes a large amount of arguments, which can be seen in the docstring by running AnchoredSizeBar?
To set the size of the text in the scalebar, the fontproperties object is used.
fontprops = fm.FontProperties(size=30)
scalebar = AnchoredSizeBar(
transform=ax.transData, size=30, label='30 nm',
loc=4, frameon=False,
color='black', size_vertical=3,
label_top=False,
fontproperties=fontprops)
To increase the contrast of the scalebar text, use the patheffects feature. This adds a border around the text. The capstyle argument needs to be used to get a continuous border.
scalebar.txt_label._text.set_path_effects([patheffects.withStroke(linewidth=2, foreground='white', capstyle="round")])
ax.add_artist(scalebar)
The next line is needed due to a bug in the current version of matplotlib (2.0.2), which leads to the scalebar being not solid. This has been fixed in the current development version.
scalebar.size_bar.get_children()[0].fill = True
Using ax.annotate, we add an arrow point to some xy coordinate. The xytext specifies either the tail or the text of the arrow. If no text is wanted, use s=''.
annotation = ax.annotate(s="An arrow", xy=(20, 70), xytext=(40, 50),
arrowprops={'arrowstyle':'->'},
path_effects=[patheffects.withStroke(linewidth=2, foreground='white', capstyle="round")])
To increase the contrast of arrow, add a border in a different color.
annotation.arrow_patch.set_path_effects([patheffects.withStroke(linewidth=2, foreground='white', capstyle="round")])
ax.text(0.05, 0.95, "Some random data", size=20, transform=ax.transAxes,
verticalalignment='top', horizontalalignment='left', color='white',
path_effects=[patheffects.withStroke(linewidth=3, foreground='black', capstyle="round")])
For figures of image data, it is possible to make the figure borderless by using the subplot_adjust.
Note, this only works well if the axis ticks are deactivated.
fig.subplots_adjust(left=0., bottom=0., right=1., top=1.)
fig.savefig("image_data_figure.png", dpi=300)