pyTEMlib 0.2020.11.1__py3-none-any.whl → 0.2024.8.4__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.

Files changed (60) hide show
  1. pyTEMlib/__init__.py +11 -11
  2. pyTEMlib/animation.py +631 -0
  3. pyTEMlib/atom_tools.py +240 -245
  4. pyTEMlib/config_dir.py +57 -33
  5. pyTEMlib/core_loss_widget.py +658 -0
  6. pyTEMlib/crystal_tools.py +1255 -0
  7. pyTEMlib/diffraction_plot.py +756 -0
  8. pyTEMlib/dynamic_scattering.py +293 -0
  9. pyTEMlib/eds_tools.py +609 -0
  10. pyTEMlib/eels_dialog.py +749 -491
  11. pyTEMlib/{interactive_eels.py → eels_dialog_utilities.py} +1199 -1177
  12. pyTEMlib/eels_tools.py +2031 -1698
  13. pyTEMlib/file_tools.py +1276 -560
  14. pyTEMlib/file_tools_qt.py +193 -0
  15. pyTEMlib/graph_tools.py +1166 -450
  16. pyTEMlib/graph_viz.py +449 -0
  17. pyTEMlib/image_dialog.py +158 -0
  18. pyTEMlib/image_dlg.py +146 -232
  19. pyTEMlib/image_tools.py +1399 -1028
  20. pyTEMlib/info_widget.py +933 -0
  21. pyTEMlib/interactive_image.py +1 -226
  22. pyTEMlib/kinematic_scattering.py +1196 -0
  23. pyTEMlib/low_loss_widget.py +176 -0
  24. pyTEMlib/microscope.py +61 -81
  25. pyTEMlib/peak_dialog.py +1047 -410
  26. pyTEMlib/peak_dlg.py +286 -242
  27. pyTEMlib/probe_tools.py +653 -207
  28. pyTEMlib/sidpy_tools.py +153 -136
  29. pyTEMlib/simulation_tools.py +104 -87
  30. pyTEMlib/version.py +6 -3
  31. pyTEMlib/xrpa_x_sections.py +20972 -0
  32. {pyTEMlib-0.2020.11.1.dist-info → pyTEMlib-0.2024.8.4.dist-info}/LICENSE +21 -21
  33. pyTEMlib-0.2024.8.4.dist-info/METADATA +93 -0
  34. pyTEMlib-0.2024.8.4.dist-info/RECORD +37 -0
  35. {pyTEMlib-0.2020.11.1.dist-info → pyTEMlib-0.2024.8.4.dist-info}/WHEEL +6 -5
  36. {pyTEMlib-0.2020.11.1.dist-info → pyTEMlib-0.2024.8.4.dist-info}/entry_points.txt +0 -1
  37. pyTEMlib/KinsCat.py +0 -2758
  38. pyTEMlib/__version__.py +0 -2
  39. pyTEMlib/data/TEMlibrc +0 -68
  40. pyTEMlib/data/edges_db.csv +0 -189
  41. pyTEMlib/data/edges_db.pkl +0 -0
  42. pyTEMlib/data/fparam.txt +0 -103
  43. pyTEMlib/data/microscopes.csv +0 -7
  44. pyTEMlib/data/microscopes.xml +0 -167
  45. pyTEMlib/data/path.txt +0 -1
  46. pyTEMlib/defaults_parser.py +0 -90
  47. pyTEMlib/dm3_reader.py +0 -613
  48. pyTEMlib/edges_db.py +0 -76
  49. pyTEMlib/eels_dlg.py +0 -224
  50. pyTEMlib/hdf_utils.py +0 -483
  51. pyTEMlib/image_tools1.py +0 -2194
  52. pyTEMlib/info_dialog.py +0 -237
  53. pyTEMlib/info_dlg.py +0 -202
  54. pyTEMlib/nion_reader.py +0 -297
  55. pyTEMlib/nsi_reader.py +0 -170
  56. pyTEMlib/structure_tools.py +0 -316
  57. pyTEMlib/test.py +0 -2072
  58. pyTEMlib-0.2020.11.1.dist-info/METADATA +0 -20
  59. pyTEMlib-0.2020.11.1.dist-info/RECORD +0 -45
  60. {pyTEMlib-0.2020.11.1.dist-info → pyTEMlib-0.2024.8.4.dist-info}/top_level.txt +0 -0
