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.

Files changed (94) hide show
  1. build/lib/pyTEMlib/__init__.py +33 -0
  2. build/lib/pyTEMlib/animation.py +640 -0
  3. build/lib/pyTEMlib/atom_tools.py +238 -0
  4. build/lib/pyTEMlib/config_dir.py +31 -0
  5. build/lib/pyTEMlib/crystal_tools.py +1219 -0
  6. build/lib/pyTEMlib/diffraction_plot.py +756 -0
  7. build/lib/pyTEMlib/dynamic_scattering.py +293 -0
  8. build/lib/pyTEMlib/eds_tools.py +826 -0
  9. build/lib/pyTEMlib/eds_xsections.py +432 -0
  10. build/lib/pyTEMlib/eels_tools/__init__.py +44 -0
  11. build/lib/pyTEMlib/eels_tools/core_loss_tools.py +751 -0
  12. build/lib/pyTEMlib/eels_tools/eels_database.py +134 -0
  13. build/lib/pyTEMlib/eels_tools/low_loss_tools.py +655 -0
  14. build/lib/pyTEMlib/eels_tools/peak_fit_tools.py +175 -0
  15. build/lib/pyTEMlib/eels_tools/zero_loss_tools.py +264 -0
  16. build/lib/pyTEMlib/file_reader.py +274 -0
  17. build/lib/pyTEMlib/file_tools.py +811 -0
  18. build/lib/pyTEMlib/get_bote_salvat.py +69 -0
  19. build/lib/pyTEMlib/graph_tools.py +1153 -0
  20. build/lib/pyTEMlib/graph_viz.py +599 -0
  21. build/lib/pyTEMlib/image/__init__.py +37 -0
  22. build/lib/pyTEMlib/image/image_atoms.py +270 -0
  23. build/lib/pyTEMlib/image/image_clean.py +197 -0
  24. build/lib/pyTEMlib/image/image_distortion.py +299 -0
  25. build/lib/pyTEMlib/image/image_fft.py +277 -0
  26. build/lib/pyTEMlib/image/image_graph.py +926 -0
  27. build/lib/pyTEMlib/image/image_registration.py +316 -0
  28. build/lib/pyTEMlib/image/image_utilities.py +309 -0
  29. build/lib/pyTEMlib/image/image_window.py +421 -0
  30. build/lib/pyTEMlib/image_tools.py +699 -0
  31. build/lib/pyTEMlib/interactive_image.py +1 -0
  32. build/lib/pyTEMlib/kinematic_scattering.py +1196 -0
  33. build/lib/pyTEMlib/microscope.py +61 -0
  34. build/lib/pyTEMlib/probe_tools.py +906 -0
  35. build/lib/pyTEMlib/sidpy_tools.py +153 -0
  36. build/lib/pyTEMlib/simulation_tools.py +104 -0
  37. build/lib/pyTEMlib/test.py +437 -0
  38. build/lib/pyTEMlib/utilities.py +314 -0
  39. build/lib/pyTEMlib/version.py +5 -0
  40. build/lib/pyTEMlib/xrpa_x_sections.py +20976 -0
  41. pyTEMlib/__init__.py +25 -3
  42. pyTEMlib/animation.py +31 -22
  43. pyTEMlib/atom_tools.py +29 -34
  44. pyTEMlib/config_dir.py +2 -28
  45. pyTEMlib/crystal_tools.py +129 -165
  46. pyTEMlib/eds_tools.py +559 -342
  47. pyTEMlib/eds_xsections.py +432 -0
  48. pyTEMlib/eels_tools/__init__.py +44 -0
  49. pyTEMlib/eels_tools/core_loss_tools.py +751 -0
  50. pyTEMlib/eels_tools/eels_database.py +134 -0
  51. pyTEMlib/eels_tools/low_loss_tools.py +655 -0
  52. pyTEMlib/eels_tools/peak_fit_tools.py +175 -0
  53. pyTEMlib/eels_tools/zero_loss_tools.py +264 -0
  54. pyTEMlib/file_reader.py +274 -0
  55. pyTEMlib/file_tools.py +260 -1130
  56. pyTEMlib/get_bote_salvat.py +69 -0
  57. pyTEMlib/graph_tools.py +101 -174
  58. pyTEMlib/graph_viz.py +150 -0
  59. pyTEMlib/image/__init__.py +37 -0
  60. pyTEMlib/image/image_atoms.py +270 -0
  61. pyTEMlib/image/image_clean.py +197 -0
  62. pyTEMlib/image/image_distortion.py +299 -0
  63. pyTEMlib/image/image_fft.py +277 -0
  64. pyTEMlib/image/image_graph.py +926 -0
  65. pyTEMlib/image/image_registration.py +316 -0
  66. pyTEMlib/image/image_utilities.py +309 -0
  67. pyTEMlib/image/image_window.py +421 -0
  68. pyTEMlib/image_tools.py +154 -915
  69. pyTEMlib/kinematic_scattering.py +1 -1
  70. pyTEMlib/probe_tools.py +1 -1
  71. pyTEMlib/test.py +437 -0
  72. pyTEMlib/utilities.py +314 -0
  73. pyTEMlib/version.py +2 -3
  74. pyTEMlib/xrpa_x_sections.py +14 -10
  75. {pytemlib-0.2025.4.1.dist-info → pytemlib-0.2025.9.1.dist-info}/METADATA +13 -16
  76. pytemlib-0.2025.9.1.dist-info/RECORD +86 -0
  77. {pytemlib-0.2025.4.1.dist-info → pytemlib-0.2025.9.1.dist-info}/WHEEL +1 -1
  78. pytemlib-0.2025.9.1.dist-info/top_level.txt +6 -0
  79. pyTEMlib/core_loss_widget.py +0 -721
  80. pyTEMlib/eels_dialog.py +0 -754
  81. pyTEMlib/eels_dialog_utilities.py +0 -1199
  82. pyTEMlib/eels_tools.py +0 -2359
  83. pyTEMlib/file_tools_qt.py +0 -193
  84. pyTEMlib/image_dialog.py +0 -158
  85. pyTEMlib/image_dlg.py +0 -146
  86. pyTEMlib/info_widget.py +0 -1086
  87. pyTEMlib/info_widget3.py +0 -1120
  88. pyTEMlib/low_loss_widget.py +0 -479
  89. pyTEMlib/peak_dialog.py +0 -1129
  90. pyTEMlib/peak_dlg.py +0 -286
  91. pytemlib-0.2025.4.1.dist-info/RECORD +0 -38
  92. pytemlib-0.2025.4.1.dist-info/top_level.txt +0 -1
  93. {pytemlib-0.2025.4.1.dist-info → pytemlib-0.2025.9.1.dist-info}/entry_points.txt +0 -0
  94. {pytemlib-0.2025.4.1.dist-info → pytemlib-0.2025.9.1.dist-info}/licenses/LICENSE +0 -0
