pyTEMlib 0.2025.4.1__py3-none-any.whl → 0.2025.9.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyTEMlib might be problematic. Click here for more details.
- build/lib/pyTEMlib/__init__.py +33 -0
- build/lib/pyTEMlib/animation.py +640 -0
- build/lib/pyTEMlib/atom_tools.py +238 -0
- build/lib/pyTEMlib/config_dir.py +31 -0
- build/lib/pyTEMlib/crystal_tools.py +1219 -0
- build/lib/pyTEMlib/diffraction_plot.py +756 -0
- build/lib/pyTEMlib/dynamic_scattering.py +293 -0
- build/lib/pyTEMlib/eds_tools.py +826 -0
- build/lib/pyTEMlib/eds_xsections.py +432 -0
- build/lib/pyTEMlib/eels_tools/__init__.py +44 -0
- build/lib/pyTEMlib/eels_tools/core_loss_tools.py +751 -0
- build/lib/pyTEMlib/eels_tools/eels_database.py +134 -0
- build/lib/pyTEMlib/eels_tools/low_loss_tools.py +655 -0
- build/lib/pyTEMlib/eels_tools/peak_fit_tools.py +175 -0
- build/lib/pyTEMlib/eels_tools/zero_loss_tools.py +264 -0
- build/lib/pyTEMlib/file_reader.py +274 -0
- build/lib/pyTEMlib/file_tools.py +811 -0
- build/lib/pyTEMlib/get_bote_salvat.py +69 -0
- build/lib/pyTEMlib/graph_tools.py +1153 -0
- build/lib/pyTEMlib/graph_viz.py +599 -0
- build/lib/pyTEMlib/image/__init__.py +37 -0
- build/lib/pyTEMlib/image/image_atoms.py +270 -0
- build/lib/pyTEMlib/image/image_clean.py +197 -0
- build/lib/pyTEMlib/image/image_distortion.py +299 -0
- build/lib/pyTEMlib/image/image_fft.py +277 -0
- build/lib/pyTEMlib/image/image_graph.py +926 -0
- build/lib/pyTEMlib/image/image_registration.py +316 -0
- build/lib/pyTEMlib/image/image_utilities.py +309 -0
- build/lib/pyTEMlib/image/image_window.py +421 -0
- build/lib/pyTEMlib/image_tools.py +699 -0
- build/lib/pyTEMlib/interactive_image.py +1 -0
- build/lib/pyTEMlib/kinematic_scattering.py +1196 -0
- build/lib/pyTEMlib/microscope.py +61 -0
- build/lib/pyTEMlib/probe_tools.py +906 -0
- build/lib/pyTEMlib/sidpy_tools.py +153 -0
- build/lib/pyTEMlib/simulation_tools.py +104 -0
- build/lib/pyTEMlib/test.py +437 -0
- build/lib/pyTEMlib/utilities.py +314 -0
- build/lib/pyTEMlib/version.py +5 -0
- build/lib/pyTEMlib/xrpa_x_sections.py +20976 -0
- pyTEMlib/__init__.py +25 -3
- pyTEMlib/animation.py +31 -22
- pyTEMlib/atom_tools.py +29 -34
- pyTEMlib/config_dir.py +2 -28
- pyTEMlib/crystal_tools.py +129 -165
- pyTEMlib/eds_tools.py +559 -342
- pyTEMlib/eds_xsections.py +432 -0
- pyTEMlib/eels_tools/__init__.py +44 -0
- pyTEMlib/eels_tools/core_loss_tools.py +751 -0
- pyTEMlib/eels_tools/eels_database.py +134 -0
- pyTEMlib/eels_tools/low_loss_tools.py +655 -0
- pyTEMlib/eels_tools/peak_fit_tools.py +175 -0
- pyTEMlib/eels_tools/zero_loss_tools.py +264 -0
- pyTEMlib/file_reader.py +274 -0
- pyTEMlib/file_tools.py +260 -1130
- pyTEMlib/get_bote_salvat.py +69 -0
- pyTEMlib/graph_tools.py +101 -174
- pyTEMlib/graph_viz.py +150 -0
- pyTEMlib/image/__init__.py +37 -0
- pyTEMlib/image/image_atoms.py +270 -0
- pyTEMlib/image/image_clean.py +197 -0
- pyTEMlib/image/image_distortion.py +299 -0
- pyTEMlib/image/image_fft.py +277 -0
- pyTEMlib/image/image_graph.py +926 -0
- pyTEMlib/image/image_registration.py +316 -0
- pyTEMlib/image/image_utilities.py +309 -0
- pyTEMlib/image/image_window.py +421 -0
- pyTEMlib/image_tools.py +154 -915
- pyTEMlib/kinematic_scattering.py +1 -1
- pyTEMlib/probe_tools.py +1 -1
- pyTEMlib/test.py +437 -0
- pyTEMlib/utilities.py +314 -0
- pyTEMlib/version.py +2 -3
- pyTEMlib/xrpa_x_sections.py +14 -10
- {pytemlib-0.2025.4.1.dist-info → pytemlib-0.2025.9.1.dist-info}/METADATA +13 -16
- pytemlib-0.2025.9.1.dist-info/RECORD +86 -0
- {pytemlib-0.2025.4.1.dist-info → pytemlib-0.2025.9.1.dist-info}/WHEEL +1 -1
- pytemlib-0.2025.9.1.dist-info/top_level.txt +6 -0
- pyTEMlib/core_loss_widget.py +0 -721
- pyTEMlib/eels_dialog.py +0 -754
- pyTEMlib/eels_dialog_utilities.py +0 -1199
- pyTEMlib/eels_tools.py +0 -2359
- pyTEMlib/file_tools_qt.py +0 -193
- pyTEMlib/image_dialog.py +0 -158
- pyTEMlib/image_dlg.py +0 -146
- pyTEMlib/info_widget.py +0 -1086
- pyTEMlib/info_widget3.py +0 -1120
- pyTEMlib/low_loss_widget.py +0 -479
- pyTEMlib/peak_dialog.py +0 -1129
- pyTEMlib/peak_dlg.py +0 -286
- pytemlib-0.2025.4.1.dist-info/RECORD +0 -38
- pytemlib-0.2025.4.1.dist-info/top_level.txt +0 -1
- {pytemlib-0.2025.4.1.dist-info → pytemlib-0.2025.9.1.dist-info}/entry_points.txt +0 -0
- {pytemlib-0.2025.4.1.dist-info → pytemlib-0.2025.9.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
PyTEMlib
|
|
4
|
+
--------
|
|
5
|
+
A Python package for analyzing and processing transmission electron microscopy (TEM) data.
|
|
6
|
+
This package provides tools for data quantification through a model-based approach,
|
|
7
|
+
including functionalities for imaging, spectra analysis, and data visualization.
|
|
8
|
+
|
|
9
|
+
The package is part of the pycrosccopy ecosystem and the dataformat is based on sidpy,
|
|
10
|
+
the fileformat is based on pyNSDI.
|
|
11
|
+
Created on Sat Jan 19 10:07:35 2019
|
|
12
|
+
Update on Sun Jul 20 2025
|
|
13
|
+
|
|
14
|
+
@author: gduscher
|
|
15
|
+
"""
|
|
16
|
+
from .version import __version__
|
|
17
|
+
|
|
18
|
+
from . import file_tools
|
|
19
|
+
from . import image_tools
|
|
20
|
+
from .image import image_atoms as atom_tools
|
|
21
|
+
from . import graph_tools
|
|
22
|
+
from . import probe_tools
|
|
23
|
+
from . import eels_tools
|
|
24
|
+
from . import eds_tools
|
|
25
|
+
from . import crystal_tools
|
|
26
|
+
from . import kinematic_scattering
|
|
27
|
+
from . import dynamic_scattering
|
|
28
|
+
from .config_dir import config_path
|
|
29
|
+
|
|
30
|
+
__all__ = ['__version__', 'file_tools', 'image_tools', 'atom_tools',
|
|
31
|
+
'graph_tools', 'probe_tools', 'eels_tools', 'eds_tools',
|
|
32
|
+
'crystal_tools', 'kinematic_scattering', 'dynamic_scattering', 'config_path']
|
|
33
|
+
__author__ = 'Gerd Duscher'
|
|
@@ -0,0 +1,640 @@
|
|
|
1
|
+
"""Figures and Animations for TEM in jupyter notebooks
|
|
2
|
+
part of MSE 672 course at UTK
|
|
3
|
+
|
|
4
|
+
Author: Gerd Duscher
|
|
5
|
+
revision: 01/11/2021
|
|
6
|
+
03/17/2021 added Aberration Animation
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
import matplotlib.pyplot as plt
|
|
11
|
+
from matplotlib import patches
|
|
12
|
+
|
|
13
|
+
from ipywidgets import widgets
|
|
14
|
+
from IPython.display import display
|
|
15
|
+
|
|
16
|
+
import pyTEMlib.kinematic_scattering as ks
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def geometric_ray_diagram(focal_length=1., magnification=False):
|
|
20
|
+
""" Sketch of geometric ray diagram od one lens
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
focal_length: float
|
|
25
|
+
focal length of lens
|
|
26
|
+
magnification: boolean
|
|
27
|
+
draw magnification on the side
|
|
28
|
+
|
|
29
|
+
Returns
|
|
30
|
+
-------
|
|
31
|
+
matplotlib figure
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
f = focal_length
|
|
35
|
+
|
|
36
|
+
u = 1.5
|
|
37
|
+
v = 1 / (1 / f - 1 / u)
|
|
38
|
+
m = v / u
|
|
39
|
+
if magnification:
|
|
40
|
+
line_strong = .5
|
|
41
|
+
else:
|
|
42
|
+
line_strong = 2
|
|
43
|
+
|
|
44
|
+
x = 0.4
|
|
45
|
+
|
|
46
|
+
fig, ax = plt.subplots()
|
|
47
|
+
|
|
48
|
+
# add an ellipse
|
|
49
|
+
ellipse = patches.Ellipse((0.0, 0.0), 3.4, 0.3, alpha=0.3, color='blue')
|
|
50
|
+
ax.add_patch(ellipse)
|
|
51
|
+
ax.plot([1.5, -1.5], [0, 0], '--', color='black')
|
|
52
|
+
ax.plot([0, 0], [u, -v], '--', color='black')
|
|
53
|
+
single_prop = {"arrowstyle": '->', "shrinkA": 0, "shrinkB": 0}
|
|
54
|
+
double_prop = {"arrowstyle": "<->", "shrinkA": 0, "shrinkB": 0}
|
|
55
|
+
|
|
56
|
+
if magnification:
|
|
57
|
+
ax.annotate("", xy=(-x, u), xytext=(x, u), arrowprops=single_prop)
|
|
58
|
+
ax.annotate("", xy=(x * m, -v), xytext=(-x * m, -v), arrowprops=single_prop)
|
|
59
|
+
|
|
60
|
+
else:
|
|
61
|
+
ax.annotate("", xy=(-x, u), xytext=(0, u), arrowprops=single_prop)
|
|
62
|
+
ax.annotate("", xy=(x * m, -v), xytext=(0, -v), arrowprops=single_prop)
|
|
63
|
+
|
|
64
|
+
ax.text(x + 0.1, u, 'object plane', va='center')
|
|
65
|
+
ax.plot([1, -1], [-f, -f], '--', color='black')
|
|
66
|
+
ax.text(1.1, -f, 'back focal\n plane', va='center')
|
|
67
|
+
ax.text(x * m + 0.1, -v, 'image plane', va='center')
|
|
68
|
+
|
|
69
|
+
ax.annotate("", xy=(-.9, 0), xytext=(-.9, -f), arrowprops=double_prop)
|
|
70
|
+
ax.text(-1, -f / 2, 'f')
|
|
71
|
+
if magnification:
|
|
72
|
+
ax.annotate("", xy=(-1.8, 0), xytext=(-1.8, -v), arrowprops=double_prop)
|
|
73
|
+
ax.text(-1.7, -v / 2, 'v')
|
|
74
|
+
ax.annotate("", xy=(-1.8, 0), xytext=(-1.8, u), arrowprops=double_prop)
|
|
75
|
+
ax.text(-1.7, u / 2, 'u')
|
|
76
|
+
|
|
77
|
+
ax.plot([-x, x * m], [u, -v], color='black', linewidth=line_strong)
|
|
78
|
+
ax.plot([-x, -x], [u, 0], color='black', linewidth=line_strong)
|
|
79
|
+
ax.plot([-x, x * m], [0, -v], color='black', linewidth=line_strong)
|
|
80
|
+
|
|
81
|
+
ax.plot([-x, -2 * x], [u, 0], color='black', linewidth=0.5)
|
|
82
|
+
ax.plot([-2 * x, x * m], [0, -v], color='black', linewidth=0.5)
|
|
83
|
+
if magnification:
|
|
84
|
+
ax.plot([x, -x * m], [u, -v], color='black', linewidth=0.5)
|
|
85
|
+
ax.plot([x, x], [u, 0], color='black', linewidth=0.5)
|
|
86
|
+
ax.plot([x, -x * m], [0, -v], color='black', linewidth=0.5)
|
|
87
|
+
|
|
88
|
+
ax.plot([x, 2 * x], [u, 0], color='black', linewidth=0.5)
|
|
89
|
+
ax.plot([2 * x, -x * m], [0, -v], color='black', linewidth=0.5)
|
|
90
|
+
else:
|
|
91
|
+
ax.plot([-x, x * m], [u, 0], color='black', linewidth=0.5)
|
|
92
|
+
ax.plot([x * m, x * m], [0, -v], color='black', linewidth=0.5)
|
|
93
|
+
|
|
94
|
+
ax.set_xlim(-2, 3)
|
|
95
|
+
ax.set_ylim(-3.5, 2)
|
|
96
|
+
ax.set_aspect('equal')
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
# ----------------------------------------------------------------
|
|
100
|
+
# Modified from Michael Fairchild :simply draws a thin-lens at the provided location parameters:
|
|
101
|
+
# - z: location along the optical axis (in mm)
|
|
102
|
+
# - f: focal length (in mm, can be negative if div. lens)
|
|
103
|
+
# - diam: lens diameter in mm
|
|
104
|
+
# - lens_labels: label to identify the lens on the drawing
|
|
105
|
+
# ----------------------------------------------------------------
|
|
106
|
+
def add_lens(z, f, diam, lens_labels):
|
|
107
|
+
"""add lens to propagate beam plot"""
|
|
108
|
+
ww, tw, rad = diam / 10.0, diam / 3.0, diam / 2.0
|
|
109
|
+
plt.plot([z, z], [-rad, rad], 'k', linewidth=2)
|
|
110
|
+
plt.plot([z, z + tw], [-rad, -rad + np.sign(f) * ww], 'k', linewidth=2)
|
|
111
|
+
plt.plot([z, z - tw], [-rad, -rad + np.sign(f) * ww], 'k', linewidth=2)
|
|
112
|
+
plt.plot([z, z + tw], [rad, rad - np.sign(f) * ww], 'k', linewidth=2)
|
|
113
|
+
plt.plot([z, z - tw], [rad, rad - np.sign(f) * ww], 'k', linewidth=2)
|
|
114
|
+
plt.plot([z + f, z + f], [-ww, ww], 'k', linewidth=2)
|
|
115
|
+
plt.plot([z - f, z - f], [-ww, ww], 'k', linewidth=2)
|
|
116
|
+
plt.text(z, rad + 5.0, lens_labels, fontsize=12)
|
|
117
|
+
plt.text(z, rad + 2.0, 'f=' + str(int(f)), fontsize=10)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def add_aperture(z, diam, radius, lens_labels):
|
|
121
|
+
"""add aperture to propagate beam plot"""
|
|
122
|
+
|
|
123
|
+
# ww, tw, rad = diam / 10.0, diam / 3.0, diam / 2.0
|
|
124
|
+
rad = diam / 2
|
|
125
|
+
radius = radius / 2
|
|
126
|
+
plt.plot([z, z], [-rad, -radius], 'k', linewidth=2)
|
|
127
|
+
plt.plot([z, z], [rad, radius], 'k', linewidth=2)
|
|
128
|
+
plt.text(z, -rad - 2.0, lens_labels, fontsize=12)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def propagate_beam(source_position, numerical_aperture, number_of_rays,
|
|
132
|
+
lens_positions, focal_lengths,
|
|
133
|
+
lens_labels='', color='b'):
|
|
134
|
+
"""geometrical propagation of light rays from given source
|
|
135
|
+
|
|
136
|
+
Parameters
|
|
137
|
+
----------
|
|
138
|
+
source_position: list
|
|
139
|
+
location of the source (z0, x0) along and off axis (in mm)
|
|
140
|
+
numerical_aperture: float
|
|
141
|
+
numerical aperture of the beam (in degrees)
|
|
142
|
+
number_of_rays: int
|
|
143
|
+
number of rays to trace
|
|
144
|
+
lens_positions: numpy array
|
|
145
|
+
array with the location of the lenses
|
|
146
|
+
focal_lengths: numpy array
|
|
147
|
+
array with the focal length of lenses
|
|
148
|
+
lens_labels: list of string
|
|
149
|
+
label for the nature of lenses
|
|
150
|
+
color: str
|
|
151
|
+
color of the rays on plot
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
plt.figure()
|
|
155
|
+
z_max = 1600.
|
|
156
|
+
|
|
157
|
+
# aperture (maximum angle) in radians
|
|
158
|
+
apa = numerical_aperture * np.pi / 180.0
|
|
159
|
+
|
|
160
|
+
for i in range(np.size(lens_positions)):
|
|
161
|
+
add_lens(lens_positions[i], focal_lengths[i], 25, lens_labels[i])
|
|
162
|
+
|
|
163
|
+
add_aperture(840, 25, 7, 'CA')
|
|
164
|
+
|
|
165
|
+
# position of source is z0,x0
|
|
166
|
+
z0 = source_position[0]
|
|
167
|
+
if np.size(source_position) == 2:
|
|
168
|
+
x0 = source_position[1]
|
|
169
|
+
else:
|
|
170
|
+
x0 = 0.0
|
|
171
|
+
|
|
172
|
+
# list of lens positions
|
|
173
|
+
zl1, ff1 = lens_positions[(z0 < lens_positions)], focal_lengths[(z0 < lens_positions)]
|
|
174
|
+
nl = np.size(zl1) # number of lenses
|
|
175
|
+
|
|
176
|
+
zz, xx, tani = np.zeros(nl + 2), np.zeros(nl + 2), np.zeros(nl + 2)
|
|
177
|
+
tan0 = np.tan(apa / 2.0) - np.tan(apa) * np.arange(number_of_rays) / (number_of_rays - 1)
|
|
178
|
+
|
|
179
|
+
for i in range(number_of_rays):
|
|
180
|
+
tani[0] = tan0[i] # initial incidence angle
|
|
181
|
+
zz[0], xx[0] = z0, x0
|
|
182
|
+
for j in range(nl):
|
|
183
|
+
zz[j + 1] = zl1[j]
|
|
184
|
+
xx[j + 1] = xx[j] + (zz[j + 1] - zz[j]) * tani[j]
|
|
185
|
+
tani[j + 1] = tani[j] - xx[j + 1] / ff1[j]
|
|
186
|
+
|
|
187
|
+
zz[nl + 1] = z_max
|
|
188
|
+
xx[nl + 1] = xx[nl] + (zz[nl + 1] - zz[nl]) * tani[nl]
|
|
189
|
+
plt.plot(zz, xx, color)
|
|
190
|
+
plt.axis([-20, z_max, -20, 20])
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def deficient_holz_line(exact_bragg=False, shift=False, laue_zone=1, color='black'):
|
|
194
|
+
"""
|
|
195
|
+
Ewald sphere construction to explain Laue Circle and deficient HOLZ lines
|
|
196
|
+
|
|
197
|
+
Parameters:
|
|
198
|
+
exact_bragg: boolean
|
|
199
|
+
whether to tilt into exact Bragg condition or along zone axis
|
|
200
|
+
shift: boolean
|
|
201
|
+
whether to shift exact Bragg-condition onto zone axis origin
|
|
202
|
+
laue_zone: int
|
|
203
|
+
first or second Laue zone only
|
|
204
|
+
color: string
|
|
205
|
+
color of wave vectors and Ewald sphere
|
|
206
|
+
"""
|
|
207
|
+
|
|
208
|
+
k_0 = [0, 1 / ks.get_wavelength(600)]
|
|
209
|
+
|
|
210
|
+
d = 5. # lattice parameter in nm
|
|
211
|
+
|
|
212
|
+
if laue_zone == 0:
|
|
213
|
+
s_g = 1 / d + 0.06
|
|
214
|
+
else:
|
|
215
|
+
s_g = .1
|
|
216
|
+
|
|
217
|
+
g = np.linspace(-5, 6, 12) * 1 / d
|
|
218
|
+
g_d = np.array([5. / d + laue_zone * 1 / d / 2, laue_zone * 1 / d])
|
|
219
|
+
g_sg = g_d.copy()
|
|
220
|
+
g_sg[1] = g_d[1] + s_g # point on Ewald sphere
|
|
221
|
+
|
|
222
|
+
# reciprocal lattice
|
|
223
|
+
plt.scatter(g[:-1], [0] * 11, color='red')
|
|
224
|
+
plt.scatter(g - 1 / d / 2, [1 / d] * 12, color='blue')
|
|
225
|
+
|
|
226
|
+
shift_x = shift_y = 0.
|
|
227
|
+
d_theta = d_theta1 = d_theta2 = 0
|
|
228
|
+
|
|
229
|
+
if exact_bragg:
|
|
230
|
+
|
|
231
|
+
d_theta1 = np.arctan((1 / d * laue_zone + s_g) / g_d[0])
|
|
232
|
+
d_theta2 = np.arctan((1 / d * laue_zone) / g_d[0])
|
|
233
|
+
d_theta = -(d_theta1 - d_theta2)
|
|
234
|
+
s_g = 0
|
|
235
|
+
s = np.sin(d_theta)
|
|
236
|
+
c = np.cos(d_theta)
|
|
237
|
+
k_0 = [-s * k_0[1], c * k_0[1]]
|
|
238
|
+
if shift:
|
|
239
|
+
shift_x = -k_0[0]
|
|
240
|
+
shift_y = np.linalg.norm(k_0) - k_0[1]
|
|
241
|
+
d_theta = np.degrees(d_theta)
|
|
242
|
+
|
|
243
|
+
k_0[0] += shift_x
|
|
244
|
+
k_0[1] += shift_y
|
|
245
|
+
|
|
246
|
+
# Ewald Sphere
|
|
247
|
+
ewald_sphere = patches.Circle((k_0[0], k_0[1]), radius=np.linalg.norm(k_0),
|
|
248
|
+
clip_on=False, zorder=10, linewidth=1,
|
|
249
|
+
edgecolor=color, fill=False)
|
|
250
|
+
plt.gca().add_artist(ewald_sphere)
|
|
251
|
+
|
|
252
|
+
plt.gca().arrow(g[-1] + .1 / d / 4, 1 / d / 2, 0, 1 / d / 2, head_width=0.03,
|
|
253
|
+
head_length=0.04, fc='k', ec='k', length_includes_head=True)
|
|
254
|
+
plt.gca().arrow(g[-1] + .1 / d / 4, 1 / d / 2, 0, -1 / d / 2, head_width=0.03,
|
|
255
|
+
head_length=0.04, fc='k', ec='k', length_includes_head=True)
|
|
256
|
+
plt.gca().annotate("$|g_{HOLZ}|$", xytext=(g[-1] + .1 / d / 3, 1 / d / 3),
|
|
257
|
+
xy=(g[-1] + 1 / d / 3, 1 / d / 3))
|
|
258
|
+
plt.scatter(k_0[0], k_0[1])
|
|
259
|
+
plt.gca().arrow(k_0[0], k_0[1], -k_0[0] + shift_x, -k_0[1] + shift_y, head_width=0.03,
|
|
260
|
+
head_length=0.04, fc=color, ec=color, length_includes_head=True)
|
|
261
|
+
plt.gca().annotate("K$_0$", xytext=(k_0[0] / 2, k_0[1] / 3), xy=(k_0[0] / 2, k_0[1] / 2))
|
|
262
|
+
|
|
263
|
+
# K_d Bragg of HOLZ reflection
|
|
264
|
+
plt.gca().arrow(k_0[0], k_0[1], -k_0[0] + g_d[0] + shift_x, -k_0[1] + g_d[1] + s_g + shift_y,
|
|
265
|
+
head_width=0.03, head_length=0.04, fc=color, ec=color,
|
|
266
|
+
length_includes_head=True)
|
|
267
|
+
plt.gca().annotate("K$_d$", xytext=(k_0[0] + (g_d[0] - k_0[0]) / 2, k_0[1] / 2),
|
|
268
|
+
xy=(6.5 / d / 2, k_0[1] / 2))
|
|
269
|
+
|
|
270
|
+
# s_g excitation Error of HOLZ reflection
|
|
271
|
+
if s_g > 0:
|
|
272
|
+
plt.gca().arrow(g_d[0], g_d[1], 0, s_g, head_width=0.03, head_length=0.04, fc='k',
|
|
273
|
+
ec='k', length_includes_head=True)
|
|
274
|
+
plt.gca().annotate("s$_g$", xytext=(g_d[0] * 1.01, g_d[1] + s_g / 3),
|
|
275
|
+
xy=(g_d[0] * 1.01, g_d[1] + s_g / 3))
|
|
276
|
+
|
|
277
|
+
# Bragg angle
|
|
278
|
+
g_sg = g_d
|
|
279
|
+
g_sg[1] = g_d[1] + s_g
|
|
280
|
+
plt.plot([0 + shift_x, g_sg[0] + shift_x], [0 + shift_y, g_d[1] + shift_y], color=color, linewidth=1, alpha=0.5,
|
|
281
|
+
linestyle='--')
|
|
282
|
+
plt.plot([k_0[0], g_sg[0] / 2 + shift_x], [k_0[1], g_sg[1] / 2 + shift_y], color=color, linewidth=1, alpha=0.5,
|
|
283
|
+
linestyle='--')
|
|
284
|
+
# d_theta = np.degrees(np.arctan(k_0[0]/k_0[1]))
|
|
285
|
+
bragg_angle = patches.Arc((k_0[0], k_0[1]), width=k_0[1], height=k_0[1], theta1=-90 + d_theta,
|
|
286
|
+
theta2=-90 + d_theta + np.degrees(np.arcsin(np.linalg.norm(g_sg / 2) / k_0[1])), fc=color,
|
|
287
|
+
ec=color)
|
|
288
|
+
|
|
289
|
+
plt.gca().annotate(r"$\theta $", xytext=(k_0[0] / 1.3, k_0[1] / 1.5), xy=(k_0[0] / 2 + g_d[0] / 4, k_0[1] / 2))
|
|
290
|
+
plt.gca().add_patch(bragg_angle)
|
|
291
|
+
|
|
292
|
+
# deviation/tilt angle
|
|
293
|
+
if np.abs(d_theta) > 0:
|
|
294
|
+
if shift:
|
|
295
|
+
deviation_angle = patches.Arc((k_0[0], k_0[1]), width=k_0[1] * 1.5, height=k_0[1] * 1.5,
|
|
296
|
+
theta1=-90 + d_theta,
|
|
297
|
+
theta2=-90,
|
|
298
|
+
fc=color, ec=color, linewidth=3)
|
|
299
|
+
plt.gca().annotate(r"$d \theta $", xytext=(k_0[0] - .13, k_0[1] / 3.7),
|
|
300
|
+
xy=(k_0[0] + g_d[0] / 4, k_0[1] / 2))
|
|
301
|
+
plt.gca().arrow(shift_x, -.2, 0, .2, head_width=0.05, head_length=0.06, fc=color, ec='black',
|
|
302
|
+
length_includes_head=True, linewidth=3)
|
|
303
|
+
plt.gca().annotate("deficient line", xytext=(shift_x * 2, -.2), xy=(shift_x, 0))
|
|
304
|
+
else:
|
|
305
|
+
deviation_angle = patches.Arc((0, 0), width=k_0[1], height=k_0[1],
|
|
306
|
+
theta1=np.degrees(d_theta2),
|
|
307
|
+
theta2=np.degrees(d_theta1),
|
|
308
|
+
fc=color, ec=color, linewidth=3)
|
|
309
|
+
plt.gca().annotate(r"$d \theta $", xytext=(g_d[0] * .8, 1 / d / 3), xy=(g_d[0], 1 / d))
|
|
310
|
+
|
|
311
|
+
plt.gca().add_patch(deviation_angle)
|
|
312
|
+
plt.gca().set_aspect('equal')
|
|
313
|
+
plt.gca().set_ylim(-.5, 2.2)
|
|
314
|
+
plt.gca().set_xlim(-1.1, 1.6)
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def deficient_kikuchi_line(s_g=0., color_b='black'):
|
|
318
|
+
"""Draw the deficient Kikuchi line in the plot."""
|
|
319
|
+
k_len = 1 / ks.get_wavelength(20)
|
|
320
|
+
d = 2 # lattice parameter in nm
|
|
321
|
+
|
|
322
|
+
g = np.linspace(-2, 2, 5) * 1 / d
|
|
323
|
+
g_d = np.array([1 / d, 0])
|
|
324
|
+
|
|
325
|
+
# reciprocal lattice
|
|
326
|
+
plt.scatter(g, [0] * 5, color='blue')
|
|
327
|
+
|
|
328
|
+
alpha = -np.arctan(s_g / g_d[0])
|
|
329
|
+
theta = -np.arcsin(g_d[0] / 2 / k_len)
|
|
330
|
+
|
|
331
|
+
k_0 = np.array([-np.sin(theta - alpha) * k_len, np.cos(theta - alpha) * k_len])
|
|
332
|
+
k_d = np.array([-np.sin(-theta - alpha) * k_len, np.cos(-theta - alpha) * k_len])
|
|
333
|
+
k_i = np.array([-np.sin(theta - alpha) * 1., np.cos(theta - alpha) * 1.])
|
|
334
|
+
k_i_t = np.array([-np.sin(-alpha), np.cos(-alpha)])
|
|
335
|
+
|
|
336
|
+
kk_e = np.array([-np.sin(-theta) * k_len, np.cos(-theta) * k_len])
|
|
337
|
+
kk_d = np.array([-np.sin(theta) * k_len, np.cos(theta) * k_len])
|
|
338
|
+
|
|
339
|
+
# Ewald Sphere
|
|
340
|
+
ewald_sphere = patches.Circle((k_0[0], k_0[1]), radius=np.linalg.norm(k_0), clip_on=False, zorder=10, linewidth=1,
|
|
341
|
+
edgecolor=color_b, fill=False)
|
|
342
|
+
plt.gca().add_artist(ewald_sphere)
|
|
343
|
+
|
|
344
|
+
# K_0
|
|
345
|
+
plt.plot([k_0[0], k_0[0]], [k_0[1], k_0[1] + .4], color='gray', linestyle='-', alpha=0.3)
|
|
346
|
+
|
|
347
|
+
plt.gca().arrow(k_0[0] + k_i[0], k_0[1] + k_i[1], -k_i[0], -k_i[1], head_width=0.01, head_length=0.015, fc=color_b,
|
|
348
|
+
ec=color_b, length_includes_head=True)
|
|
349
|
+
plt.plot([k_0[0] + k_i_t[0], k_0[0] - k_i_t[0]], [k_0[1] + k_i_t[1], k_0[1] - k_i_t[1]], color='black',
|
|
350
|
+
linestyle='--', alpha=0.5)
|
|
351
|
+
plt.scatter(k_0[0], k_0[1], color='black')
|
|
352
|
+
plt.gca().arrow(k_0[0], k_0[1], -k_0[0], -k_0[1], head_width=0.01, head_length=0.015, fc=color_b,
|
|
353
|
+
ec=color_b, length_includes_head=True)
|
|
354
|
+
plt.gca().annotate("K$_0$", xytext=(-k_0[0] / 2, 0), xy=(k_0[0] / 2, 0))
|
|
355
|
+
|
|
356
|
+
plt.gca().arrow(k_0[0], k_0[1], -k_d[0], -k_d[1], head_width=0.01, head_length=0.015, fc=color_b,
|
|
357
|
+
ec=color_b, length_includes_head=True)
|
|
358
|
+
# K_e excess line
|
|
359
|
+
plt.gca().arrow(k_0[0], k_0[1], -kk_e[0], -kk_e[1], head_width=0.01, head_length=0.015, fc='red',
|
|
360
|
+
ec='red', length_includes_head=True)
|
|
361
|
+
plt.gca().annotate("excess", xytext=(k_0[0] - kk_e[0], -1), xy=(-kk_e[0] + k_0[0], 0))
|
|
362
|
+
plt.plot([k_0[0] - kk_e[0], k_0[0] - kk_e[0]], [-.1, .1], color='red')
|
|
363
|
+
|
|
364
|
+
# k_d deficient line
|
|
365
|
+
plt.gca().arrow(k_0[0], k_0[1], -kk_d[0], -kk_d[1], head_width=0.01, head_length=0.015, fc='blue',
|
|
366
|
+
ec='blue', length_includes_head=True)
|
|
367
|
+
plt.plot([k_0[0] - kk_d[0], k_0[0] - kk_d[0]], [-.1, .1], color='blue')
|
|
368
|
+
plt.gca().annotate("deficient", xytext=(k_0[0] - kk_d[0], -1), xy=(k_0[0] - kk_d[0], 0))
|
|
369
|
+
|
|
370
|
+
# s_g excitation Error of HOLZ reflection
|
|
371
|
+
plt.gca().arrow(g_d[0], g_d[1], 0, s_g, head_width=0.01, head_length=0.015, fc='k',
|
|
372
|
+
ec='k', length_includes_head=True)
|
|
373
|
+
plt.gca().annotate("s$_g$", xytext=(g_d[0] * 1.01, g_d[1] + s_g / 3), xy=(g_d[0] * 1.01, g_d[1] + s_g / 3))
|
|
374
|
+
|
|
375
|
+
theta = np.degrees(theta)
|
|
376
|
+
alpha = np.degrees(alpha)
|
|
377
|
+
|
|
378
|
+
bragg_angle = patches.Arc((k_0[0], k_0[1]), width=.55, height=.55,
|
|
379
|
+
theta1=90 + theta - alpha, theta2=90 - alpha, fc='black', ec='black')
|
|
380
|
+
if alpha > 0:
|
|
381
|
+
deviation_angle = patches.Arc((k_0[0], k_0[1]), width=.6, height=.6,
|
|
382
|
+
theta1=90 - alpha, theta2=90, fc='black', ec='red')
|
|
383
|
+
else:
|
|
384
|
+
deviation_angle = patches.Arc((k_0[0], k_0[1]), width=.6, height=.6,
|
|
385
|
+
theta1=90, theta2=90 - alpha, fc='black', ec='red')
|
|
386
|
+
|
|
387
|
+
plt.gca().annotate(r"$\theta$", xytext=(k_0[0] + k_i_t[0] / 20, k_0[1] + .2), xy=(k_0[0] + k_i_t[0], k_0[1] + .2))
|
|
388
|
+
plt.gca().annotate(r"$\alpha$", xytext=(k_0[0] + k_i_t[0] / 10, k_0[1] + .3), xy=(k_0[0] + k_i_t[0], k_0[1] + .3),
|
|
389
|
+
color='red')
|
|
390
|
+
plt.gca().add_patch(bragg_angle)
|
|
391
|
+
plt.gca().add_patch(deviation_angle)
|
|
392
|
+
|
|
393
|
+
plt.gca().set_aspect('equal')
|
|
394
|
+
plt.gca().set_xlabel(r'angle (1/$\AA$)')
|
|
395
|
+
plt.gca().set_ylim(-.1, k_0[1] * 2.2)
|
|
396
|
+
plt.gca().set_xlim(-.2, 1.03)
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
class InteractiveAberration():
|
|
400
|
+
"""
|
|
401
|
+
### Interactive explanation of aberrations
|
|
402
|
+
|
|
403
|
+
"""
|
|
404
|
+
|
|
405
|
+
def __init__(self, horizontal=True):
|
|
406
|
+
|
|
407
|
+
box_layout = widgets.Layout(display='flex',
|
|
408
|
+
flex_flow='row',
|
|
409
|
+
align_items='stretch',
|
|
410
|
+
width='100%')
|
|
411
|
+
|
|
412
|
+
self.words = ['ideal rays', 'aberrated rays', 'aberrated wavefront', 'aberration function']
|
|
413
|
+
|
|
414
|
+
self.buttons = [widgets.ToggleButton(value=False, description=word, disabled=False) for word in self.words]
|
|
415
|
+
box = widgets.Box(children=self.buttons, layout=box_layout)
|
|
416
|
+
display(box)
|
|
417
|
+
|
|
418
|
+
# Button(description='edge_quantification')
|
|
419
|
+
for button in self.buttons:
|
|
420
|
+
button.observe(self.on_button_clicked, 'value') # on_click(self.on_button_clicked)
|
|
421
|
+
|
|
422
|
+
self.figure = plt.figure()
|
|
423
|
+
self.ax = plt.gca()
|
|
424
|
+
self.horizontal = horizontal
|
|
425
|
+
self.ax.set_aspect('equal')
|
|
426
|
+
self.analysis = []
|
|
427
|
+
self.update()
|
|
428
|
+
# self.cid = self.figure.canvas.mpl_connect('button_press_event', self.onclick)
|
|
429
|
+
|
|
430
|
+
def on_button_clicked(self, b):
|
|
431
|
+
"""Handle button click events to update the analysis options"""
|
|
432
|
+
# print(b['owner'].description)
|
|
433
|
+
selection = b['owner'].description
|
|
434
|
+
if selection in self.analysis:
|
|
435
|
+
self.analysis.remove(selection)
|
|
436
|
+
else:
|
|
437
|
+
self.analysis.append(selection)
|
|
438
|
+
self.update()
|
|
439
|
+
|
|
440
|
+
def update(self):
|
|
441
|
+
"""Update the plot based on the selected analysis options"""
|
|
442
|
+
ax = self.ax
|
|
443
|
+
ax.clear()
|
|
444
|
+
selection = self.analysis
|
|
445
|
+
ax.plot([0, 15], [0, 0], color='black')
|
|
446
|
+
ax.plot([9, 9], [-.3, .3], color='black')
|
|
447
|
+
lens = patches.Ellipse((2, 0),
|
|
448
|
+
width=.4,
|
|
449
|
+
height=7,
|
|
450
|
+
facecolor='gray')
|
|
451
|
+
ax.add_patch(lens)
|
|
452
|
+
ax.set_ylim(-6.5, 6.5)
|
|
453
|
+
ax.set_aspect('equal')
|
|
454
|
+
|
|
455
|
+
if self.words[0] in selection:
|
|
456
|
+
color = 'gray'
|
|
457
|
+
ax.plot([0, 2], [1, 1], color=color)
|
|
458
|
+
ax.plot([0, 2], [-1, -1], color=color)
|
|
459
|
+
ax.plot([2, 9], [1, 0], color=color)
|
|
460
|
+
ax.plot([2, 9], [-1, 0], color=color)
|
|
461
|
+
|
|
462
|
+
gauss = patches.Ellipse((9, 0),
|
|
463
|
+
width=12,
|
|
464
|
+
height=12,
|
|
465
|
+
fill=False)
|
|
466
|
+
ax.add_patch(gauss)
|
|
467
|
+
|
|
468
|
+
if self.words[1] in selection:
|
|
469
|
+
color = 'blue'
|
|
470
|
+
ax.plot([0, 2], [2, 2], color=color)
|
|
471
|
+
ax.plot([0, 2], [-2, -2], color=color)
|
|
472
|
+
ax.plot([2, 7], [2, 0], color=color)
|
|
473
|
+
ax.plot([2, 7], [-2, 0], color=color)
|
|
474
|
+
gauss2 = patches.Ellipse((7, 0),
|
|
475
|
+
width=8,
|
|
476
|
+
height=8,
|
|
477
|
+
fill=False,
|
|
478
|
+
color=color, linestyle='--')
|
|
479
|
+
plt.gca().add_patch(gauss2)
|
|
480
|
+
|
|
481
|
+
if self.words[2] in selection:
|
|
482
|
+
color = 'red'
|
|
483
|
+
ax.plot([0, 2], [2, 2], color=color)
|
|
484
|
+
ax.plot([0, 2], [-2, -2], color=color)
|
|
485
|
+
ax.plot([2, 7], [2, 0], color=color)
|
|
486
|
+
ax.plot([2, 7], [-2, 0], color=color)
|
|
487
|
+
ax.plot([0, 2], [1, 1], color=color)
|
|
488
|
+
ax.plot([0, 2], [-1, -1], color=color)
|
|
489
|
+
ax.plot([2, 9], [1, 0], color=color)
|
|
490
|
+
ax.plot([2, 9], [-1, 0], color=color)
|
|
491
|
+
gauss3 = patches.Ellipse((9, 0),
|
|
492
|
+
width=12,
|
|
493
|
+
height=9.7,
|
|
494
|
+
fill=False,
|
|
495
|
+
color=color)
|
|
496
|
+
plt.gca().add_patch(gauss3)
|
|
497
|
+
|
|
498
|
+
if self.words[3] in selection:
|
|
499
|
+
color = 'green'
|
|
500
|
+
x = np.arange(100) / 100 - 6
|
|
501
|
+
x2 = np.arange(100) / 100 * 1.5 - 6
|
|
502
|
+
b = 4.8
|
|
503
|
+
a = 6
|
|
504
|
+
y = np.sqrt(a ** 2 - x ** 2)
|
|
505
|
+
y2 = b / a * np.sqrt(a ** 2 - x2 ** 2)
|
|
506
|
+
|
|
507
|
+
x = np.append(x[::-1], x[1:])
|
|
508
|
+
y = np.append(y[::-1], -y[1:])
|
|
509
|
+
x2 = np.append(x2[::-1], x2[1:])
|
|
510
|
+
y2 = np.append(y2[::-1], -y2[1:])
|
|
511
|
+
|
|
512
|
+
dif = y2 - y
|
|
513
|
+
|
|
514
|
+
x = np.append(x[::-1], x2)
|
|
515
|
+
y = np.append(y[::-1], y2)
|
|
516
|
+
aberration = patches.Polygon(np.array([x + 9, y]).T,
|
|
517
|
+
fill=True,
|
|
518
|
+
color=color, alpha=.5)
|
|
519
|
+
|
|
520
|
+
aberration2 = patches.Polygon(np.array(
|
|
521
|
+
[np.append(np.abs(dif), [0, 0]) * 2 + 2.5, np.append(np.linspace(-3.3, 3.3, len(dif)), [3.3, -3.3])]).T,
|
|
522
|
+
fill=True,
|
|
523
|
+
color=color, alpha=.9)
|
|
524
|
+
|
|
525
|
+
plt.gca().add_patch(aberration)
|
|
526
|
+
plt.gca().add_patch(aberration2)
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
class InteractiveRonchigramMagnification():
|
|
530
|
+
"""
|
|
531
|
+
### Interactive explanation of magnification
|
|
532
|
+
|
|
533
|
+
"""
|
|
534
|
+
|
|
535
|
+
def __init__(self, horizontal=True):
|
|
536
|
+
|
|
537
|
+
box_layout = widgets.Layout(display='flex',
|
|
538
|
+
flex_flow='row',
|
|
539
|
+
align_items='stretch',
|
|
540
|
+
width='100%')
|
|
541
|
+
|
|
542
|
+
self.words = ['ideal rays', 'radial circle rays', 'axial circle rays', 'over-focused rays']
|
|
543
|
+
|
|
544
|
+
self.buttons = [widgets.ToggleButton(value=False, description=word, disabled=False) for word in self.words]
|
|
545
|
+
box = widgets.Box(children=self.buttons, layout=box_layout)
|
|
546
|
+
display(box)
|
|
547
|
+
|
|
548
|
+
# Button(description='edge_quantification')
|
|
549
|
+
for button in self.buttons:
|
|
550
|
+
button.observe(self.on_button_clicked, 'value') # on_click(self.on_button_clicked)
|
|
551
|
+
|
|
552
|
+
self.figure = plt.figure()
|
|
553
|
+
self.ax = plt.gca()
|
|
554
|
+
self.horizontal = horizontal
|
|
555
|
+
self.ax.set_aspect('equal')
|
|
556
|
+
self.analysis = []
|
|
557
|
+
self.update()
|
|
558
|
+
# self.cid = self.figure.canvas.mpl_connect('button_press_event', self.onclick)
|
|
559
|
+
|
|
560
|
+
def on_button_clicked(self, b):
|
|
561
|
+
"""Handle button click events"""
|
|
562
|
+
# print(b['owner'].description)
|
|
563
|
+
selection = b['owner'].description
|
|
564
|
+
if selection in self.analysis:
|
|
565
|
+
self.analysis.remove(selection)
|
|
566
|
+
else:
|
|
567
|
+
self.analysis.append(selection)
|
|
568
|
+
self.update()
|
|
569
|
+
|
|
570
|
+
def update(self):
|
|
571
|
+
"""Update the plot based on the selected analysis options"""
|
|
572
|
+
ax = self.ax
|
|
573
|
+
ax.clear()
|
|
574
|
+
selection = self.analysis
|
|
575
|
+
ax.plot([0, 24], [0, 0], color='black')
|
|
576
|
+
ax.plot([14, 14], [-.3, .3], color='black')
|
|
577
|
+
ax.text(14, 1, s='f')
|
|
578
|
+
lens = patches.Ellipse((4, 0),
|
|
579
|
+
width=.8,
|
|
580
|
+
height=14,
|
|
581
|
+
facecolor='gray')
|
|
582
|
+
ax.add_patch(lens)
|
|
583
|
+
ax.text(4, 8, s='lens')
|
|
584
|
+
sample = patches.Rectangle((10, -2),
|
|
585
|
+
width=.2,
|
|
586
|
+
height=4,
|
|
587
|
+
facecolor='gray')
|
|
588
|
+
|
|
589
|
+
ax.add_patch(sample)
|
|
590
|
+
ax.text(9, 3, s='sample')
|
|
591
|
+
ax.set_ylim(-10, 10)
|
|
592
|
+
ax.set_aspect('equal')
|
|
593
|
+
|
|
594
|
+
if self.words[0] in selection:
|
|
595
|
+
color = 'gray'
|
|
596
|
+
ax.plot([0, 4], [1, 1], color=color)
|
|
597
|
+
ax.plot([0, 4], [-1, -1], color=color)
|
|
598
|
+
ax.plot([4, 24], [1, -1], color=color)
|
|
599
|
+
ax.plot([4, 24], [-1, 1], color=color)
|
|
600
|
+
|
|
601
|
+
circle1 = patches.Ellipse((24, 0), width=.2, height=2, fill=False, color=color)
|
|
602
|
+
ax.add_patch(circle1)
|
|
603
|
+
|
|
604
|
+
if self.words[1] in selection:
|
|
605
|
+
color = 'red'
|
|
606
|
+
ax.plot([0, 4], [3, 3], color=color)
|
|
607
|
+
ax.plot([0, 4], [-3, -3], color=color)
|
|
608
|
+
ax.plot([4, 24], [3, -4], color=color)
|
|
609
|
+
ax.plot([4, 24], [-3, 4], color=color)
|
|
610
|
+
ax.plot([0, 4], [2.5, 2.5], color=color)
|
|
611
|
+
ax.plot([0, 4], [-2.50, -2.5], color=color)
|
|
612
|
+
ax.plot([4, 24], [2.5, -2.8], color=color)
|
|
613
|
+
ax.plot([4, 24], [-2.5, 2.8], color=color)
|
|
614
|
+
|
|
615
|
+
circle2 = patches.Ellipse((24, 0), width=.9, height=8, fill=False, color=color)
|
|
616
|
+
ax.add_patch(circle2)
|
|
617
|
+
circle3 = patches.Ellipse((24, 0), width=.6, height=5.6, fill=False, color=color)
|
|
618
|
+
ax.add_patch(circle3)
|
|
619
|
+
circle3 = patches.Ellipse((24, 0), width=.7, height=7.3, fill=False, color=color, linewidth=5, alpha=.5)
|
|
620
|
+
ax.add_patch(circle3)
|
|
621
|
+
|
|
622
|
+
if self.words[2] in selection:
|
|
623
|
+
color = 'orange'
|
|
624
|
+
ax.plot([0, 4], [4, 4], color=color)
|
|
625
|
+
ax.plot([0, 4], [-4, -4], color=color)
|
|
626
|
+
ax.plot([4, 24], [4, -9.25], color=color)
|
|
627
|
+
ax.plot([4, 24], [-4, 9.25], color=color)
|
|
628
|
+
|
|
629
|
+
circle4 = patches.Ellipse((24, 0), width=2, height=18.5, fill=False, color=color)
|
|
630
|
+
plt.gca().add_patch(circle4)
|
|
631
|
+
|
|
632
|
+
if self.words[3] in selection:
|
|
633
|
+
color = 'green'
|
|
634
|
+
ax.plot([0, 4], [5, 5], color=color, linestyle='--')
|
|
635
|
+
ax.plot([0, 4], [-5, -5], color=color, linestyle='--')
|
|
636
|
+
ax.plot([4, 24], [5, -13], color=color, linestyle='--')
|
|
637
|
+
ax.plot([4, 24], [-5, 13], color=color, linestyle='--')
|
|
638
|
+
|
|
639
|
+
circle6 = patches.Ellipse((24, 0), width=4, height=26, fill=False, color=color, linestyle='--')
|
|
640
|
+
plt.gca().add_patch(circle6)
|