Note
Go to the end to download the full example code.
Strain Mapping#
Strain mapping in pyxem is done by fitting a DisplacementGradientMap to the data.
This can be thought of as image distortion around some central point.
from pyxem.data import simulated_strain
import hyperspy.api as hs
In this example we will create a simulated strain map using the simulated_strain() function.
This just creates a simulated diffraction pattern and applies a simple “strain” to it. In this
case using simulated data is slightly easier for demonstration purposes. If you want to use
real data the zrnb_precipitate() dataset is a good example of strain from a precipitate.
strained_signal = simulated_strain(
navigation_shape=(32, 32),
signal_shape=(512, 512),
disk_radius=20,
num_electrons=1e5,
strain_matrix=None,
lazy=True,
)
The first thing we want to do is to find peaks within the diffraction pattern. I’d recommend
using the get_diffraction_vectors() method
strained_signal.calibration.center = (
None # First set the center to be (256, 256) or the center of the signal
)
template_matched = strained_signal.template_match_disk(disk_r=20, subtract_min=False)
template_matched.plot(vmin=0.4)
0%| | 0/65 [00:00<?, ?it/s]
2%|▏ | 1/65 [00:00<00:33, 1.92it/s]
8%|▊ | 5/65 [00:01<00:11, 5.41it/s]
14%|█▍ | 9/65 [00:01<00:08, 6.65it/s]
20%|██ | 13/65 [00:02<00:07, 7.23it/s]
26%|██▌ | 17/65 [00:02<00:06, 7.56it/s]
32%|███▏ | 21/65 [00:02<00:05, 7.95it/s]
38%|███▊ | 25/65 [00:03<00:04, 8.27it/s]
45%|████▍ | 29/65 [00:03<00:04, 8.49it/s]
48%|████▊ | 31/65 [00:03<00:03, 9.46it/s]
51%|█████ | 33/65 [00:04<00:03, 8.36it/s]
54%|█████▍ | 35/65 [00:04<00:03, 9.46it/s]
57%|█████▋ | 37/65 [00:04<00:03, 8.36it/s]
60%|██████ | 39/65 [00:04<00:02, 9.38it/s]
63%|██████▎ | 41/65 [00:05<00:02, 8.42it/s]
66%|██████▌ | 43/65 [00:05<00:02, 9.28it/s]
69%|██████▉ | 45/65 [00:05<00:02, 8.47it/s]
72%|███████▏ | 47/65 [00:05<00:01, 9.19it/s]
75%|███████▌ | 49/65 [00:06<00:01, 8.61it/s]
78%|███████▊ | 51/65 [00:06<00:01, 9.06it/s]
82%|████████▏ | 53/65 [00:06<00:01, 8.67it/s]
85%|████████▍ | 55/65 [00:06<00:01, 8.95it/s]
88%|████████▊ | 57/65 [00:06<00:00, 8.83it/s]
91%|█████████ | 59/65 [00:07<00:00, 8.81it/s]
94%|█████████▍| 61/65 [00:07<00:00, 8.92it/s]
97%|█████████▋| 63/65 [00:07<00:00, 8.95it/s]
100%|██████████| 65/65 [00:07<00:00, 8.53it/s]
Plotting the template matched signal and setting vmin is a good way to see what threshold you
should use for the get_diffraction_vectors() method.
diffraction_vectors = template_matched.get_diffraction_vectors(
threshold_abs=0.4, min_distance=5
)
markers = diffraction_vectors.to_markers(color="w", sizes=5, alpha=0.5)
strained_signal.plot()
strained_signal.add_marker(markers)
0%| | 0/65 [00:00<?, ?it/s]
100%|██████████| 65/65 [00:00<00:00, 1023.69it/s]
Determining the Strain#
We can just use the first ring of the diffraction pattern to determine the strain. We can do this by
using the filter_magnitude() method. You can also look at the
filtering vectors example to see
how to select which vectors you want to use more generally. You can also just manually input the un-strained
vectors or use simulated/ rotated vectors as well.
first_ring_vectors = diffraction_vectors.filter_magnitude(
min_magnitude=0.1,
max_magnitude=1,
)
unstrained_vectors = first_ring_vectors.inav[0, 0]
strain_maps = first_ring_vectors.get_strain_maps(
unstrained_vectors=unstrained_vectors, return_residuals=False
)
strain_maps.plot()

