This tutorial shows the various functionalities in HyperSpy which is used to analyse off-axis electron holograms using dataset from
Migunov, V., London, A., Farle, M. & Dunin-Borkowski, R. E. Model-independent measurement of the charge density distribution along an Fe atom probe needle using off-axis electron holography without mean inner potential effects. Journal of Applied Physics 117, 134301 (2015). DOI:10.1063/1.4916609
It assumes some knowledge on how to use HyperSpy, like loading datasets and how the basic signals work.
This notebook requires:
HyperSpy 1.7 and above.
Vadim Migunov (Ernst Ruska-Centre for Microscopy and Spectroscopy with Electrons, Juelich, Germany, email: v.migunov@fz-juelich.de), created on 08.11.2016
Donwload the data
%matplotlib ipympl
import holospy as holo
import hyperspy.api as hs
import numpy as np
Loading object hologram of the needle at 0V bias and plotting it afterwards
holo0 = holo.datasets.Fe_needle_hologram()
hs.plot.plot_images([holo0, holo0.isig[150:250, 200:300]], tight_layout=True, axes_decor='off')
[<Axes: xlabel='x axis (nm)', ylabel='y axis (nm)'>, <Axes: xlabel='x axis (nm)', ylabel='y axis (nm)'>]
Loading object hologram of the needle at 5V bias and vacuum reference
holo5 = hs.load('./datasets/02_holo_Vbp_130V_5V_bin2_crop.hdf5', signal_type='hologram', reader='hspy')
C:\Users\M0041User\Dev\hyperspy\hyperspy\io.py:628: VisibleDeprecationWarning: Loading old file version. The binned attribute has been moved from metadata.Signal to axis.is_binned. Setting this attribute for all signal axes instead. warnings.warn('Loading old file version. The binned attribute '
ref = holo.datasets.Fe_needle_reference_hologram()
ref.plot(vmax='99.995th')
Reconstruction of off-axis holograms involves finding a sideband in FFT patttern, filtering the sideband and re-centering FFT in the centre of the sideband, followed by inverse Fourier transform
First, onc may check how does FFT of a hologram looks like:
fft_holo0 = holo0.fft(shift=True)
fft_holo0.plot(power_spectrum=True)
One sees two sidebands in upper and lower parts of the FFT. Those correspond to two complex conjugate electron waves. Selecting one or another will only change sign of the reconstructed phase. The criteria for the selection is the convention that the phase shift inside material is positive with respect to vacuum. This can be checked only after the reconstruction, therefore the upper sideband is selected for the moment:
m = hs.plot.markers.Rectangle(x1=0.09, y1=-0.32, x2=0.19, y2=-0.21, color='red')
fft_holo0.add_marker(m)
Prior to reconstruction the position of sideband centre and the radius of sideband filter have to be defined. To avoid artificial slopes in the reconstructed phase this has to be done using vacuum reference rather than object hologram:
sb_position = ref.estimate_sideband_position(sb='upper')
sb_position.data
array([390, 58], dtype=int64)
The output is HyperSpy's Signal1D
Note: The coordinates of sideband are given for non-shifted FFT, therefore there are differnt from above!
sb_size = ref.estimate_sideband_size(sb_position)
sb_size.data
array([67.54257916])
By default sideband size is set to half a distance from sideband to origin and it is Signal1D class as well
Reconstructing both holograms with vacuum reference, setting output_shape to the size of the sideband filter to avoid oversampling:
wave0 = holo0.reconstruct_phase(ref, sb_position=sb_position, sb_size=sb_size,
output_shape=(int(sb_size.data*2), int(sb_size.data*2)))
wave5 = holo5.reconstruct_phase(ref, sb_position=sb_position, sb_size=sb_size,
output_shape=(int(sb_size.data*2), int(sb_size.data*2)))
hs.plot.plot_images([wave0.real, wave0.imag, wave5.real, wave5.imag], vmin='0.5th', vmax='99.5th',
per_row=2, cmap="RdBu_r", tight_layout=True, )
WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals. WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals. WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals. WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals. WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals. WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals.
[<Axes: title={'center': 'real(Hologram of Fe needle)'}, xlabel='x axis (nm)', ylabel='y axis (nm)'>, <Axes: title={'center': 'imag(Hologram of Fe needle)'}, xlabel='x axis (nm)', ylabel='y axis (nm)'>, <Axes: title={'center': 'real(13_holo_+05_130V_5V)'}, xlabel='x axis (nm)', ylabel='y axis (nm)'>, <Axes: title={'center': 'imag(13_holo_+05_130V_5V)'}, xlabel='x axis (nm)', ylabel='y axis (nm)'>]
Plotting amplitude of a reconstructed wave:
wave5.amplitude.plot(vmin=0, vmax='99.5th')
WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals.
Wrapped phase:
wave5.phase.plot(cmap="RdBu_r")
WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals.
Since phase changes between -Pi and PI, it possesse rapid jumps called phase wraps. The phase can be unwrapped as follows:
wave5.unwrapped_phase().plot(cmap="RdBu_r")
WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals. WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals.
[########################################] | 100% Completed | 108.87 ms
C:\Users\M0041User\Dev\hyperspy\hyperspy\misc\utils.py:1450: FutureWarning: `seed` is a deprecated argument name for `unwrap_phase`. It will be removed in version 0.23. Please use `rng` instead. output = function(test_data, **kwargs) C:\Users\M0041User\Dev\hyperspy\hyperspy\misc\utils.py:1370: FutureWarning: `seed` is a deprecated argument name for `unwrap_phase`. It will be removed in version 0.23. Please use `rng` instead. output_array[islice] = function(data[islice], **kwargs) C:\Users\M0041User\Dev\hyperspy\hyperspy\misc\utils.py:1370: FutureWarning: `seed` is a deprecated argument name for `unwrap_phase`. It will be removed in version 0.23. Please use `rng` instead. output_array[islice] = function(data[islice], **kwargs)
WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals.
One sees, that the phase shift inside material is positive, therefore the sideband was selected correctly.
The phase shift shown above includes three contributions:
Since 1 and 2 are the same for both holograms, the 0V phase shift should be subtracted from 5V phase shift in order to access external electrostatic field contribution only. Though, two factors have to be taken into account:
Trying simple subtraction without alignment:
wave_electrostatic = wave5 / wave0
wave_electrostatic.phase.plot(cmap="RdBu_r")
WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals.
One sees the shadows around needle surface which is a clear indication for missalignment of the images. Aligning the images:
phase_stack = hs.stack([wave0.unwrapped_phase(), wave5.unwrapped_phase()])
shifts = phase_stack.estimate_shift2D()
WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals. WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals.
[########################################] | 100% Completed | 107.28 ms
C:\Users\M0041User\Dev\hyperspy\hyperspy\misc\utils.py:1450: FutureWarning: `seed` is a deprecated argument name for `unwrap_phase`. It will be removed in version 0.23. Please use `rng` instead. output = function(test_data, **kwargs) C:\Users\M0041User\Dev\hyperspy\hyperspy\misc\utils.py:1370: FutureWarning: `seed` is a deprecated argument name for `unwrap_phase`. It will be removed in version 0.23. Please use `rng` instead. output_array[islice] = function(data[islice], **kwargs) C:\Users\M0041User\Dev\hyperspy\hyperspy\misc\utils.py:1370: FutureWarning: `seed` is a deprecated argument name for `unwrap_phase`. It will be removed in version 0.23. Please use `rng` instead. output_array[islice] = function(data[islice], **kwargs) WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals. WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals. WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals.
[ ] | 0% Completed | 455.90 us
C:\Users\M0041User\Dev\hyperspy\hyperspy\misc\utils.py:1450: FutureWarning: `seed` is a deprecated argument name for `unwrap_phase`. It will be removed in version 0.23. Please use `rng` instead. output = function(test_data, **kwargs) C:\Users\M0041User\Dev\hyperspy\hyperspy\misc\utils.py:1370: FutureWarning: `seed` is a deprecated argument name for `unwrap_phase`. It will be removed in version 0.23. Please use `rng` instead. output_array[islice] = function(data[islice], **kwargs) C:\Users\M0041User\Dev\hyperspy\hyperspy\misc\utils.py:1370: FutureWarning: `seed` is a deprecated argument name for `unwrap_phase`. It will be removed in version 0.23. Please use `rng` instead. output_array[islice] = function(data[islice], **kwargs)
[########################################] | 100% Completed | 106.50 ms
WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals. WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals. WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals. WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals. WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals.
[########################################] | 100% Completed | 114.52 ms
WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals.
0%| | 0/2 [00:00<?, ?it/s]
shifts
array([[ 0, 0], [ 0, -1]], dtype=int64)
Typically alignment of holograms is not a trivial task. Different methods should be tried to achiev best results. Also a subpixel alignmnet is benifitial especially for the case when the size of reconstructed image set to the size of sideband filter. Here the improovmnet of automatic alignment is skept and images are aligned manualy by varying shifts untill best results were achieved istead.
wave5a= wave5.deepcopy()
wave5a.map(np.roll, shift=0, axis=0)
wave5a.map(np.roll, shift=1, axis=1)
wave_electrostatic = wave5a / wave0
wave_electrostatic.phase.plot(cmap="RdBu_r")
WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals.
[########################################] | 100% Completed | 107.79 ms
WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals. WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals.
[########################################] | 100% Completed | 111.41 ms
WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals. WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals.
One can get unwrapped phase shift due to external electrostatic field:
uphase_electrostatic = wave_electrostatic.unwrapped_phase()
uphase_electrostatic.plot(cmap="RdBu_r")
WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals. WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals.
[########################################] | 100% Completed | 106.35 ms
C:\Users\M0041User\Dev\hyperspy\hyperspy\misc\utils.py:1450: FutureWarning: `seed` is a deprecated argument name for `unwrap_phase`. It will be removed in version 0.23. Please use `rng` instead. output = function(test_data, **kwargs) C:\Users\M0041User\Dev\hyperspy\hyperspy\misc\utils.py:1370: FutureWarning: `seed` is a deprecated argument name for `unwrap_phase`. It will be removed in version 0.23. Please use `rng` instead. output_array[islice] = function(data[islice], **kwargs) C:\Users\M0041User\Dev\hyperspy\hyperspy\misc\utils.py:1370: FutureWarning: `seed` is a deprecated argument name for `unwrap_phase`. It will be removed in version 0.23. Please use `rng` instead. output_array[islice] = function(data[islice], **kwargs)
WARNING:hyperspy.io:`signal_type='complex_signal2d'` not understood. See `hs.print_known_signal_types()` for a list of installed signal types or https://github.com/hyperspy/hyperspy-extensions-list for the list of all hyperspy extensions providing signals.
Use a cosine function to plot equiphase contours which represent projected equipotential lines (here the cosine argument is multiplied with 2 that corresponds to contour separation of PI):
contours_electrostatic = uphase_electrostatic._deepcopy_with_new_data(np.cos(2*uphase_electrostatic.data))
contours_electrostatic.plot(cmap="RdBu_r")
Signal uphase_electrostatic can be used for further analyses of charge distribution using Laplacian or loop integration of phase gradient. The corresponding functions will be included in next releases