pyTEMlib/eels_dialog.py DELETED
@@ -1,754 +0,0 @@
1
- """
2
- Author: Gerd Duscher
3
- """
4
-
5
-
6
- import numpy as np
7
- import warnings
8
-
9
- import ipywidgets
10
- import IPython.display
11
- # from IPython.display import display
12
- import matplotlib
13
- import matplotlib.pylab as plt
14
- import matplotlib.patches as patches
15
-
16
- from pyTEMlib import file_tools as ft
17
- from pyTEMlib import eels_tools as eels
18
- from pyTEMlib import eels_dialog_utilities
19
-
20
- import sidpy
21
-
22
-
23
- class CurveVisualizer(object):
24
- """Plots a sidpy.Dataset with spectral dimension-type
25
-
26
- """
27
- def __init__(self, dset, spectrum_number=None, axis=None, leg=None, **kwargs):
28
- if not isinstance(dset, sidpy.Dataset):
29
- raise TypeError('dset should be a sidpy.Dataset object')
30
- if axis is None:
31
- self.fig = plt.figure()
32
- self.axis = self.fig.add_subplot(1, 1, 1)
33
- else:
34
- self.axis = axis
35
- self.fig = axis.figure
36
-
37
- self.dset = dset
38
- self.selection = []
39
- [self.spec_dim, self.energy_scale] = ft.get_dimensions_by_type('spectral', self.dset)[0]
40
-
41
- self.lined = dict()
42
- self.plot(**kwargs)
43
-
44
- def plot(self, **kwargs):
45
- if self.dset.data_type.name == 'IMAGE_STACK':
46
- line1, = self.axis.plot(self.energy_scale.values, self.dset[0, 0], label='spectrum', **kwargs)
47
- else:
48
- line1, = self.axis.plot(self.energy_scale.values, self.dset, label='spectrum', **kwargs)
49
- lines = [line1]
50
- if 'add2plot' in self.dset.metadata:
51
- data = self.dset.metadata['add2plot']
52
- for key, line in data.items():
53
- line_add, = self.axis.plot(self.energy_scale.values, line['data'], label=line['legend'])
54
- lines.append(line_add)
55
-
56
- legend = self.axis.legend(loc='upper right', fancybox=True, shadow=True)
57
- legend.get_frame().set_alpha(0.4)
58
-
59
- for legline, origline in zip(legend.get_lines(), lines):
60
- legline.set_picker(True)
61
- legline.set_pickradius(5) # 5 pts tolerance
62
- self.lined[legline] = origline
63
- self.fig.canvas.mpl_connect('pick_event', self.onpick)
64
-
65
- self.axis.axhline(0, color='gray', alpha=0.6)
66
- self.axis.set_xlabel(self.dset.labels[0])
67
- self.axis.set_ylabel(self.dset.data_descriptor)
68
- self.axis.ticklabel_format(style='sci', scilimits=(-2, 3))
69
- self.fig.canvas.draw_idle()
70
-
71
- def update(self, **kwargs):
72
- x_limit = self.axis.get_xlim()
73
- y_limit = self.axis.get_ylim()
74
- self.axis.clear()
75
- self.plot(**kwargs)
76
- self.axis.set_xlim(x_limit)
77
- self.axis.set_ylim(y_limit)
78
-
79
- def onpick(self, event):
80
- # on the pick event, find the orig line corresponding to the
81
- # legend proxy line, and toggle the visibility
82
- legline = event.artist
83
- origline = self.lined[legline]
84
- vis = not origline.get_visible()
85
- origline.set_visible(vis)
86
- # Change the alpha on the line in the legend, so we can see what lines
87
- # have been toggled
88
- if vis:
89
- legline.set_alpha(1.0)
90
- else:
91
- legline.set_alpha(0.2)
92
- self.fig.canvas.draw()
93
-
94
- def get_core_loss_sidebar():
95
- side_bar = ipywidgets.GridspecLayout(14, 3,width='auto', grid_gap="0px")
96
-
97
-
98
- row = 0
99
- side_bar[row, :3] = ipywidgets.ToggleButton(description='Fit Area',
100
- layout=ipywidgets.Layout(width='auto', grid_area='header'),
101
- tooltip='Shows fit regions and regions excluded from fit',
102
- button_style='info') #ipywidgets.ButtonStyle(button_color='lightblue'))
103
- row += 1
104
- side_bar[row, :2] = ipywidgets.FloatText(value=7.5,description='Fit Start:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
105
- side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='20px'))
106
- row += 1
107
- side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Fit End:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
108
- side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='20px'))
109
-
110
- row += 1
111
-
112
- side_bar[row, :3] = ipywidgets.Button(description='Elements',
113
- layout=ipywidgets.Layout(width='auto', grid_area='header'),
114
- style=ipywidgets.ButtonStyle(button_color='lightblue'))
115
- row += 1
116
- side_bar[row, :2] = ipywidgets.Dropdown(
117
- options=[('Edge 1', 0), ('Edge 2', 1), ('Edge 3', 2), ('Edge 4', 3),('Add Edge', -1)],
118
- value=0,
119
- description='Edges:',
120
- disabled=False,
121
- layout=ipywidgets.Layout(width='200px'))
122
- """side_bar[row,2] = ipywidgets.ToggleButton(
123
- description='Regions',
124
- disabled=False,
125
- button_style='', # 'success', 'info', 'warning', 'danger' or ''
126
- tooltip='Shows fit regions and regions excluded from fit',
127
- layout=ipywidgets.Layout(width='100px')
128
- )
129
- """
130
- row += 1
131
- side_bar[row, :2] = ipywidgets.IntText(value=7.5,description='Z:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
132
- side_bar[row, 2] = ipywidgets.widgets.Label(value="", layout=ipywidgets.Layout(width='100px'))
133
- row += 1
134
- side_bar[row, :2] = ipywidgets.Dropdown(
135
- options=['K1','L3', 'M5', 'M3', 'M1', 'N7', 'N5', 'N3', 'N1'],
136
- value='K1',
137
- description='Symmetry:',
138
- disabled=False,
139
- layout=ipywidgets.Layout(width='200px'))
140
- row += 1
141
- side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Onset:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
142
- side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='100px'))
143
- row += 1
144
- side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Excl.Start:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
145
- side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='100px'))
146
- row += 1
147
- side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Excl.End:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
148
- side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='100px'))
149
- row += 1
150
- side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Mutliplier:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
151
- side_bar[row, 2] = ipywidgets.widgets.Label(value="a.u.", layout=ipywidgets.Layout(width='100px'))
152
- row += 1
153
-
154
- side_bar[row, :3] = ipywidgets.Button(description='Quantification',
155
- layout=ipywidgets.Layout(width='auto', grid_area='header'),
156
- style=ipywidgets.ButtonStyle(button_color='lightblue'))
157
-
158
- row += 1
159
- side_bar[row,0] = ipywidgets.ToggleButton(
160
- description='Probabiity',
161
- disabled=False,
162
- button_style='', # 'success', 'info', 'warning', 'danger' or ''
163
- tooltip='Changes y-axis to probability of flux is given',
164
- layout=ipywidgets.Layout(width='100px')
165
- )
166
- side_bar[row,1] = ipywidgets.ToggleButton(
167
- description='Conv.LL',
168
- disabled=False,
169
- button_style='', # 'success', 'info', 'warning', 'danger' or ''
170
- tooltip='Changes y-axis to probability of flux is given',
171
- layout=ipywidgets.Layout(width='100px')
172
- )
173
- side_bar[row,2] = ipywidgets.ToggleButton(
174
- description='Show Edges',
175
- disabled=False,
176
- button_style='', # 'success', 'info', 'warning', 'danger' or ''
177
- tooltip='Changes y-axis to probability of flux is given',
178
- layout=ipywidgets.Layout(width='100px')
179
- )
180
-
181
- row += 1
182
- side_bar[row,0] = ipywidgets.ToggleButton(
183
- description='Do All',
184
- disabled=False,
185
- button_style='', # 'success', 'info', 'warning', 'danger' or ''
186
- tooltip='Fits all spectra of spectrum image',
187
- layout=ipywidgets.Layout(width='100px')
188
- )
189
-
190
- side_bar[row,1] = ipywidgets.IntProgress(value=0, min=0, max=10, description=' ', bar_style='', # 'success', 'info', 'warning', 'danger' or ''
191
- style={'bar_color': 'maroon'}, orientation='horizontal')
192
- return side_bar
193
-
194
-
195
-
196
- class CompositionWidget(object):
197
- def __init__(self, datasets=None):
198
-
199
- if not isinstance(datasets, dict):
200
- raise TypeError('dataset or first item has to be a sidpy dataset')
201
- self.datasets = datasets
202
-
203
-
204
- self.model = []
205
- self.sidebar = get_core_loss_sidebar()
206
-
207
- self.set_dataset()
208
-
209
- self.periodic_table = eels_dialog_utilities.PeriodicTableWidget(self.energy_scale)
210
- self.elements_cancel_button = ipywidgets.Button(description='Cancel')
211
- self.elements_select_button = ipywidgets.Button(description='Select')
212
- self.elements_auto_button = ipywidgets.Button(description='Auto ID')
213
-
214
- self.periodic_table_panel = ipywidgets.VBox([self.periodic_table.periodic_table,
215
- ipywidgets.HBox([self.elements_cancel_button, self.elements_auto_button, self.elements_select_button])])
216
-
217
-
218
- self.app_layout = ipywidgets.AppLayout(
219
- left_sidebar=self.sidebar,
220
- center=self.view.panel,
221
- footer=None,#message_bar,
222
- pane_heights=[0, 10, 0],
223
- pane_widths=[4, 10, 0],
224
- )
225
- self.set_action()
226
- IPython.display.display(self.app_layout)
227
-
228
-
229
- def line_select_callback(self, x_min, x_max):
230
- self.start_cursor.value = np.round(x_min,3)
231
- self.end_cursor.value = np.round(x_max, 3)
232
-
233
- self.start_channel = np.searchsorted(self.datasets[self.key].energy_loss, self.start_cursor.value)
234
- self.end_channel = np.searchsorted(self.datasets[self.key].energy_loss, self.end_cursor.value)
235
-
236
-
237
- def plot(self, scale=True):
238
- self.view.change_y_scale = self.change_y_scale
239
- self.view.y_scale = self.y_scale
240
- self.energy_scale = self.dataset.energy_loss.values
241
-
242
- if self.dataset.data_type == sidpy.DataType.SPECTRAL_IMAGE:
243
- spectrum = self.view.get_spectrum()
244
- else:
245
- spectrum = self.dataset
246
- if len(self.model) > 1:
247
- additional_spectra = {'model': self.model,
248
- 'difference': spectrum-self.model}
249
- else:
250
- additional_spectra = None
251
- self.view.plot(scale=True, additional_spectra=additional_spectra )
252
- self.change_y_scale = 1.
253
-
254
- if self.sidebar[12, 2].value:
255
- self.show_edges()
256
- if self.sidebar[0, 0].value:
257
- self.plot_regions()
258
- self.view.figure.canvas.draw_idle()
259
-
260
-
261
- def plot_regions(self):
262
- axis = self.view.figure.gca()
263
- y_min, y_max = axis.get_ylim()
264
- height = y_max - y_min
265
-
266
- rect = []
267
- if 'fit_area' in self.edges:
268
- color = 'blue'
269
- alpha = 0.2
270
- x_min = self.edges['fit_area']['fit_start']
271
- width = self.edges['fit_area']['fit_end'] - x_min
272
- rect.append(patches.Rectangle((x_min, y_min), width, height,
273
- edgecolor=color, alpha=alpha, facecolor=color))
274
- axis.add_patch(rect[0])
275
- axis.text(x_min, y_max, 'fit region', verticalalignment='top')
276
- color = 'red'
277
- alpha = 0.5
278
-
279
- for key in self.edges:
280
- if key.isdigit():
281
- x_min = self.edges[key]['start_exclude']
282
- width = self.edges[key]['end_exclude']-x_min
283
- rect.append(patches.Rectangle((x_min, y_min), width, height,
284
- edgecolor=color, alpha=alpha, facecolor=color))
285
- axis.add_patch(rect[-1])
286
- axis.text(x_min, y_max, f"exclude\n edge {int(key)+1}", verticalalignment='top')
287
-
288
- def show_edges(self):
289
- axis = self.view.figure.gca()
290
- x_min, x_max = axis.get_xlim()
291
- y_min, y_max = axis.get_ylim()
292
-
293
- for key, edge in self.edges.items():
294
- i = 0
295
- if key.isdigit():
296
- element = edge['element']
297
- for sym in edge['all_edges']:
298
- x = edge['all_edges'][sym]['onset'] + edge['chemical_shift']
299
- if x_min < x < x_max:
300
- axis.text(x, y_max, '\n' * i + f"{element}-{sym}",
301
- verticalalignment='top', color='black')
302
- axis.axvline(x, ymin=0, ymax=1, color='gray')
303
- i += 1
304
-
305
-
306
-
307
-
308
- def set_dataset(self, set_key=None):
309
- spectrum_list = []
310
- self.spectrum_keys_list = []
311
- reference_list =[('None', -1)]
312
-
313
- for index, key in enumerate(self.datasets.keys()):
314
- if '_rel' not in key:
315
- if 'Reference' not in key :
316
- if 'SPECTR' in self.datasets[key].data_type.name:
317
- spectrum_list.append((f'{key}: {self.datasets[key].title}', index))
318
- self.spectrum_keys_list.append(key)
319
- if key == self.parent.coreloss_key:
320
- self.key = key
321
- self.coreloss_key = self.key
322
- dataset_index = len(spectrum_list)-1
323
-
324
- reference_list.append((f'{key}: {self.datasets[key].title}', index))
325
- self.sidebar[0, 0].options = spectrum_list
326
- self.sidebar[0, 0].value = dataset_index
327
-
328
- if self.coreloss_key is None:
329
- return
330
- self.dataset = self.datasets[self.coreloss_key]
331
-
332
- self.spec_dim = self.dataset.get_spectral_dims(return_axis=True)[0]
333
-
334
- self.energy_scale = self.spec_dim.values
335
- self.dd = (self.energy_scale[0], self.energy_scale[1])
336
-
337
- self.dataset.metadata['experiment']['offset'] = self.energy_scale[0]
338
- self.dataset.metadata['experiment']['dispersion'] = self.spec_dim.slope
339
- if 'edges' not in self.dataset.metadata or self.dataset.metadata['edges'] == {}:
340
- self.dataset.metadata['edges'] = {'0': {}, 'model': {}, 'use_low_loss': False}
341
-
342
- self.edges = self.dataset.metadata['edges']
343
- if '0' not in self.edges:
344
- self.edges['0'] = {}
345
-
346
- if 'fit_area' not in self.edges:
347
- self.edges['fit_area'] = {}
348
- if 'fit_start' not in self.edges['fit_area']:
349
- self.sidebar[1,0].value = np.round(self.energy_scale[50], 3)
350
- self.edges['fit_area']['fit_start'] = self.sidebar[1,0].value
351
- else:
352
- self.sidebar[1,0].value = np.round(self.edges['fit_area']['fit_start'],3)
353
- if 'fit_end' not in self.edges['fit_area']:
354
- self.sidebar[2,0].value = np.round(self.energy_scale[-2], 3)
355
- self.edges['fit_area']['fit_end'] = self.sidebar[2,0].value
356
- else:
357
- self.sidebar[2,0].value = np.round(self.edges['fit_area']['fit_end'],3)
358
-
359
- if self.dataset.data_type.name == 'SPECTRAL_IMAGE':
360
- if 'SI_bin_x' not in self.dataset.metadata['experiment']:
361
- self.dataset.metadata['experiment']['SI_bin_x'] = 1
362
- self.dataset.metadata['experiment']['SI_bin_y'] = 1
363
-
364
- bin_x = self.dataset.metadata['experiment']['SI_bin_x']
365
- bin_y = self.dataset.metadata['experiment']['SI_bin_y']
366
- # self.dataset.view.set_bin([bin_x, bin_y])
367
- if self.dataset.data_type.name =='SPECTRAL_IMAGE':
368
- self.view = eels_dialog_utilities.SIPlot(self.dataset)
369
- else:
370
- self.view = eels_dialog_utilities.SpectrumPlot(self.dataset)
371
- self.y_scale = 1.0
372
- self.change_y_scale = 1.0
373
-
374
- self.update()
375
-
376
- def update_element(self, z=0, index=-1):
377
- # We check whether this element is already in the
378
- if z == 0:
379
- z = self.sidebar[5,0].value
380
-
381
- zz = eels.get_z(z)
382
- for key, edge in self.edges.items():
383
- if key.isdigit():
384
- if 'z' in edge:
385
- if zz == edge['z']:
386
- return False
387
-
388
- major_edge = ''
389
- minor_edge = ''
390
- all_edges = {}
391
- x_section = eels.get_x_sections(zz)
392
- edge_start = 10 # int(15./ft.get_slope(self.energy_scale)+0.5)
393
- for key in x_section:
394
- if len(key) == 2 and key[0] in ['K', 'L', 'M', 'N', 'O'] and key[1].isdigit():
395
- if self.energy_scale[edge_start] < x_section[key]['onset'] < self.energy_scale[-edge_start]:
396
- if key in ['K1', 'L3', 'M5']:
397
- major_edge = key
398
- elif key in self.sidebar[6,0].options:
399
- if minor_edge == '':
400
- minor_edge = key
401
- if int(key[-1]) % 2 > 0:
402
- if int(minor_edge[-1]) % 2 == 0 or key[-1] > minor_edge[-1]:
403
- minor_edge = key
404
-
405
- all_edges[key] = {'onset': x_section[key]['onset']}
406
-
407
- if major_edge != '':
408
- key = major_edge
409
- elif minor_edge != '':
410
- key = minor_edge
411
- else:
412
- print(f'Could not find no edge of {zz} in spectrum')
413
- return False
414
- if index == -1:
415
- index = self.sidebar[4, 0].value
416
- # self.ui.dialog.setWindowTitle(f'{index}, {zz}')
417
-
418
- if str(index) not in self.edges:
419
- self.edges[str(index)] = {}
420
-
421
- start_exclude = x_section[key]['onset'] - x_section[key]['excl before']
422
- end_exclude = x_section[key]['onset'] + x_section[key]['excl after']
423
-
424
- self.edges[str(index)] = {'z': zz, 'symmetry': key, 'element': eels.elements[zz],
425
- 'onset': x_section[key]['onset'], 'end_exclude': end_exclude,
426
- 'start_exclude': start_exclude}
427
- self.edges[str(index)]['all_edges'] = all_edges
428
- self.edges[str(index)]['chemical_shift'] = 0.0
429
- self.edges[str(index)]['areal_density'] = 0.0
430
- self.edges[str(index)]['original_onset'] = self.edges[str(index)]['onset']
431
- return True
432
-
433
- def sort_elements(self):
434
- onsets = []
435
- for index, edge in self.edges.items():
436
- if index.isdigit():
437
- onsets.append(float(edge['onset']))
438
-
439
- arg_sorted = np.argsort(onsets)
440
- edges = self.edges.copy()
441
- for index, i_sorted in enumerate(arg_sorted):
442
- self.edges[str(index)] = edges[str(i_sorted)].copy()
443
-
444
- index = 0
445
- edge = self.edges['0']
446
- dispersion = self.energy_scale[1]-self.energy_scale[0]
447
-
448
- while str(index + 1) in self.edges:
449
- next_edge = self.edges[str(index + 1)]
450
- if edge['end_exclude'] > next_edge['start_exclude'] - 5 * dispersion:
451
- edge['end_exclude'] = next_edge['start_exclude'] - 5 * dispersion
452
- edge = next_edge
453
- index += 1
454
-
455
- if edge['end_exclude'] > self.energy_scale[-3]:
456
- edge['end_exclude'] = self.energy_scale[-3]
457
-
458
- def set_elements(self, value=0):
459
- selected_elements = self.periodic_table.get_output()
460
- edges = self.edges.copy()
461
- to_delete = []
462
- old_elements = []
463
- if len(selected_elements) > 0:
464
- for key in self.edges:
465
- if key.isdigit():
466
- to_delete.append(key)
467
- old_elements.append(self.edges[key]['element'])
468
-
469
- for key in to_delete:
470
- edges[key] = self.edges[key]
471
- del self.edges[key]
472
-
473
- for index, elem in enumerate(selected_elements):
474
- if elem in old_elements:
475
- self.edges[str(index)] = edges[str(old_elements.index(elem))]
476
- else:
477
- self.update_element(elem, index=index)
478
- self.sort_elements()
479
- self.update()
480
- self.set_figure_pane()
481
-
482
- def set_element(self, elem):
483
- self.update_element(self.sidebar[5, 0].value)
484
- # self.sort_elements()
485
- self.update()
486
-
487
- def cursor2energy_scale(self, value):
488
- dispersion = (self.end_cursor.value - self.start_cursor.value) / (self.end_channel - self.start_channel)
489
- self.datasets[self.key].energy_loss *= (self.sidebar[3, 0].value/dispersion)
490
- self.sidebar[3, 0].value = dispersion
491
- offset = self.start_cursor.value - self.start_channel * dispersion
492
- self.datasets[self.key].energy_loss += (self.sidebar[2, 0].value-self.datasets[self.key].energy_loss[0])
493
- self.sidebar[2, 0].value = offset
494
- self.plot()
495
-
496
- def set_fit_area(self, value):
497
- if self.sidebar[1,0].value > self.sidebar[2,0].value:
498
- self.sidebar[1,0].value = self.sidebar[2,0].value -1
499
- if self.sidebar[1,0].value < self.energy_scale[0]:
500
- self.sidebar[1,0].value = self.energy_scale[0]
501
- if self.sidebar[2,0].value > self.energy_scale[-1]:
502
- self.sidebar[2,0].value = self.energy_scale[-1]
503
- self.edges['fit_area']['fit_start'] = self.sidebar[1,0].value
504
- self.edges['fit_area']['fit_end'] = self.sidebar[2,0].value
505
-
506
- self.plot()
507
-
508
- def set_y_scale(self, value):
509
- self.change_y_scale = 1/self.y_scale
510
- self.y_scale = 1.0
511
- if self.dataset.metadata['experiment']['flux_ppm'] > 0:
512
- if self.sidebar[12, 0].value:
513
- dispersion = self.energy_scale[1] - self.energy_scale[0]
514
- self.y_scale = 1/self.dataset.metadata['experiment']['flux_ppm'] * dispersion
515
-
516
- self.change_y_scale *= self.y_scale
517
- self.update()
518
- self.plot()
519
-
520
- def auto_id(self, value=0):
521
- found_edges = eels.auto_id_edges(self.dataset)
522
- if len(found_edges) > 0:
523
- self.periodic_table.elements_selected = found_edges
524
- self.periodic_table.update()
525
-
526
- def find_elements(self, value=0):
527
-
528
- if '0' not in self.edges:
529
- self.edges['0'] = {}
530
- # found_edges = eels.auto_id_edges(self.dataset)
531
- found_edges = {}
532
-
533
- selected_elements = []
534
- elements = self.edges.copy()
535
-
536
- for key in self.edges:
537
- if key.isdigit():
538
- if 'element' in self.edges[key]:
539
- selected_elements.append(self.edges[key]['element'])
540
- self.periodic_table.elements_selected = selected_elements
541
- self.periodic_table.update()
542
- self.app_layout.center = self.periodic_table_panel # self.periodic_table.periodic_table
543
-
544
- def set_figure_pane(self, value=0):
545
-
546
- self.app_layout.center = self.view.panel
547
-
548
- def update(self, index=0):
549
-
550
- index = self.sidebar[4,0].value # which edge
551
- if index < 0:
552
- options = list(self.sidebar[4,0].options)
553
- options.insert(-1, (f'Edge {len(self.sidebar[4,0].options)}', len(self.sidebar[4,0].options)-1))
554
- self.sidebar[4,0].options= options
555
- self.sidebar[4,0].value = len(self.sidebar[4,0].options)-2
556
- if str(index) not in self.edges:
557
- self.edges[str(index)] = {'z': 0, 'element': 'x', 'symmetry': 'K1', 'onset': 0, 'start_exclude': 0, 'end_exclude':0,
558
- 'areal_density': 0, 'chemical_shift':0}
559
- if 'z' not in self.edges[str(index)]:
560
- self.edges[str(index)] = {'z': 0, 'element': 'x', 'symmetry': 'K1', 'onset': 0, 'start_exclude': 0, 'end_exclude':0,
561
- 'areal_density': 0, 'chemical_shift':0}
562
- edge = self.edges[str(index)]
563
-
564
- self.sidebar[5,0].value = edge['z']
565
- self.sidebar[5,2].value = edge['element']
566
- self.sidebar[6,0].value = edge['symmetry']
567
- self.sidebar[7,0].value = edge['onset']
568
- self.sidebar[8,0].value = edge['start_exclude']
569
- self.sidebar[9,0].value = edge['end_exclude']
570
- if self.y_scale == 1.0:
571
- self.sidebar[10, 0].value = edge['areal_density']
572
- self.sidebar[10, 2].value = 'a.u.'
573
- else:
574
- dispersion = self.energy_scale[1]-self.energy_scale[0]
575
- self.sidebar[10, 0].value = np.round(edge['areal_density']/self.dataset.metadata['experiment']['flux_ppm']*1e-6, 2)
576
- self.sidebar[10, 2].value = 'atoms/nm²'
577
-
578
-
579
- def do_fit(self, value=0):
580
- if 'experiment' in self.dataset.metadata:
581
- exp = self.dataset.metadata['experiment']
582
- if 'convergence_angle' not in exp:
583
- raise ValueError('need a convergence_angle in experiment of metadata dictionary ')
584
- alpha = exp['convergence_angle']
585
- beta = exp['collection_angle']
586
- beam_kv = exp['acceleration_voltage']
587
-
588
- else:
589
- raise ValueError('need a experiment parameter in metadata dictionary')
590
-
591
- eff_beta = eels.effective_collection_angle(self.energy_scale, alpha, beta, beam_kv)
592
-
593
- self.low_loss = None
594
- if self.sidebar[12, 1].value:
595
- for key in self.datasets.keys():
596
- if key != self.key:
597
- if isinstance(self.datasets[key], sidpy.Dataset):
598
- if self.datasets[key].data_type.name == 'SPECTRUM':
599
- if self.datasets[key].energy_loss[0] < 0:
600
- self.low_loss = self.datasets[key]/self.datasets[key].sum()
601
-
602
- edges = eels.make_cross_sections(self.edges, np.array(self.energy_scale), beam_kv, eff_beta, self.low_loss)
603
-
604
- if self.dataset.data_type == sidpy.DataType.SPECTRAL_IMAGE:
605
- spectrum = self.view.get_spectrum()
606
- else:
607
- spectrum = self.dataset
608
- self.edges = eels.fit_edges2(spectrum, self.energy_scale, edges)
609
- areal_density = []
610
- elements = []
611
- for key in edges:
612
- if key.isdigit(): # only edges have numbers in that dictionary
613
- elements.append(edges[key]['element'])
614
- areal_density.append(edges[key]['areal_density'])
615
- areal_density = np.array(areal_density)
616
- out_string = '\nRelative composition: \n'
617
- for i, element in enumerate(elements):
618
- out_string += f'{element}: {areal_density[i] / areal_density.sum() * 100:.1f}% '
619
-
620
- self.model = self.edges['model']['spectrum']
621
- self.update()
622
- self.plot()
623
-
624
- def do_all_button_click(self, value=0):
625
- if self.sidebar[13,0].value==False:
626
- return
627
-
628
- if self.dataset.data_type.name != 'SPECTRAL_IMAGE':
629
- self.do_fit()
630
- return
631
-
632
- if 'experiment' in self.dataset.metadata:
633
- exp = self.dataset.metadata['experiment']
634
- if 'convergence_angle' not in exp:
635
- raise ValueError('need a convergence_angle in experiment of metadata dictionary ')
636
- alpha = exp['convergence_angle']
637
- beta = exp['collection_angle']
638
- beam_kv = exp['acceleration_voltage']
639
- else:
640
- raise ValueError('need a experiment parameter in metadata dictionary')
641
-
642
- eff_beta = eels.effective_collection_angle(self.energy_scale, alpha, beta, beam_kv)
643
- eff_beta = beta
644
- self.low_loss = None
645
- if self.sidebar[12, 1].value:
646
- for key in self.datasets.keys():
647
- if key != self.key:
648
- if isinstance(self.datasets[key], sidpy.Dataset):
649
- if 'SPECTR' in self.datasets[key].data_type.name:
650
- if self.datasets[key].energy_loss[0] < 0:
651
- self.low_loss = self.datasets[key]/self.datasets[key].sum()
652
-
653
- edges = eels.make_cross_sections(self.edges, np.array(self.energy_scale), beam_kv, eff_beta, self.low_loss)
654
-
655
- view = self.view
656
- bin_x = view.bin_x
657
- bin_y = view.bin_y
658
-
659
- start_x = view.x
660
- start_y = view.y
661
-
662
- number_of_edges = 0
663
- for key in self.edges:
664
- if key.isdigit():
665
- number_of_edges += 1
666
-
667
- results = np.zeros([int(self.dataset.shape[0]/bin_x), int(self.dataset.shape[1]/bin_y), number_of_edges])
668
- total_spec = int(self.dataset.shape[0]/bin_x)*int(self.dataset.shape[1]/bin_y)
669
- self.sidebar[13,1].max = total_spec
670
- #self.ui.progress.setMaximum(total_spec)
671
- #self.ui.progress.setValue(0)
672
- ind = 0
673
- for x in range(int(self.dataset.shape[0]/bin_x)):
674
- for y in range(int(self.dataset.shape[1]/bin_y)):
675
- ind += 1
676
- self.sidebar[13,1].value = ind
677
- view.x = x*bin_x
678
- view.y = y*bin_y
679
- spectrum = view.get_spectrum()
680
- with warnings.catch_warnings():
681
- warnings.simplefilter("ignore")
682
- edges = eels.fit_edges2(spectrum, self.energy_scale, edges)
683
- for key, edge in edges.items():
684
- if key.isdigit():
685
- # element.append(edge['element'])
686
- results[x, y, int(key)] = edge['areal_density']
687
- edges['spectrum_image_quantification'] = results
688
- self.sidebar[13,1].value = total_spec
689
- view.x = start_x
690
- view.y = start_y
691
- self.sidebar[13,0].value = False
692
-
693
-
694
- def modify_onset(self, value=-1):
695
- edge_index = self.sidebar[4, 0].value
696
- edge = self.edges[str(edge_index)]
697
- edge['onset'] = self.sidebar[7,0].value
698
- if 'original_onset' not in edge:
699
- edge['original_onset'] = edge['onset']
700
- edge['chemical_shift'] = edge['onset'] - edge['original_onset']
701
- self.update()
702
-
703
-
704
- def modify_start_exclude(self, value=-1):
705
- edge_index = self.sidebar[4, 0].value
706
- edge = self.edges[str(edge_index)]
707
- edge['start_exclude'] = self.sidebar[8,0].value
708
- self.plot()
709
-
710
- def modify_end_exclude(self, value=-1):
711
- edge_index = self.sidebar[4, 0].value
712
- edge = self.edges[str(edge_index)]
713
- edge['end_exclude'] = self.sidebar[9,0].value
714
- self.plot()
715
-
716
- def modify_areal_density(self, value=-1):
717
- edge_index = self.sidebar[4, 0].value
718
- edge = self.edges[str(edge_index)]
719
-
720
- edge['areal_density'] = self.sidebar[10, 0].value
721
- if self.y_scale != 1.0:
722
- dispersion = self.energy_scale[1]-self.energy_scale[0]
723
- edge['areal_density'] = self.sidebar[10, 0].value *self.dataset.metadata['experiment']['flux_ppm']/1e-6
724
-
725
- self.model = self.edges['model']['background']
726
- for key in self.edges:
727
- if key.isdigit():
728
- if 'data' in self.edges[key]:
729
-
730
- self.model = self.model + self.edges[key]['areal_density'] * self.edges[key]['data']
731
- self.plot()
732
-
733
- def set_action(self):
734
- self.sidebar[1, 0].observe(self.set_fit_area, names='value')
735
- self.sidebar[2, 0].observe(self.set_fit_area, names='value')
736
-
737
- self.sidebar[3, 0].on_click(self.find_elements)
738
- self.sidebar[4, 0].observe(self.update, names='value')
739
- self.sidebar[5, 0].observe(self.set_element, names='value')
740
-
741
- self.sidebar[7, 0].observe(self.modify_onset, names='value')
742
- self.sidebar[8, 0].observe(self.modify_start_exclude, names='value')
743
- self.sidebar[9, 0].observe(self.modify_end_exclude, names='value')
744
- self.sidebar[10, 0].observe(self.modify_areal_density, names='value')
745
-
746
- self.sidebar[11, 0].on_click(self.do_fit)
747
- self.sidebar[12, 2].observe(self.plot, names='value')
748
- self.sidebar[0, 0].observe(self.set_dataset, names='value')
749
- self.sidebar[12,0].observe(self.set_y_scale, names='value')
750
- self.sidebar[13,0].observe(self.do_all_button_click, names='value')
751
-
752
- self.elements_cancel_button.on_click(self.set_figure_pane)
753
- self.elements_auto_button.on_click(self.auto_id)
754
- self.elements_select_button.on_click(self.set_elements)