0%| | 0/2 [00:00<?, ?it/s]
50%|█████ | 1/2 [00:00<00:00, 1.66it/s]
100%|██████████| 2/2 [00:00<00:00, 3.31it/s]
0%| | 0/65 [00:00<?, ?it/s]
2%|▏ | 1/65 [00:00<00:40, 1.56it/s]
8%|▊ | 5/65 [00:01<00:13, 4.33it/s]
14%|█▍ | 9/65 [00:01<00:10, 5.21it/s]
20%|██ | 13/65 [00:02<00:09, 5.62it/s]
23%|██▎ | 15/65 [00:02<00:07, 6.63it/s]
26%|██▌ | 17/65 [00:03<00:08, 5.64it/s]
29%|██▉ | 19/65 [00:03<00:07, 6.56it/s]
32%|███▏ | 21/65 [00:03<00:07, 5.68it/s]
35%|███▌ | 23/65 [00:04<00:06, 6.56it/s]
38%|███▊ | 25/65 [00:04<00:06, 5.74it/s]
42%|████▏ | 27/65 [00:04<00:05, 6.38it/s]
45%|████▍ | 29/65 [00:05<00:06, 5.82it/s]
48%|████▊ | 31/65 [00:05<00:05, 6.28it/s]
51%|█████ | 33/65 [00:05<00:05, 5.93it/s]
54%|█████▍ | 35/65 [00:06<00:04, 6.20it/s]
57%|█████▋ | 37/65 [00:06<00:04, 6.00it/s]
60%|██████ | 39/65 [00:06<00:04, 6.09it/s]
63%|██████▎ | 41/65 [00:07<00:03, 6.09it/s]
66%|██████▌ | 43/65 [00:07<00:03, 6.03it/s]
69%|██████▉ | 45/65 [00:07<00:03, 6.13it/s]
72%|███████▏ | 47/65 [00:08<00:02, 6.02it/s]
75%|███████▌ | 49/65 [00:08<00:02, 6.24it/s]
78%|███████▊ | 51/65 [00:08<00:02, 5.99it/s]
82%|████████▏ | 53/65 [00:08<00:01, 6.27it/s]
85%|████████▍ | 55/65 [00:09<00:01, 5.92it/s]
88%|████████▊ | 57/65 [00:09<00:01, 6.35it/s]
91%|█████████ | 59/65 [00:10<00:01, 5.90it/s]
94%|█████████▍| 61/65 [00:10<00:00, 6.47it/s]
97%|█████████▋| 63/65 [00:10<00:00, 5.96it/s]
100%|██████████| 65/65 [00:10<00:00, 6.09it/s]
0%| | 0/33 [00:00<?, ?it/s]
100%|██████████| 33/33 [00:00<00:00, 1009.62it/s]
0%| | 0/33 [00:00<?, ?it/s]
100%|██████████| 33/33 [00:00<00:00, 1571.97it/s]
0%| | 0/33 [00:00<?, ?it/s]
100%|██████████| 33/33 [00:00<00:00, 7380.40it/s]
0%| | 0/9 [00:00<?, ?it/s]
100%|██████████| 9/9 [00:00<00:00, 11251.49it/s]
[<Axes: title={'center': 'e11'}, xlabel='x axis (nm)', ylabel='y axis (nm)'>, <Axes: title={'center': 'e22'}, xlabel='x axis (nm)', ylabel='y axis (nm)'>, <Axes: title={'center': 'e12'}, xlabel='x axis (nm)', ylabel='y axis (nm)'>, <Axes: title={'center': 'theta'}, xlabel='x axis (nm)', ylabel='y axis (nm)'>]
Some final notes about strain mapping. In general, you want to use as many pixels as possible. 512 x 512 is a good place to start. You can do strain mapping with fewer pixels, but the results will be less accurate. Precession also helps improve the results as does having a thinner sample both of which reduce the effects of dynamical diffraction.
sphinx_gallery_thumbnail_number = 5
Total running time of the script: (0 minutes 31.813 seconds)



