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.

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