pyTEMlib 0.2025.4.2__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 -928
- 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.2.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.2.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.2.dist-info/RECORD +0 -38
- pytemlib-0.2025.4.2.dist-info/top_level.txt +0 -1
- {pytemlib-0.2025.4.2.dist-info → pytemlib-0.2025.9.1.dist-info}/entry_points.txt +0 -0
- {pytemlib-0.2025.4.2.dist-info → pytemlib-0.2025.9.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,599 @@
|
|
|
1
|
+
"""
|
|
2
|
+
##################################################################
|
|
3
|
+
# plotting functions for graph_tools
|
|
4
|
+
##################################################################
|
|
5
|
+
|
|
6
|
+
part of pyTEMlib
|
|
7
|
+
a pycrosccopy package
|
|
8
|
+
|
|
9
|
+
Author: Gerd Duscher
|
|
10
|
+
First Version: 2022-01-08
|
|
11
|
+
"""
|
|
12
|
+
import numpy as np
|
|
13
|
+
import ase
|
|
14
|
+
|
|
15
|
+
import plotly.graph_objects as go
|
|
16
|
+
import plotly.express as px
|
|
17
|
+
|
|
18
|
+
import pyTEMlib.crystal_tools
|
|
19
|
+
import pyTEMlib.graph_tools
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def get_plot_bonds(atoms):
|
|
23
|
+
"""Get plotly data for bonds."""
|
|
24
|
+
connectivity_matrix = atoms.info['bonds']['connectivity_matrix']
|
|
25
|
+
data = []
|
|
26
|
+
for row in range(1, connectivity_matrix.shape[0]):
|
|
27
|
+
for column in range(row):
|
|
28
|
+
if connectivity_matrix[column, row]:
|
|
29
|
+
lines = dict(type='scatter3d',
|
|
30
|
+
x=atoms.positions[[column, row],0],
|
|
31
|
+
y=atoms.positions[[column, row],1],
|
|
32
|
+
z=atoms.positions[[column, row],2],
|
|
33
|
+
mode='lines',
|
|
34
|
+
name='',
|
|
35
|
+
line=dict(color='rgb(70,70,70)', width=1.5))
|
|
36
|
+
data.append(lines)
|
|
37
|
+
return data
|
|
38
|
+
|
|
39
|
+
def plot_atoms(atoms: ase.Atoms, polyhedra_indices=None, plot_bonds=False, color='', template=None, atom_size=None, max_size=35) -> go.Figure:
|
|
40
|
+
"""
|
|
41
|
+
Plot structure in a ase.Atoms object with plotly
|
|
42
|
+
|
|
43
|
+
If the info dictionary of the atoms object contains bond or polyedra information, these can be set tobe plotted
|
|
44
|
+
|
|
45
|
+
Partameter:
|
|
46
|
+
-----------
|
|
47
|
+
atoms: ase.Atoms object
|
|
48
|
+
structure of supercell
|
|
49
|
+
polyhedra_indices: list of integers
|
|
50
|
+
indices of polyhedra to be plotted
|
|
51
|
+
plot_bonds: boolean
|
|
52
|
+
whether to plot bonds or not
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
--------
|
|
56
|
+
fig: plotly figure object
|
|
57
|
+
handle to figure needed to modify appearance
|
|
58
|
+
"""
|
|
59
|
+
energies = np.zeros(len(atoms))
|
|
60
|
+
if 'bonds' in atoms.info:
|
|
61
|
+
if 'atom_energy' in atoms.info['bonds']:
|
|
62
|
+
energies = np.round(np.array(atoms.info['bonds']['atom_energy'] - 12 * atoms.info['bonds']['ideal_bond_energy']) *1000,0)
|
|
63
|
+
|
|
64
|
+
for atom in atoms:
|
|
65
|
+
if atom.index not in atoms.info['bonds']['super_cell_atoms']:
|
|
66
|
+
energies[atom.index] = 0.
|
|
67
|
+
if color == 'coordination':
|
|
68
|
+
colors = atoms.info['bonds']['coordination']
|
|
69
|
+
elif color == 'layer':
|
|
70
|
+
colors = atoms.positions[:, 2]
|
|
71
|
+
elif color == 'energy':
|
|
72
|
+
colors = energies
|
|
73
|
+
colors[colors>50] = 50
|
|
74
|
+
colors = np.log(1+ energies)
|
|
75
|
+
|
|
76
|
+
else:
|
|
77
|
+
colors = atoms.get_atomic_numbers()
|
|
78
|
+
|
|
79
|
+
if atom_size is None:
|
|
80
|
+
atom_size = atoms.get_atomic_numbers()*4
|
|
81
|
+
elif isinstance(atom_size, float):
|
|
82
|
+
atom_size = atoms.get_atomic_numbers()*4*atom_size
|
|
83
|
+
atom_size[atom_size>max_size] = max_size
|
|
84
|
+
elif isinstance(atom_size, int):
|
|
85
|
+
atom_size = [atom_size]*len(atoms)
|
|
86
|
+
if len(atom_size) != len(atoms):
|
|
87
|
+
atom_size = [10]*len(atoms)
|
|
88
|
+
print('wrong length of atom_size parameter')
|
|
89
|
+
plot_polyhedra = False
|
|
90
|
+
data = []
|
|
91
|
+
if polyhedra_indices is not None:
|
|
92
|
+
if 'polyhedra' in atoms.info:
|
|
93
|
+
if polyhedra_indices == -1:
|
|
94
|
+
data = plot_polyhedron(atoms.info['polyhedra']['polyhedra'], range(len(atoms.info['polyhedra']['polyhedra'])))
|
|
95
|
+
plot_polyhedra = True
|
|
96
|
+
elif isinstance(polyhedra_indices, list):
|
|
97
|
+
data = plot_polyhedron(atoms.info['polyhedra']['polyhedra'], polyhedra_indices)
|
|
98
|
+
plot_polyhedra = True
|
|
99
|
+
text = []
|
|
100
|
+
if 'bonds' in atoms.info:
|
|
101
|
+
coord = atoms.info['bonds']['coordination']
|
|
102
|
+
for atom in atoms:
|
|
103
|
+
if atom.index in atoms.info['bonds']['super_cell_atoms']:
|
|
104
|
+
|
|
105
|
+
text.append(f'Atom {atom.index}: coordination={coord[atom.index]}' +
|
|
106
|
+
f'x:{atom.position[0]:.2f} \n y:{atom.position[1]:.2f} \n z:{atom.position[2]:.2f}')
|
|
107
|
+
if 'atom_energy' in atoms.info['bonds']:
|
|
108
|
+
text[-1] += f"\n energy: {energies[atom.index]:.0f} meV"
|
|
109
|
+
else:
|
|
110
|
+
text.append('')
|
|
111
|
+
else:
|
|
112
|
+
text = [''] * len(atoms)
|
|
113
|
+
|
|
114
|
+
if plot_bonds:
|
|
115
|
+
data += get_plot_bonds(atoms)
|
|
116
|
+
if plot_polyhedra or plot_bonds:
|
|
117
|
+
fig = go.Figure(data=data)
|
|
118
|
+
else:
|
|
119
|
+
fig = go.Figure()
|
|
120
|
+
if color=='energy':
|
|
121
|
+
fig.add_trace(go.Scatter3d(
|
|
122
|
+
mode='markers',
|
|
123
|
+
x=atoms.positions[:,0], y=atoms.positions[:,1], z=atoms.positions[:,2],
|
|
124
|
+
hovertemplate='<b>%{text}</b><extra></extra>',
|
|
125
|
+
text = text,
|
|
126
|
+
marker=dict(
|
|
127
|
+
color=colors,
|
|
128
|
+
size=atom_size,
|
|
129
|
+
sizemode='diameter',
|
|
130
|
+
colorscale='Rainbow', #px.colors.qualitative.Light24,
|
|
131
|
+
colorbar=dict(thickness=10, orientation='h'))))
|
|
132
|
+
#hover_name = colors))) # ["blue", "green", "red"])))
|
|
133
|
+
|
|
134
|
+
elif 'bonds' in atoms.info:
|
|
135
|
+
fig.add_trace(go.Scatter3d(
|
|
136
|
+
mode='markers',
|
|
137
|
+
x=atoms.positions[:,0], y=atoms.positions[:,1], z=atoms.positions[:,2],
|
|
138
|
+
hovertemplate='<b>%{text}</b><extra></extra>',
|
|
139
|
+
text = text,
|
|
140
|
+
marker=dict(
|
|
141
|
+
color=colors,
|
|
142
|
+
size=atom_size,
|
|
143
|
+
sizemode='diameter',
|
|
144
|
+
colorscale= px.colors.qualitative.Light24)))
|
|
145
|
+
#hover_name = colors))) # ["blue", "green", "red"])))
|
|
146
|
+
|
|
147
|
+
else:
|
|
148
|
+
fig.add_trace(go.Scatter3d(
|
|
149
|
+
mode='markers',
|
|
150
|
+
x=atoms.positions[:,0], y=atoms.positions[:,1], z=atoms.positions[:,2],
|
|
151
|
+
marker=dict(
|
|
152
|
+
color=colors,
|
|
153
|
+
size=atom_size,
|
|
154
|
+
sizemode='diameter',
|
|
155
|
+
colorbar=dict(thickness=10),
|
|
156
|
+
colorscale= px.colors.qualitative.Light24)))
|
|
157
|
+
#hover_name = colors))) # ["blue", "green", "red"])))
|
|
158
|
+
fig.update_layout(width=1000, height=700, showlegend=False, template=template)
|
|
159
|
+
fig.update_layout(scene_aspectmode='data',
|
|
160
|
+
scene_aspectratio=dict(x=1, y=1, z=1))
|
|
161
|
+
|
|
162
|
+
camera = {'up': {'x': 0, 'y': 1, 'z': 0},
|
|
163
|
+
'center': {'x': 0, 'y': 0, 'z': 0},
|
|
164
|
+
'eye': {'x': 0, 'y': 0, 'z': 1}}
|
|
165
|
+
fig.update_coloraxes(showscale=True)
|
|
166
|
+
fig.update_layout(scene_camera=camera, title=r"Al-GB $")
|
|
167
|
+
fig.update_scenes(camera_projection_type="orthographic" )
|
|
168
|
+
fig.show()
|
|
169
|
+
return fig
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def plot_super_cell(super_cell, shift_x=0.):
|
|
173
|
+
""" make a super_cell to plot with extra atoms at periodic boundaries"""
|
|
174
|
+
|
|
175
|
+
if not isinstance(super_cell, ase.Atoms):
|
|
176
|
+
raise TypeError('Need an ase Atoms object')
|
|
177
|
+
|
|
178
|
+
plot_boundary = super_cell * (2, 2, 3)
|
|
179
|
+
plot_boundary.positions[:, 0] = plot_boundary.positions[:, 0] - super_cell.cell[0, 0] * shift_x
|
|
180
|
+
|
|
181
|
+
del plot_boundary[plot_boundary.positions[:, 2] > super_cell.cell[2, 2] * 1.5 + 0.1]
|
|
182
|
+
del plot_boundary[plot_boundary.positions[:, 1] > super_cell.cell[1, 1] + 0.1]
|
|
183
|
+
del plot_boundary[plot_boundary.positions[:, 0] > super_cell.cell[0, 0] + 0.1]
|
|
184
|
+
del plot_boundary[plot_boundary.positions[:, 0] < -0.1]
|
|
185
|
+
plot_boundary.cell = super_cell.cell * (1, 1, 1.5)
|
|
186
|
+
|
|
187
|
+
return plot_boundary
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def plot_polyhedron(polyhedra, indices, center=False):
|
|
191
|
+
"""
|
|
192
|
+
Information to plot polyhedra with plotly
|
|
193
|
+
|
|
194
|
+
Parameter
|
|
195
|
+
---------
|
|
196
|
+
polyhedra: dict
|
|
197
|
+
dictionary of all polyhedra
|
|
198
|
+
indices: list or integer
|
|
199
|
+
list or index of polyhedron to plot.
|
|
200
|
+
center: boolean
|
|
201
|
+
whether to center polyhedra on origin
|
|
202
|
+
|
|
203
|
+
Returns
|
|
204
|
+
-------
|
|
205
|
+
data: dict
|
|
206
|
+
instructions to plot for plotly
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
if isinstance(indices, int):
|
|
210
|
+
indices = [indices]
|
|
211
|
+
if len(indices) == 0:
|
|
212
|
+
print('Did not find any polyhedra')
|
|
213
|
+
return {}
|
|
214
|
+
|
|
215
|
+
center_point = np.mean(polyhedra[indices[0]]['vertices'], axis=0)
|
|
216
|
+
|
|
217
|
+
if center:
|
|
218
|
+
print(center_point)
|
|
219
|
+
center = center_point
|
|
220
|
+
else:
|
|
221
|
+
center = [0, 0, 0]
|
|
222
|
+
|
|
223
|
+
data = []
|
|
224
|
+
for index in indices:
|
|
225
|
+
polyhedron = polyhedra[index]
|
|
226
|
+
|
|
227
|
+
vertices = polyhedron['vertices'] - center
|
|
228
|
+
faces = np.array(polyhedron['triangles'])
|
|
229
|
+
x, y, z = vertices.T
|
|
230
|
+
i_i, j_j, k_k = faces.T
|
|
231
|
+
|
|
232
|
+
mesh = dict(type='mesh3d',
|
|
233
|
+
x=x,
|
|
234
|
+
y=y,
|
|
235
|
+
z=z,
|
|
236
|
+
i=i_i,
|
|
237
|
+
j=j_j,
|
|
238
|
+
k=k_k,
|
|
239
|
+
name='',
|
|
240
|
+
opacity=0.2,
|
|
241
|
+
color=px.colors.qualitative.Light24[len(vertices) % 24]
|
|
242
|
+
)
|
|
243
|
+
tri_vertices = vertices[faces]
|
|
244
|
+
x_e = []
|
|
245
|
+
y_e = []
|
|
246
|
+
z_e = []
|
|
247
|
+
for t_v in tri_vertices:
|
|
248
|
+
x_e += [t_v[k % 3][0] for k in range(4)] + [None]
|
|
249
|
+
y_e += [t_v[k % 3][1] for k in range(4)] + [None]
|
|
250
|
+
z_e += [t_v[k % 3][2] for k in range(4)] + [None]
|
|
251
|
+
|
|
252
|
+
# define the lines to be plotted
|
|
253
|
+
lines = dict(type='scatter3d',
|
|
254
|
+
x=x_e,
|
|
255
|
+
y=y_e,
|
|
256
|
+
z=z_e,
|
|
257
|
+
mode='lines',
|
|
258
|
+
name='',
|
|
259
|
+
line=dict(color='rgb(70,70,70)', width=1.5))
|
|
260
|
+
data.append(mesh)
|
|
261
|
+
data.append(lines)
|
|
262
|
+
return data
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def plot_bonds(polyhedra):
|
|
266
|
+
"""
|
|
267
|
+
Information to plot bonds with plotly
|
|
268
|
+
|
|
269
|
+
Parameter
|
|
270
|
+
---------
|
|
271
|
+
polyhedra: dict
|
|
272
|
+
dictionary of all polyhedra
|
|
273
|
+
|
|
274
|
+
Returns
|
|
275
|
+
-------
|
|
276
|
+
data: dict
|
|
277
|
+
instructions to plot for plotly
|
|
278
|
+
"""
|
|
279
|
+
indices = range(len(polyhedra))
|
|
280
|
+
|
|
281
|
+
data = []
|
|
282
|
+
for index in indices:
|
|
283
|
+
polyhedron = polyhedra[index]
|
|
284
|
+
|
|
285
|
+
vertices = polyhedron['vertices']
|
|
286
|
+
faces = np.array(polyhedron['triangles'])
|
|
287
|
+
x, y, z = vertices.T
|
|
288
|
+
i_i, j_j, k_k = faces.T
|
|
289
|
+
|
|
290
|
+
tri_vertices = vertices[faces]
|
|
291
|
+
x_e = []
|
|
292
|
+
y_e = []
|
|
293
|
+
z_e = []
|
|
294
|
+
for t_v in tri_vertices:
|
|
295
|
+
x_e += [t_v[k % 3][0] for k in range(4)] + [None]
|
|
296
|
+
y_e += [t_v[k % 3][1] for k in range(4)] + [None]
|
|
297
|
+
z_e += [t_v[k % 3][2] for k in range(4)] + [None]
|
|
298
|
+
|
|
299
|
+
# define the lines to be plotted
|
|
300
|
+
lines = dict(type='scatter3d',
|
|
301
|
+
x=x_e,
|
|
302
|
+
y=y_e,
|
|
303
|
+
z=z_e,
|
|
304
|
+
mode='lines',
|
|
305
|
+
name='',
|
|
306
|
+
line=dict(color='rgb(70,70,70)', width=1.5))
|
|
307
|
+
data.append(lines)
|
|
308
|
+
return data
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def get_boundary_polyhedra(polyhedra, boundary_x=0, boundary_width=0.5, verbose=True, z_lim=[0, 100]):
|
|
312
|
+
"""
|
|
313
|
+
get indices of polyhedra at boundary (assumed to be parallel to x-axis)
|
|
314
|
+
|
|
315
|
+
Parameter
|
|
316
|
+
---------
|
|
317
|
+
polyhedra: dict
|
|
318
|
+
dictionary of all polyhedra
|
|
319
|
+
boundary_x: float
|
|
320
|
+
position of boundary in Angstrom
|
|
321
|
+
boundary_width: float
|
|
322
|
+
width of boundary where center of polyhedra are considered in Angstrom
|
|
323
|
+
verbose: boolean
|
|
324
|
+
optional
|
|
325
|
+
z_lim: list
|
|
326
|
+
upper and lower limit of polyhedra to plot
|
|
327
|
+
|
|
328
|
+
Returns
|
|
329
|
+
-------
|
|
330
|
+
boundary_polyhedra: list
|
|
331
|
+
list of polyhedra at boundary
|
|
332
|
+
"""
|
|
333
|
+
boundary_polyhedra = []
|
|
334
|
+
for key, polyhedron in polyhedra.items():
|
|
335
|
+
center = polyhedron['vertices'].mean(axis=0)
|
|
336
|
+
if abs(center[0] - boundary_x) < 0.5 and (z_lim[0] < center[2] < z_lim[1]):
|
|
337
|
+
boundary_polyhedra.append(key)
|
|
338
|
+
if verbose:
|
|
339
|
+
print(key, polyhedron['length'], center)
|
|
340
|
+
|
|
341
|
+
return boundary_polyhedra
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def plot_with_polyhedra(polyhedra, indices, atoms=None, title=''):
|
|
345
|
+
"""
|
|
346
|
+
plot atoms and polyhedra with plotly
|
|
347
|
+
|
|
348
|
+
Parameter
|
|
349
|
+
---------
|
|
350
|
+
polyhedra: dict
|
|
351
|
+
dictionary of all polyhedra
|
|
352
|
+
indices: list or integer
|
|
353
|
+
list or index of polyhedron to plot.
|
|
354
|
+
atoms: ase.Atoms
|
|
355
|
+
optional structure info to plot atoms (with correct color)
|
|
356
|
+
|
|
357
|
+
Returns
|
|
358
|
+
-------
|
|
359
|
+
fig: plotly.figure
|
|
360
|
+
plotly figure instance
|
|
361
|
+
"""
|
|
362
|
+
|
|
363
|
+
data = plot_polyhedron(polyhedra, indices)
|
|
364
|
+
if not isinstance(atoms, ase.Atoms):
|
|
365
|
+
atoms = None
|
|
366
|
+
|
|
367
|
+
data[0]['opacity'] = 0.05
|
|
368
|
+
fig = go.Figure(data=data)
|
|
369
|
+
if atoms is not None:
|
|
370
|
+
fig.add_trace(go.Scatter3d(
|
|
371
|
+
mode='markers',
|
|
372
|
+
x=atoms.positions[:, 0], y=atoms.positions[:, 1], z=atoms.positions[:, 2],
|
|
373
|
+
marker=dict(
|
|
374
|
+
color=atoms.get_atomic_numbers(),
|
|
375
|
+
size=5,
|
|
376
|
+
sizemode='diameter',
|
|
377
|
+
colorscale=["blue", "green", "red"])))
|
|
378
|
+
|
|
379
|
+
fig.update_layout(width=1000, height=700, showlegend=False)
|
|
380
|
+
fig.update_layout(scene_aspectmode='data',
|
|
381
|
+
scene_aspectratio=dict(x=1, y=1, z=1))
|
|
382
|
+
|
|
383
|
+
camera = {'up': {'x': 1, 'y': 0, 'z': 0},
|
|
384
|
+
'center': {'x': 0, 'y': 0, 'z': 0},
|
|
385
|
+
'eye': {'x': 0, 'y': 0, 'z': 1}}
|
|
386
|
+
|
|
387
|
+
fig.update_layout(scene_camera=camera, title=title)
|
|
388
|
+
fig.update_scenes(camera_projection_type="orthographic")
|
|
389
|
+
return fig
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
def plot_supercell(supercell, size=(1, 1, 1), shift_x=0.25, title=''):
|
|
393
|
+
"""
|
|
394
|
+
plot supercell with plotly
|
|
395
|
+
|
|
396
|
+
Parameter
|
|
397
|
+
---------
|
|
398
|
+
supercell: ase.Atoms
|
|
399
|
+
optional structure info to plot atoms (with correct color)
|
|
400
|
+
shift_x: float
|
|
401
|
+
amount of shift in x direction of supercell
|
|
402
|
+
title: str
|
|
403
|
+
title of plot
|
|
404
|
+
|
|
405
|
+
Returns
|
|
406
|
+
-------
|
|
407
|
+
fig: plotly.figure
|
|
408
|
+
plotly figure instance
|
|
409
|
+
"""
|
|
410
|
+
|
|
411
|
+
plot_cell = pyTEMlib.graph_tools.plot_super_cell(supercell * size, shift_x=shift_x)
|
|
412
|
+
|
|
413
|
+
# grain_boundary.cell.volume
|
|
414
|
+
supercell_area = supercell.cell.lengths()[1] / supercell.cell.lengths()[2]
|
|
415
|
+
print(supercell.symbols)
|
|
416
|
+
volume__bulk_atom = 16.465237835776012
|
|
417
|
+
ideal_volume = len(supercell.positions) * volume__bulk_atom
|
|
418
|
+
print(len(supercell.positions) * volume__bulk_atom, supercell.cell.volume)
|
|
419
|
+
x_0 = ideal_volume / supercell.cell.lengths()[1] / supercell.cell.lengths()[2]
|
|
420
|
+
print(f'Zero volume expansion supercell length: {x_0 / 10:.2f} nm; '
|
|
421
|
+
f' compared to actual {supercell.cell.lengths()[0] / 10:.2f} nm')
|
|
422
|
+
|
|
423
|
+
fig = go.Figure(data=[
|
|
424
|
+
go.Scatter3d(x=plot_cell.positions[:, 0], y=plot_cell.positions[:, 1], z=plot_cell.positions[:, 2],
|
|
425
|
+
mode='markers',
|
|
426
|
+
marker=dict(
|
|
427
|
+
color=plot_cell.get_atomic_numbers(),
|
|
428
|
+
size=5,
|
|
429
|
+
sizemode='diameter',
|
|
430
|
+
colorscale=["blue", "green", "red"]))])
|
|
431
|
+
|
|
432
|
+
fig.update_layout(width=700, margin=dict(r=10, l=10, b=10, t=10))
|
|
433
|
+
fig.update_layout(scene_aspectmode='data',
|
|
434
|
+
scene_aspectratio=dict(x=1, y=1, z=1))
|
|
435
|
+
|
|
436
|
+
camera = dict(
|
|
437
|
+
up=dict(x=0, y=1, z=0),
|
|
438
|
+
center=dict(x=0, y=0, z=0),
|
|
439
|
+
eye=dict(x=0, y=0, z=1)
|
|
440
|
+
)
|
|
441
|
+
fig.update_layout(scene_camera=camera, title=title)
|
|
442
|
+
fig.update_scenes(camera_projection_type="orthographic")
|
|
443
|
+
return fig
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
def plot_supercell_bonds(polyhedra, atoms, volumes=None, atom_size=15, title=''):
|
|
447
|
+
"""
|
|
448
|
+
plot atoms and bonds with plotly
|
|
449
|
+
|
|
450
|
+
Parameter
|
|
451
|
+
---------
|
|
452
|
+
polyhedra: dict
|
|
453
|
+
dictionary of all polyhedra
|
|
454
|
+
atoms: ase.Atoms
|
|
455
|
+
optional structure info to plot atoms (with correct color)
|
|
456
|
+
volumes: list
|
|
457
|
+
list of volumes, optional structure
|
|
458
|
+
atoms_size: float
|
|
459
|
+
sie of atoms to plot
|
|
460
|
+
title: str
|
|
461
|
+
title of plot
|
|
462
|
+
|
|
463
|
+
Returns
|
|
464
|
+
-------
|
|
465
|
+
fig: plotly.figure
|
|
466
|
+
plotly figure instance
|
|
467
|
+
"""
|
|
468
|
+
|
|
469
|
+
data = plot_bonds(polyhedra)
|
|
470
|
+
if volumes is None:
|
|
471
|
+
volumes = [atom_size] * len(atoms.get_atomic_numbers())
|
|
472
|
+
|
|
473
|
+
fig = go.Figure(data=data)
|
|
474
|
+
fig.add_trace(go.Scatter3d(
|
|
475
|
+
mode='markers',
|
|
476
|
+
x=atoms.positions[:, 0], y=atoms.positions[:, 1], z=atoms.positions[:, 2],
|
|
477
|
+
marker=dict(
|
|
478
|
+
color=atoms.get_atomic_numbers(),
|
|
479
|
+
size=np.asarray(volumes) ** 2 / 10,
|
|
480
|
+
sizemode='diameter',
|
|
481
|
+
colorscale=["blue", "green", "red"])))
|
|
482
|
+
|
|
483
|
+
fig.update_layout(width=1000, height=700, showlegend=False)
|
|
484
|
+
fig.update_layout(scene_aspectmode='data',
|
|
485
|
+
scene_aspectratio=dict(x=1, y=1, z=1))
|
|
486
|
+
|
|
487
|
+
camera = {'up': {'x': 0, 'y': 1, 'z': 0},
|
|
488
|
+
'center': {'x': 0, 'y': 0, 'z': 0},
|
|
489
|
+
'eye': {'x': 0, 'y': 0, 'z': 1}}
|
|
490
|
+
fig.update_layout(scene_camera=camera, title=title)
|
|
491
|
+
fig.update_scenes(camera_projection_type="orthographic")
|
|
492
|
+
return fig
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
def plot_supercell_polyhedra(polyhedra, indices, atoms, volumes=None, title=''):
|
|
496
|
+
"""
|
|
497
|
+
plot atoms and polyhedra with plotly
|
|
498
|
+
|
|
499
|
+
Parameter
|
|
500
|
+
---------
|
|
501
|
+
polyhedra: dict
|
|
502
|
+
dictionary of all polyhedra
|
|
503
|
+
indices: list
|
|
504
|
+
list of indices of polyhedra to plot
|
|
505
|
+
atoms: ase.Atoms
|
|
506
|
+
optional structure info to plot atoms (with correct color)
|
|
507
|
+
volumes: list
|
|
508
|
+
list of volumes, optional structure
|
|
509
|
+
title: str
|
|
510
|
+
title of plot
|
|
511
|
+
|
|
512
|
+
Returns
|
|
513
|
+
-------
|
|
514
|
+
fig: plotly.figure
|
|
515
|
+
plotly figure instance
|
|
516
|
+
"""
|
|
517
|
+
data = plot_polyhedron(polyhedra, indices)
|
|
518
|
+
if volumes is None:
|
|
519
|
+
volumes = [10] * len(atoms.get_atomic_numbers())
|
|
520
|
+
|
|
521
|
+
fig = go.Figure(data=data)
|
|
522
|
+
fig.add_trace(go.Scatter3d(
|
|
523
|
+
mode='markers',
|
|
524
|
+
x=atoms.positions[:, 0], y=atoms.positions[:, 1], z=atoms.positions[:, 2],
|
|
525
|
+
marker=dict(
|
|
526
|
+
color=atoms.get_atomic_numbers(),
|
|
527
|
+
size=np.asarray(volumes)**2 / 10,
|
|
528
|
+
sizemode='diameter',
|
|
529
|
+
colorscale=["blue", "green", "red"])))
|
|
530
|
+
|
|
531
|
+
fig.update_layout(width=1000, height=700, showlegend=False)
|
|
532
|
+
fig.update_layout(scene_aspectmode='data',
|
|
533
|
+
scene_aspectratio=dict(x=1, y=1, z=1))
|
|
534
|
+
|
|
535
|
+
camera = {'up': {'x': 0, 'y': 1, 'z': 0},
|
|
536
|
+
'center': {'x': 0, 'y': 0, 'z': 0},
|
|
537
|
+
'eye': {'x': 0, 'y': 0, 'z': 1}}
|
|
538
|
+
fig.update_layout(scene_camera=camera, title=title)
|
|
539
|
+
fig.update_scenes(camera_projection_type="orthographic")
|
|
540
|
+
return fig
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
def show_polyhedra(polyhedra, boundary_polyhedra, atoms, volumes=None, title=f''):
|
|
544
|
+
"""
|
|
545
|
+
plot polyhedra and atoms of vertices with plotly
|
|
546
|
+
|
|
547
|
+
Parameter
|
|
548
|
+
---------
|
|
549
|
+
polyhedra: dict
|
|
550
|
+
dictionary of all polyhedra
|
|
551
|
+
boundary_polyhedra: list
|
|
552
|
+
list of indices of polyhedra to plot
|
|
553
|
+
atoms: ase.Atoms
|
|
554
|
+
optional structure info to plot atoms (with correct color)
|
|
555
|
+
volumes: list
|
|
556
|
+
list of volumes, optional structure
|
|
557
|
+
title: str
|
|
558
|
+
title of plot
|
|
559
|
+
|
|
560
|
+
Returns
|
|
561
|
+
-------
|
|
562
|
+
fig: plotly.figure
|
|
563
|
+
plotly figure instance
|
|
564
|
+
"""
|
|
565
|
+
|
|
566
|
+
data = plot_polyhedron(polyhedra, boundary_polyhedra)
|
|
567
|
+
atom_indices = []
|
|
568
|
+
for poly in boundary_polyhedra:
|
|
569
|
+
atom_indices.extend(polyhedra[poly]['indices'])
|
|
570
|
+
atom_indices = list(set(atom_indices))
|
|
571
|
+
atomic_numbers = []
|
|
572
|
+
atomic_volumes = []
|
|
573
|
+
for atom in atom_indices:
|
|
574
|
+
atomic_numbers.append(atoms[atom].number)
|
|
575
|
+
atomic_volumes.append(volumes[atoms[atom].index] ** 2 / 10)
|
|
576
|
+
|
|
577
|
+
if volumes is None:
|
|
578
|
+
atomic_volumes = [10] * len(atoms.get_atomic_numbers())
|
|
579
|
+
fig = go.Figure(data=data)
|
|
580
|
+
|
|
581
|
+
fig.add_trace(go.Scatter3d(
|
|
582
|
+
mode='markers',
|
|
583
|
+
x=atoms.positions[atom_indices, 0], y=atoms.positions[atom_indices, 1], z=atoms.positions[atom_indices, 2],
|
|
584
|
+
marker=dict(
|
|
585
|
+
color=atomic_numbers,
|
|
586
|
+
size=atomic_volumes,
|
|
587
|
+
sizemode='diameter',
|
|
588
|
+
colorscale=["blue", "green", "red"])))
|
|
589
|
+
|
|
590
|
+
fig.update_layout(width=1000, height=700, showlegend=False)
|
|
591
|
+
fig.update_layout(scene_aspectmode='data',
|
|
592
|
+
scene_aspectratio=dict(x=1, y=1, z=1))
|
|
593
|
+
|
|
594
|
+
camera = {'up': {'x': 1, 'y': 0, 'z': 0},
|
|
595
|
+
'center': {'x': 0, 'y': 0, 'z': 0},
|
|
596
|
+
'eye': {'x': 0, 'y': 0, 'z': 1}}
|
|
597
|
+
fig.update_layout(scene_camera=camera, title=title)
|
|
598
|
+
fig.update_scenes(camera_projection_type="orthographic")
|
|
599
|
+
return fig
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Image Module
|
|
3
|
+
|
|
4
|
+
Should contain
|
|
5
|
+
- general feature extraction
|
|
6
|
+
- geometry feature extraction
|
|
7
|
+
- atom finding
|
|
8
|
+
- denoising
|
|
9
|
+
- windowing
|
|
10
|
+
- transforms (e.g., radon, hough)
|
|
11
|
+
|
|
12
|
+
Submodules
|
|
13
|
+
----------
|
|
14
|
+
.. autosummary::
|
|
15
|
+
:toctree: _autosummary
|
|
16
|
+
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from .image_window import ImageWindowing
|
|
20
|
+
from .image_utilities import crop_image, flatten_image, inpaint_image, warp, rebin
|
|
21
|
+
from .image_clean import decon_lr, clean_svd, background_correction
|
|
22
|
+
from .image_atoms import find_atoms, atom_refine, intensity_area, atoms_clustering
|
|
23
|
+
from .image_graph import find_polyhedra, breadth_first_search, breadth_first_search_flexible
|
|
24
|
+
from .image_graph import get_base_atoms
|
|
25
|
+
from .image_distortion import get_distortion_matrix, undistort, undistort_sitk
|
|
26
|
+
from .image_registration import complete_registration, rigid_registration, demon_registration
|
|
27
|
+
from .image_fft import power_spectrum, diffractogram_spots, adaptive_fourier_filter
|
|
28
|
+
from .image_fft import rotational_symmetry_diffractogram
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
__all__ = ['ImageWindowing', 'crop_image', 'decon_lr', 'clean_svd', 'background_correction',
|
|
32
|
+
'find_atoms', 'atom_refine', 'intensity_area', 'atoms_clustering',
|
|
33
|
+
'find_polyhedra', 'breadth_first_search', 'breadth_first_search_flexible', 'get_base_atoms',
|
|
34
|
+
'get_distortion_matrix', 'undistort', 'undistort_sitk',
|
|
35
|
+
'complete_registration', 'demon_registration', 'rigid_registration',
|
|
36
|
+
'flatten_image', 'inpaint_image', 'warp', 'rebin',
|
|
37
|
+
'power_spectrum', 'diffractogram_spots', 'adaptive_fourier_filter', 'rotational_symmetry_diffractogram']
|