pyTEMlib/graph_viz.py ADDED
@@ -0,0 +1,449 @@
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 plot_super_cell(super_cell, shift_x=0.):
23
+ """ make a super_cell to plot with extra atoms at periodic boundaries"""
24
+
25
+ if not isinstance(super_cell, ase.Atoms):
26
+ raise TypeError('Need an ase Atoms object')
27
+
28
+ plot_boundary = super_cell * (2, 2, 3)
29
+ plot_boundary.positions[:, 0] = plot_boundary.positions[:, 0] - super_cell.cell[0, 0] * shift_x
30
+
31
+ del plot_boundary[plot_boundary.positions[:, 2] > super_cell.cell[2, 2] * 1.5 + 0.1]
32
+ del plot_boundary[plot_boundary.positions[:, 1] > super_cell.cell[1, 1] + 0.1]
33
+ del plot_boundary[plot_boundary.positions[:, 0] > super_cell.cell[0, 0] + 0.1]
34
+ del plot_boundary[plot_boundary.positions[:, 0] < -0.1]
35
+ plot_boundary.cell = super_cell.cell * (1, 1, 1.5)
36
+
37
+ return plot_boundary
38
+
39
+
40
+ def plot_polyhedron(polyhedra, indices, center=False):
41
+ """
42
+ Information to plot polyhedra with plotly
43
+
44
+ Parameter
45
+ ---------
46
+ polyhedra: dict
47
+ dictionary of all polyhedra
48
+ indices: list or integer
49
+ list or index of polyhedron to plot.
50
+ center: boolean
51
+ whether to center polyhedra on origin
52
+
53
+ Returns
54
+ -------
55
+ data: dict
56
+ instructions to plot for plotly
57
+ """
58
+
59
+ if isinstance(indices, int):
60
+ indices = [indices]
61
+ if len(indices) == 0:
62
+ print('Did not find any polyhedra')
63
+ return {}
64
+
65
+ center_point = np.mean(polyhedra[indices[0]]['vertices'], axis=0)
66
+
67
+ if center:
68
+ print(center_point)
69
+ center = center_point
70
+ else:
71
+ center = [0, 0, 0]
72
+
73
+ data = []
74
+ for index in indices:
75
+ polyhedron = polyhedra[index]
76
+
77
+ vertices = polyhedron['vertices'] - center
78
+ faces = np.array(polyhedron['triangles'])
79
+ x, y, z = vertices.T
80
+ i_i, j_j, k_k = faces.T
81
+
82
+ mesh = dict(type='mesh3d',
83
+ x=x,
84
+ y=y,
85
+ z=z,
86
+ i=i_i,
87
+ j=j_j,
88
+ k=k_k,
89
+ name='',
90
+ opacity=0.2,
91
+ color=px.colors.qualitative.Light24[len(vertices) % 24]
92
+ )
93
+ tri_vertices = vertices[faces]
94
+ x_e = []
95
+ y_e = []
96
+ z_e = []
97
+ for t_v in tri_vertices:
98
+ x_e += [t_v[k % 3][0] for k in range(4)] + [None]
99
+ y_e += [t_v[k % 3][1] for k in range(4)] + [None]
100
+ z_e += [t_v[k % 3][2] for k in range(4)] + [None]
101
+
102
+ # define the lines to be plotted
103
+ lines = dict(type='scatter3d',
104
+ x=x_e,
105
+ y=y_e,
106
+ z=z_e,
107
+ mode='lines',
108
+ name='',
109
+ line=dict(color='rgb(70,70,70)', width=1.5))
110
+ data.append(mesh)
111
+ data.append(lines)
112
+ return data
113
+
114
+
115
+ def plot_bonds(polyhedra):
116
+ """
117
+ Information to plot bonds with plotly
118
+
119
+ Parameter
120
+ ---------
121
+ polyhedra: dict
122
+ dictionary of all polyhedra
123
+
124
+ Returns
125
+ -------
126
+ data: dict
127
+ instructions to plot for plotly
128
+ """
129
+ indices = range(len(polyhedra))
130
+
131
+ data = []
132
+ for index in indices:
133
+ polyhedron = polyhedra[index]
134
+
135
+ vertices = polyhedron['vertices']
136
+ faces = np.array(polyhedron['triangles'])
137
+ x, y, z = vertices.T
138
+ i_i, j_j, k_k = faces.T
139
+
140
+ tri_vertices = vertices[faces]
141
+ x_e = []
142
+ y_e = []
143
+ z_e = []
144
+ for t_v in tri_vertices:
145
+ x_e += [t_v[k % 3][0] for k in range(4)] + [None]
146
+ y_e += [t_v[k % 3][1] for k in range(4)] + [None]
147
+ z_e += [t_v[k % 3][2] for k in range(4)] + [None]
148
+
149
+ # define the lines to be plotted
150
+ lines = dict(type='scatter3d',
151
+ x=x_e,
152
+ y=y_e,
153
+ z=z_e,
154
+ mode='lines',
155
+ name='',
156
+ line=dict(color='rgb(70,70,70)', width=1.5))
157
+ data.append(lines)
158
+ return data
159
+
160
+
161
+ def get_boundary_polyhedra(polyhedra, boundary_x=0, boundary_width=0.5, verbose=True, z_lim=[0, 100]):
162
+ """
163
+ get indices of polyhedra at boundary (assumed to be parallel to x-axis)
164
+
165
+ Parameter
166
+ ---------
167
+ polyhedra: dict
168
+ dictionary of all polyhedra
169
+ boundary_x: float
170
+ position of boundary in Angstrom
171
+ boundary_width: float
172
+ width of boundary where center of polyhedra are considered in Angstrom
173
+ verbose: boolean
174
+ optional
175
+ z_lim: list
176
+ upper and lower limit of polyhedra to plot
177
+
178
+ Returns
179
+ -------
180
+ boundary_polyhedra: list
181
+ list of polyhedra at boundary
182
+ """
183
+ boundary_polyhedra = []
184
+ for key, polyhedron in polyhedra.items():
185
+ center = polyhedron['vertices'].mean(axis=0)
186
+ if abs(center[0] - boundary_x) < 0.5 and (z_lim[0] < center[2] < z_lim[1]):
187
+ boundary_polyhedra.append(key)
188
+ if verbose:
189
+ print(key, polyhedron['length'], center)
190
+
191
+ return boundary_polyhedra
192
+
193
+
194
+ def plot_with_polyhedra(polyhedra, indices, atoms=None, title=''):
195
+ """
196
+ plot atoms and polyhedra with plotly
197
+
198
+ Parameter
199
+ ---------
200
+ polyhedra: dict
201
+ dictionary of all polyhedra
202
+ indices: list or integer
203
+ list or index of polyhedron to plot.
204
+ atoms: ase.Atoms
205
+ optional structure info to plot atoms (with correct color)
206
+
207
+ Returns
208
+ -------
209
+ fig: plotly.figure
210
+ plotly figure instance
211
+ """
212
+
213
+ data = plot_polyhedron(polyhedra, indices)
214
+ if not isinstance(atoms, ase.Atoms):
215
+ atoms = None
216
+
217
+ data[0]['opacity'] = 0.05
218
+ fig = go.Figure(data=data)
219
+ if atoms is not None:
220
+ fig.add_trace(go.Scatter3d(
221
+ mode='markers',
222
+ x=atoms.positions[:, 0], y=atoms.positions[:, 1], z=atoms.positions[:, 2],
223
+ marker=dict(
224
+ color=atoms.get_atomic_numbers(),
225
+ size=5,
226
+ sizemode='diameter',
227
+ colorscale=["blue", "green", "red"])))
228
+
229
+ fig.update_layout(width=1000, height=700, showlegend=False)
230
+ fig.update_layout(scene_aspectmode='data',
231
+ scene_aspectratio=dict(x=1, y=1, z=1))
232
+
233
+ camera = {'up': {'x': 1, 'y': 0, 'z': 0},
234
+ 'center': {'x': 0, 'y': 0, 'z': 0},
235
+ 'eye': {'x': 0, 'y': 0, 'z': 1}}
236
+
237
+ fig.update_layout(scene_camera=camera, title=title)
238
+ fig.update_scenes(camera_projection_type="orthographic")
239
+ return fig
240
+
241
+
242
+ def plot_supercell(supercell, size=(1, 1, 1), shift_x=0.25, title=''):
243
+ """
244
+ plot supercell with plotly
245
+
246
+ Parameter
247
+ ---------
248
+ supercell: ase.Atoms
249
+ optional structure info to plot atoms (with correct color)
250
+ shift_x: float
251
+ amount of shift in x direction of supercell
252
+ title: str
253
+ title of plot
254
+
255
+ Returns
256
+ -------
257
+ fig: plotly.figure
258
+ plotly figure instance
259
+ """
260
+
261
+ plot_cell = pyTEMlib.graph_tools.plot_super_cell(supercell * size, shift_x=shift_x)
262
+
263
+ # grain_boundary.cell.volume
264
+ supercell_area = supercell.cell.lengths()[1] / supercell.cell.lengths()[2]
265
+ print(supercell.symbols)
266
+ volume__bulk_atom = 16.465237835776012
267
+ ideal_volume = len(supercell.positions) * volume__bulk_atom
268
+ print(len(supercell.positions) * volume__bulk_atom, supercell.cell.volume)
269
+ x_0 = ideal_volume / supercell.cell.lengths()[1] / supercell.cell.lengths()[2]
270
+ print(f'Zero volume expansion supercell length: {x_0 / 10:.2f} nm; '
271
+ f' compared to actual {supercell.cell.lengths()[0] / 10:.2f} nm')
272
+
273
+ fig = go.Figure(data=[
274
+ go.Scatter3d(x=plot_cell.positions[:, 0], y=plot_cell.positions[:, 1], z=plot_cell.positions[:, 2],
275
+ mode='markers',
276
+ marker=dict(
277
+ color=plot_cell.get_atomic_numbers(),
278
+ size=5,
279
+ sizemode='diameter',
280
+ colorscale=["blue", "green", "red"]))])
281
+
282
+ fig.update_layout(width=700, margin=dict(r=10, l=10, b=10, t=10))
283
+ fig.update_layout(scene_aspectmode='data',
284
+ scene_aspectratio=dict(x=1, y=1, z=1))
285
+
286
+ camera = dict(
287
+ up=dict(x=0, y=1, z=0),
288
+ center=dict(x=0, y=0, z=0),
289
+ eye=dict(x=0, y=0, z=1)
290
+ )
291
+ fig.update_layout(scene_camera=camera, title=title)
292
+ fig.update_scenes(camera_projection_type="orthographic")
293
+ return fig
294
+
295
+
296
+ def plot_supercell_bonds(polyhedra, atoms, volumes=None, atom_size=15, title=''):
297
+ """
298
+ plot atoms and bonds with plotly
299
+
300
+ Parameter
301
+ ---------
302
+ polyhedra: dict
303
+ dictionary of all polyhedra
304
+ atoms: ase.Atoms
305
+ optional structure info to plot atoms (with correct color)
306
+ volumes: list
307
+ list of volumes, optional structure
308
+ atoms_size: float
309
+ sie of atoms to plot
310
+ title: str
311
+ title of plot
312
+
313
+ Returns
314
+ -------
315
+ fig: plotly.figure
316
+ plotly figure instance
317
+ """
318
+
319
+ data = plot_bonds(polyhedra)
320
+ if volumes is None:
321
+ volumes = [atom_size] * len(atoms.get_atomic_numbers())
322
+
323
+ fig = go.Figure(data=data)
324
+ fig.add_trace(go.Scatter3d(
325
+ mode='markers',
326
+ x=atoms.positions[:, 0], y=atoms.positions[:, 1], z=atoms.positions[:, 2],
327
+ marker=dict(
328
+ color=atoms.get_atomic_numbers(),
329
+ size=np.asarray(volumes) ** 2 / 10,
330
+ sizemode='diameter',
331
+ colorscale=["blue", "green", "red"])))
332
+
333
+ fig.update_layout(width=1000, height=700, showlegend=False)
334
+ fig.update_layout(scene_aspectmode='data',
335
+ scene_aspectratio=dict(x=1, y=1, z=1))
336
+
337
+ camera = {'up': {'x': 0, 'y': 1, 'z': 0},
338
+ 'center': {'x': 0, 'y': 0, 'z': 0},
339
+ 'eye': {'x': 0, 'y': 0, 'z': 1}}
340
+ fig.update_layout(scene_camera=camera, title=title)
341
+ fig.update_scenes(camera_projection_type="orthographic")
342
+ return fig
343
+
344
+
345
+ def plot_supercell_polyhedra(polyhedra, indices, atoms, volumes=None, title=''):
346
+ """
347
+ plot atoms and polyhedra with plotly
348
+
349
+ Parameter
350
+ ---------
351
+ polyhedra: dict
352
+ dictionary of all polyhedra
353
+ indices: list
354
+ list of indices of polyhedra to plot
355
+ atoms: ase.Atoms
356
+ optional structure info to plot atoms (with correct color)
357
+ volumes: list
358
+ list of volumes, optional structure
359
+ title: str
360
+ title of plot
361
+
362
+ Returns
363
+ -------
364
+ fig: plotly.figure
365
+ plotly figure instance
366
+ """
367
+ data = plot_polyhedron(polyhedra, indices)
368
+ if volumes is None:
369
+ volumes = [10] * len(atoms.get_atomic_numbers())
370
+
371
+ fig = go.Figure(data=data)
372
+ fig.add_trace(go.Scatter3d(
373
+ mode='markers',
374
+ x=atoms.positions[:, 0], y=atoms.positions[:, 1], z=atoms.positions[:, 2],
375
+ marker=dict(
376
+ color=atoms.get_atomic_numbers(),
377
+ size=np.asarray(volumes)**2 / 10,
378
+ sizemode='diameter',
379
+ colorscale=["blue", "green", "red"])))
380
+
381
+ fig.update_layout(width=1000, height=700, showlegend=False)
382
+ fig.update_layout(scene_aspectmode='data',
383
+ scene_aspectratio=dict(x=1, y=1, z=1))
384
+
385
+ camera = {'up': {'x': 0, 'y': 1, 'z': 0},
386
+ 'center': {'x': 0, 'y': 0, 'z': 0},
387
+ 'eye': {'x': 0, 'y': 0, 'z': 1}}
388
+ fig.update_layout(scene_camera=camera, title=title)
389
+ fig.update_scenes(camera_projection_type="orthographic")
390
+ return fig
391
+
392
+
393
+ def show_polyhedra(polyhedra, boundary_polyhedra, atoms, volumes=None, title=f''):
394
+ """
395
+ plot polyhedra and atoms of vertices with plotly
396
+
397
+ Parameter
398
+ ---------
399
+ polyhedra: dict
400
+ dictionary of all polyhedra
401
+ boundary_polyhedra: list
402
+ list of indices of polyhedra to plot
403
+ atoms: ase.Atoms
404
+ optional structure info to plot atoms (with correct color)
405
+ volumes: list
406
+ list of volumes, optional structure
407
+ title: str
408
+ title of plot
409
+
410
+ Returns
411
+ -------
412
+ fig: plotly.figure
413
+ plotly figure instance
414
+ """
415
+
416
+ data = plot_polyhedron(polyhedra, boundary_polyhedra)
417
+ atom_indices = []
418
+ for poly in boundary_polyhedra:
419
+ atom_indices.extend(polyhedra[poly]['indices'])
420
+ atom_indices = list(set(atom_indices))
421
+ atomic_numbers = []
422
+ atomic_volumes = []
423
+ for atom in atom_indices:
424
+ atomic_numbers.append(atoms[atom].number)
425
+ atomic_volumes.append(volumes[atoms[atom].index] ** 2 / 10)
426
+
427
+ if volumes is None:
428
+ atomic_volumes = [10] * len(atoms.get_atomic_numbers())
429
+ fig = go.Figure(data=data)
430
+
431
+ fig.add_trace(go.Scatter3d(
432
+ mode='markers',
433
+ x=atoms.positions[atom_indices, 0], y=atoms.positions[atom_indices, 1], z=atoms.positions[atom_indices, 2],
434
+ marker=dict(
435
+ color=atomic_numbers,
436
+ size=atomic_volumes,
437
+ sizemode='diameter',
438
+ colorscale=["blue", "green", "red"])))
439
+
440
+ fig.update_layout(width=1000, height=700, showlegend=False)
441
+ fig.update_layout(scene_aspectmode='data',
442
+ scene_aspectratio=dict(x=1, y=1, z=1))
443
+
444
+ camera = {'up': {'x': 1, 'y': 0, 'z': 0},
445
+ 'center': {'x': 0, 'y': 0, 'z': 0},
446
+ 'eye': {'x': 0, 'y': 0, 'z': 1}}
447
+ fig.update_layout(scene_camera=camera, title=title)
448
+ fig.update_scenes(camera_projection_type="orthographic")
449
+ return fig
@@ -0,0 +1,158 @@
1
+ """
2
+ Input Dialog for Image Analysis
3
+
4
+ Author: Gerd Duscher
5
+
6
+ """
7
+ # -*- coding: utf-8 -*-
8
+
9
+ import numpy as np
10
+ import sidpy
11
+
12
+ Qt_available = True
13
+ try:
14
+ from PyQt5 import QtCore, QtWidgets
15
+ except:
16
+ Qt_available = False
17
+ # print('Qt dialogs are not available')
18
+
19
+ from matplotlib.widgets import SpanSelector
20
+ from skimage import exposure
21
+
22
+ from pyTEMlib.image_dlg import *
23
+ from pyTEMlib.microscope import microscope
24
+
25
+ _version = 000
26
+
27
+ if Qt_available:
28
+ class ImageDialog(QtWidgets.QDialog):
29
+ """
30
+ Input Dialog for Image Analysis
31
+
32
+ Opens a PyQt5 GUi Dialog that allows to set the experimental parameter necessary for a Quantification.
33
+
34
+
35
+ The dialog operates on a sidpy dataset
36
+ """
37
+
38
+ def __init__(self, dataset, parent=None):
39
+ super(ImageDialog, self).__init__(parent)
40
+ if not isinstance(dataset, sidpy.Dataset):
41
+ raise TypeError("we need a sidpy.Dataset")
42
+ self.parent = parent
43
+ self.debug = 0
44
+ self.dataset = dataset
45
+ self.image = np.array(self.dataset)
46
+ self.v_min = np.array(dataset).min()
47
+ self.v_max = np.array(dataset).max()
48
+
49
+ self.ui = UiDialog(self)
50
+ self.setWindowTitle('Image Info')
51
+
52
+ self.dataset.plot()
53
+ self.histogram()
54
+ self.cid = self.ui.histogram.axes.figure.canvas.mpl_connect('button_press_event', self.onclick)
55
+
56
+ self.span = SpanSelector(self.ui.histogram.axes, self.on_select, 'horizontal', useblit=False,
57
+ button=1, minspan=5,
58
+ rectprops=dict(alpha=0.3, facecolor='blue'))
59
+ minimum_info = {'size': self.dataset.shape,
60
+ 'exposure_time': 0.0,
61
+ 'convergence_angle': 0.0,
62
+ 'acceleration_voltage': 100.0,
63
+ 'binning': 1, 'conversion': 1.0,
64
+ 'flux': 1.0, 'current': 1.0}
65
+
66
+ if 'experiment' not in self.dataset.metadata:
67
+ self.dataset.metadata['experiment'] = {}
68
+ for key, value in minimum_info.items():
69
+ if key not in self.dataset.metadata['experiment']:
70
+ self.dataset.metadata['experiment'][key] = value
71
+ self.experiment = self.dataset.metadata['experiment']
72
+ self.set_action()
73
+ self.update()
74
+
75
+ def histogram(self, bins=256):
76
+ ax_hist = self.ui.histogram.axes
77
+ ax_hist.clear()
78
+
79
+ hist, bin_edges = np.histogram(np.array(self.image), range=[self.v_min, self.v_max], bins=bins, density=True)
80
+ ax_hist.plot(np.array(bin_edges)[:-1], np.array(hist))
81
+
82
+ image = self.image * 1.0
83
+ image[image < self.v_min] = self.v_min
84
+ image[image > self.v_max] = self.v_max
85
+
86
+ img_cdf, bins = exposure.cumulative_distribution(np.array(image), bins)
87
+ ax_hist.plot(bins, img_cdf * hist.max(), 'r')
88
+ ax_hist.figure.canvas.draw()
89
+ self.span = SpanSelector(self.ui.histogram.axes, self.on_select, 'horizontal', useblit=False,
90
+ button=1, minspan=5,
91
+ rectprops=dict(alpha=0.3, facecolor='blue'))
92
+ self.plot()
93
+
94
+ def onclick(self, event):
95
+ if event.dblclick:
96
+ self.v_min = np.array(self.dataset).min()
97
+ self.v_max = np.array(self.dataset).max()
98
+ self.histogram()
99
+
100
+ def on_select(self, v_min, v_max):
101
+ self.v_min = v_min
102
+ self.v_max = v_max
103
+ self.histogram()
104
+
105
+ def plot(self):
106
+ ax = self.dataset.view.axis
107
+ img = self.dataset.view.img
108
+ img.set_data(self.image)
109
+ img.set_clim(vmin=self.v_min, vmax=self.v_max)
110
+ ax.figure.canvas.draw()
111
+
112
+ def on_enter(self):
113
+ sender = self.sender()
114
+ if sender == self.ui.timeEdit:
115
+ value = float(str(sender.displayText()).strip())
116
+ self.experiment['exposure_time'] = value
117
+ sender.setText(f"{value:.2f}")
118
+ elif sender == self.ui.convEdit:
119
+ value = float(str(sender.displayText()).strip())
120
+ self.experiment['convergence_angle'] = value
121
+ sender.setText(f"{value:.2f}")
122
+ elif sender == self.ui.E0Edit:
123
+ value = float(str(sender.displayText()).strip())
124
+ self.experiment['acceleration_voltage'] = value * 1000.0
125
+ sender.setText(f"{value:.2f}")
126
+
127
+ def on_list_enter(self):
128
+ sender = self.sender()
129
+ if sender == self.ui.TEMList:
130
+ microscope.set_microscope(self.ui.TEMList.currentText())
131
+ self.setWindowTitle(microscope.name)
132
+
133
+ self.experiment['microscope'] = microscope.name
134
+ self.experiment['convergence_angle'] = microscope.alpha
135
+ self.experiment['acceleration_voltage'] = microscope.E0
136
+ self.update()
137
+
138
+ def update(self):
139
+ self.ui.convEdit.setText(f"{self.experiment['convergence_angle']:.2f}")
140
+ self.ui.E0Edit.setText(f"{self.experiment['acceleration_voltage']/1000.:.2f}")
141
+
142
+ self.ui.timeEdit.setText(f"{self.experiment['exposure_time']:.6f}")
143
+ size_text = f'{self.dataset.shape[0]}'
144
+ for size in self.dataset.shape[1:]:
145
+ size_text = size_text + f' x {size}'
146
+ self.ui.sizeEdit.setText(size_text)
147
+
148
+ # self.ui.binningEdit.setText(f"{self.experiment['binning']}")
149
+ # self.ui.conversionEdit.setText(f"{self.experiment['conversion']:.2f}")
150
+ # self.ui.fluxEdit.setText(f"{self.experiment['flux']:.2f}")
151
+ # self.ui.VOAEdit.setText(f"{self.experiment['current']:.2f}")
152
+
153
+ def set_action(self):
154
+ self.ui.timeEdit.editingFinished.connect(self.on_enter)
155
+ self.ui.TEMList.activated[str].connect(self.on_list_enter)
156
+
157
+ self.ui.convEdit.editingFinished.connect(self.on_enter)
158
+ self.ui.E0Edit.editingFinished.connect(self.on_enter)