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/peak_dialog.py DELETED
@@ -1,1129 +0,0 @@
1
- """
2
- EELS Input Dialog for ELNES Analysis
3
- """
4
- from os import error
5
- Qt_available = True
6
- try:
7
- from PyQt5 import QtCore, QtWidgets
8
- except:
9
- Qt_available = False
10
- # print('Qt dialogs are not available')
11
-
12
- import numpy as np
13
- import scipy
14
- import scipy.optimize
15
- import scipy.signal
16
-
17
- import ipywidgets
18
- from IPython.display import display
19
- import matplotlib
20
- import matplotlib.pylab as plt
21
- import matplotlib.patches as patches
22
-
23
- import sidpy
24
- import pyTEMlib.file_tools as ft
25
- from pyTEMlib import eels_tools
26
- from pyTEMlib import peak_dlg
27
- from pyTEMlib import eels_dialog_utilities
28
-
29
- advanced_present = True
30
- try:
31
- import advanced_eels_tools
32
- print('advanced EELS features enabled')
33
- except ModuleNotFoundError:
34
- advanced_present = False
35
-
36
- _version = .001
37
-
38
- def get_sidebar():
39
- side_bar = ipywidgets.GridspecLayout(16, 3, width='auto', grid_gap="0px")
40
- row = 0
41
- side_bar[row, :3] = ipywidgets.Button(description='Fit Area',
42
- layout=ipywidgets.Layout(width='auto', grid_area='header'),
43
- style=ipywidgets.ButtonStyle(button_color='lightblue'))
44
- row += 1
45
- side_bar[row, :2] = ipywidgets.FloatText(value=7.5,description='Fit Start:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
46
- side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='20px'))
47
- row += 1
48
- side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Fit End:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
49
- side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='20px'))
50
-
51
- row += 1
52
- side_bar[row, :3] = ipywidgets.Button(description='Peak Finding',
53
- layout=ipywidgets.Layout(width='auto', grid_area='header'),
54
- style=ipywidgets.ButtonStyle(button_color='lightblue'))
55
-
56
- row += 1
57
-
58
-
59
- side_bar[row, :2] = ipywidgets.Dropdown(
60
- options=[('0', 0), ('1', 1), ('2', 2), ('3', 3), ('4', 4)],
61
- value=0,
62
- description='Peaks:',
63
- disabled=False,
64
- layout=ipywidgets.Layout(width='200px'))
65
-
66
- side_bar[row, 2] = ipywidgets.Button(
67
- description='Smooth',
68
- disabled=False,
69
- button_style='', # 'success', 'info', 'warning', 'danger' or ''
70
- tooltip='Do Gaussian Mixing',
71
- layout=ipywidgets.Layout(width='100px'))
72
-
73
- row += 1
74
- side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Number:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
75
- side_bar[row, 2] = ipywidgets.Button(
76
- description='Find',
77
- disabled=False,
78
- button_style='', # 'success', 'info', 'warning', 'danger' or ''
79
- tooltip='Find first peaks from Gaussian mixture',
80
- layout=ipywidgets.Layout(width='100px'))
81
-
82
- row += 1
83
-
84
- side_bar[row, :3] = ipywidgets.Button(description='Peaks',
85
- layout=ipywidgets.Layout(width='auto', grid_area='header'),
86
- style=ipywidgets.ButtonStyle(button_color='lightblue'))
87
- row += 1
88
- side_bar[row, :2] = ipywidgets.Dropdown(
89
- options=[('Peak 1', 0), ('add peak', -1)],
90
- value=0,
91
- description='Peaks:',
92
- disabled=False,
93
- layout=ipywidgets.Layout(width='200px'))
94
- side_bar[row, 2] = ipywidgets.widgets.Label(value="", layout=ipywidgets.Layout(width='100px'))
95
- row += 1
96
- side_bar[row, :2] = ipywidgets.Dropdown(
97
- options=[ 'Gauss', 'Lorentzian', 'Drude', 'Zero-Loss'],
98
- value='Gauss',
99
- description='Symmetry:',
100
- disabled=False,
101
- layout=ipywidgets.Layout(width='200px'))
102
- row += 1
103
- side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Position:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
104
- side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='100px'))
105
- row += 1
106
- side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Amplitude:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
107
- side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='100px'))
108
- row += 1
109
- side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Width FWHM:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
110
- side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='100px'))
111
- row += 1
112
- side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Asymmetry:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
113
- side_bar[row, 2] = ipywidgets.widgets.Label(value="a.u.", layout=ipywidgets.Layout(width='100px'))
114
- row += 1
115
-
116
- side_bar[row, :3] = ipywidgets.Button(description='White-Line',
117
- layout=ipywidgets.Layout(width='auto', grid_area='header'),
118
- style=ipywidgets.ButtonStyle(button_color='lightblue'))
119
-
120
- row += 1
121
- side_bar[row, :2] = ipywidgets.Dropdown(
122
- options=[('None', 0)],
123
- value=0,
124
- description='Ratio:',
125
- disabled=False,
126
- layout=ipywidgets.Layout(width='200px'))
127
- side_bar[row, 2] = ipywidgets.widgets.Label(value=" ", layout=ipywidgets.Layout(width='100px'))
128
- row += 1
129
- side_bar[row, :2] = ipywidgets.Dropdown(
130
- options=[('None', 0)],
131
- value=0,
132
- description= 'Sum:',
133
- disabled=False,
134
- layout=ipywidgets.Layout(width='200px'))
135
- side_bar[row, 2] = ipywidgets.widgets.Label(value=" ", layout=ipywidgets.Layout(width='100px'))
136
- return side_bar
137
-
138
- class PeakFitWidget(object):
139
- def __init__(self, datasets, key):
140
- self.datasets = datasets
141
- if not isinstance(datasets, dict):
142
- raise TypeError('need dictioary of sidpy datasets')
143
-
144
- self.sidebar = get_sidebar()
145
- self.key = key
146
- self.dataset = datasets[self.key]
147
- if not isinstance(self.dataset, sidpy.Dataset):
148
- raise TypeError('dataset or first item inhas to be a sidpy dataset')
149
-
150
- self.model = np.array([])
151
- self.y_scale = 1.0
152
- self.change_y_scale = 1.0
153
- self.spectrum_ll = None
154
- self.low_loss_key = None
155
-
156
- self.peaks = {}
157
-
158
- self.show_regions = False
159
-
160
- self.set_dataset()
161
-
162
- self.app_layout = ipywidgets.AppLayout(
163
- left_sidebar=self.sidebar,
164
- center=self.view.panel,
165
- footer=None,#message_bar,
166
- pane_heights=[0, 10, 0],
167
- pane_widths=[4, 10, 0],
168
- )
169
- display(self.app_layout)
170
- self.set_action()
171
-
172
- def line_select_callback(self, x_min, x_max):
173
- self.start_cursor.value = np.round(x_min,3)
174
- self.end_cursor.value = np.round(x_max, 3)
175
- self.start_channel = np.searchsorted(self.datasets[self.key].energy_loss, self.start_cursor.value)
176
- self.end_channel = np.searchsorted(self.datasets[self.key].energy_loss, self.end_cursor.value)
177
-
178
-
179
- def set_peak_list(self):
180
- self.peak_list = []
181
- if 'peaks' not in self.peaks:
182
- self.peaks['peaks'] = {}
183
- key = 0
184
- for key in self.peaks['peaks']:
185
- if key.isdigit():
186
- self.peak_list.append((f'Peak {int(key) + 1}', int(key)))
187
- self.peak_list.append(('add peak', -1))
188
- #self.sidebar[7, 0].options = self.peak_list
189
- #self.sidebar[7, 0].value = 0
190
-
191
-
192
- def plot(self, scale=True):
193
-
194
- self.view.change_y_scale = self.change_y_scale
195
- self.view.y_scale = self.y_scale
196
- self.energy_scale = self.dataset.energy_loss.values
197
-
198
- if self.dataset.data_type == sidpy.DataType.SPECTRAL_IMAGE:
199
- spectrum = self.dataset.view.get_spectrum()
200
- else:
201
- spectrum = self.dataset
202
- #if 'features' in self.peaks:
203
- if 'resolution_function' in self.datasets.keys():
204
-
205
- zl = self.datasets['resolution_function'] # self.peaks['features']]
206
- additional_spectra = {}
207
- if len(self.model) > 1:
208
- additional_spectra = {'model': self.model,
209
- 'difference': spectrum-self.model,
210
- 'zero_loss': self.datasets['resolution_function']}
211
- else:
212
- additional_spectra = {}
213
- if 'peaks' in self.peaks:
214
- if len(self.peaks)>0:
215
- for index, peak in self.peaks['peaks'].items(): # ll
216
- p = [peak['position'], peak['amplitude'], peak['width']]
217
- additional_spectra[f'peak {index}']= gauss(np.array(self.energy_scale), p)
218
- self.view.plot(scale=True, additional_spectra=additional_spectra )
219
- self.change_y_scale = 1.
220
-
221
- self.view.figure.canvas.draw_idle()
222
-
223
-
224
- def set_dataset(self, index=0):
225
- self.spec_dim = ft.get_dimensions_by_type('spectral', self.dataset)
226
- if len(self.spec_dim) != 1:
227
- raise TypeError('We need exactly one SPECTRAL dimension')
228
- self.spec_dim = self.spec_dim[0]
229
- self.energy_scale = self.spec_dim[1]
230
-
231
- self.y_scale = 1.0
232
- self.change_y_scale = 1.0
233
-
234
- if 'peak_fit' not in self.dataset.metadata:
235
- self.dataset.metadata['peak_fit'] = {}
236
- if 'edges' in self.dataset.metadata:
237
- if 'fit_area' in self.dataset.metadata['edges']:
238
- self.dataset.metadata['peak_fit']['fit_start'] = self.dataset.metadata['edges']['fit_area']['fit_start']
239
- self.dataset.metadata['peak_fit']['fit_end'] = self.dataset.metadata['edges']['fit_area']['fit_end']
240
- self.dataset.metadata['peak_fit']['peaks'] = {'0': {'position': self.energy_scale[1],
241
- 'amplitude': 1000.0, 'width': 1.0,
242
- 'type': 'Gauss', 'asymmetry': 0}}
243
-
244
- self.peaks = self.dataset.metadata['peak_fit']
245
- if 'fit_start' not in self.peaks:
246
- self.peaks['fit_start'] = self.energy_scale[1]
247
- if 'fit_end' not in self.peaks:
248
- self.peaks['fit_end'] = self.energy_scale[-2]
249
-
250
- if 'peak_model' in self.peaks:
251
- self.peak_model = self.peaks['peak_model']
252
- self.model = self.peak_model
253
- if 'edge_model' in self.peaks:
254
- self.model = self.model + self.peaks['edge_model']
255
- else:
256
- self.model = np.array([])
257
- self.peak_model = np.array([])
258
- if 'peak_out_list' in self.peaks:
259
- self.peak_out_list = self.peaks['peak_out_list']
260
- self.set_peak_list()
261
-
262
- # check whether a core loss analysis has been done previously
263
- if not hasattr(self, 'core_loss') and 'edges' in self.dataset.metadata:
264
- self.core_loss = True
265
- else:
266
- self.core_loss = False
267
-
268
- self.update()
269
- if self.dataset.data_type.name =='SPECTRAL_IMAGE':
270
- self.view = eels_dialog_utilities.SIPlot(self.dataset)
271
- else:
272
- self.view = eels_dialog_utilities.SpectrumPlot(self.dataset)
273
- self.dataset.view = self.view
274
- #self.view.legend(loc='Upper Right')
275
- self.y_scale = 1.0
276
- self.change_y_scale = 1.0
277
-
278
- def set_fit_area(self, value):
279
-
280
- self.peaks['fit_start'] = self.sidebar[1, 0].value
281
- self.peaks['fit_end'] = self.sidebar[2, 0].value
282
-
283
- self.plot()
284
-
285
- def set_y_scale(self, value):
286
- self.change_y_scale = 1/self.y_scale
287
- if self.sidebar[12, 0].value:
288
- dispersion = self.energy_scale[1] - self.energy_scale[0]
289
- self.y_scale = 1/self.dataset.metadata['experiment']['flux_ppm'] * dispersion
290
- else:
291
- self.y_scale = 1.0
292
-
293
- self.change_y_scale *= self.y_scale
294
- self.update()
295
- self.plot()
296
-
297
- def update(self, index=0):
298
-
299
- # self.setWindowTitle('update')
300
- self.sidebar[1, 0].value = self.peaks['fit_start']
301
- self.sidebar[2, 0].value = self.peaks['fit_end']
302
-
303
- peak_index = self.sidebar[7, 0].value
304
- self.peak_index = self.sidebar[7, 0].value
305
- if str(peak_index) not in self.peaks['peaks']:
306
- self.peaks['peaks'][str(peak_index)] = {'position': self.energy_scale[1], 'amplitude': 1000.0,
307
- 'width': 1.0, 'type': 'Gauss', 'asymmetry': 0}
308
- self.sidebar[8, 0].value = self.peaks['peaks'][str(peak_index)]['type']
309
- if 'associated_edge' in self.peaks['peaks'][str(peak_index)]:
310
- self.sidebar[7, 2].value = (self.peaks['peaks'][str(peak_index)]['associated_edge'])
311
- else:
312
- self.sidebar[7, 2].value = ''
313
- self.sidebar[9, 0].value = self.peaks['peaks'][str(peak_index)]['position']
314
- self.sidebar[10, 0].value = self.peaks['peaks'][str(peak_index)]['amplitude']
315
- self.sidebar[11, 0].value = self.peaks['peaks'][str(peak_index)]['width']
316
- if 'asymmetry' not in self.peaks['peaks'][str(peak_index)]:
317
- self.peaks['peaks'][str(peak_index)]['asymmetry'] = 0.
318
- self.sidebar[12, 0].value = self.peaks['peaks'][str(peak_index)]['asymmetry']
319
-
320
-
321
- def get_input(self):
322
- p_in = []
323
- for key, peak in self.peaks['peaks'].items():
324
- if key.isdigit():
325
- p_in.append(peak['position'])
326
- p_in.append(peak['amplitude'])
327
- p_in.append(peak['width'])
328
- return p_in
329
-
330
-
331
- def fit_peaks(self, value=0):
332
- """Fit spectrum with peaks given in peaks dictionary"""
333
- # print('Fitting peaks...')
334
-
335
- if self.dataset.data_type.name == 'SPECTRUM':
336
- spectrum = np.array(self.dataset)
337
- else:
338
- spectrum = self.dataset.view.get_spectrum()
339
- spectrum -= spectrum.min() - 1
340
- # set the energy scale and fit start and end points
341
- energy_scale = np.array(self.energy_scale)
342
- start_channel = np.searchsorted(energy_scale, self.peaks['fit_start'])
343
- end_channel = np.searchsorted(energy_scale, self.peaks['fit_end'])
344
-
345
- energy_scale = self.energy_scale[start_channel:end_channel]
346
- # select the core loss model if it exists. Otherwise, we will fit to the full spectrum.
347
- if 'model' in self.dataset.metadata:
348
- model = self.dataset.metadata['model'][start_channel:end_channel]
349
- elif self.core_loss:
350
- # print('Core loss model found. Fitting on top of the model.')
351
- model = self.dataset.metadata['edges']['model']['spectrum'][start_channel:end_channel]
352
- else:
353
-
354
- # print('No core loss model found. Fitting to the full spectrum.')
355
- model = np.zeros(end_channel - start_channel)
356
-
357
- # if we have a core loss model we will only fit the difference between the model and the data.
358
- difference = np.array(spectrum[start_channel:end_channel] - model)
359
- p_in = self.get_input()
360
- # find the optimum fitting parameters
361
- #[self.p_out, _] = scipy.optimize.leastsq(eels_tools.residuals_smooth, np.array(p_in), ftol=1e-3,
362
- # args=(energy_scale, difference, False))
363
-
364
- [self.p_out, _] = scipy.optimize.leastsq(eels_tools.residuals3, np.array(p_in, dtype=np.float64),
365
- args=(energy_scale, difference) ) # , False))
366
- # construct the fit data from the optimized parameters
367
- #self.peak_model = np.zeros(len(self.energy_scale))
368
- #self.model = np.zeros(len(self.energy_scale))
369
- #self.model[start_channel:end_channel] = model
370
- #fit = eels_tools.model_smooth(energy_scale, self.p_out, False)
371
- fit = eels_tools.gmm(energy_scale, self.p_out) # , False)
372
- self.peak_model = fit
373
-
374
- #self.peak_model[start_channel:end_channel] = fit
375
- #self.dataset.metadata['peak_fit']['edge_model'] = self.model
376
- #self.model = self.model + self.peak_model
377
- #self.dataset.metadata['peak_fit']['peak_model'] = self.peak_model
378
-
379
- for key, peak in self.peaks['peaks'].items():
380
- if key.isdigit():
381
- p_index = int(key)*3
382
- self.peaks['peaks'][key] = {'position': self.p_out[p_index],
383
- 'amplitude': self.p_out[p_index+1],
384
- 'width': self.p_out[p_index+2],
385
- 'type': 'Gauss',
386
- 'associated_edge': ''}
387
-
388
- eels_tools.find_associated_edges(self.dataset)
389
- self.find_white_lines()
390
- self.update()
391
- self.plot()
392
-
393
-
394
-
395
- def find_white_lines(self):
396
- eels_tools.find_white_lines(self.dataset)
397
- self.wl_list = []
398
- self.wls_list = []
399
- if 'white_line_ratios' in self.dataset.metadata['peak_fit']:
400
- if len(self.dataset.metadata['peak_fit']['white_line_ratios']) > 0:
401
- for key in self.dataset.metadata['peak_fit']['white_line_ratios']:
402
- self.wl_list.append(key)
403
- for key in self.dataset.metadata['peak_fit']['white_line_sums']:
404
- self.wls_list.append(key)
405
-
406
- self.sidebar[14, 0].options = self.wl_list
407
- self.sidebar[14, 0].value = self.wl_list[0]
408
- self.sidebar[14, 2].value = f"{self.dataset.metadata['peak_fit']['white_line_ratios'][self.wl_list[0]]:.2f}"
409
-
410
- self.sidebar[15, 0].options = self.wls_list
411
- self.sidebar[15, 0].value = self.wls_list[0]
412
- self.sidebar[15, 2].value = f"{self.dataset.metadata['peak_fit']['white_line_sums'][self.wls_list[0]]*1e6:.4f} ppm"
413
-
414
- else:
415
- self.wl_list.append('Ratio')
416
- self.wls_list.append('Sum')
417
-
418
- self.sidebar[14, 0].options = ['None']
419
- self.sidebar[14, 0].value = 'None'
420
- self.sidebar[14, 2].value = ' '
421
-
422
- self.sidebar[15, 0].options = ['None']
423
- self.sidebar[15, 0].value = 'None'
424
- self.sidebar[15, 2].value = ' '
425
-
426
- def find_peaks(self, value=0):
427
- number_of_peaks = int(self.sidebar[5, 0].value)
428
- if number_of_peaks > len(self.peak_out_list):
429
- number_of_peaks = len(self.peak_out_list)
430
- self.sidebar[5, 0].value = str(len(self.peak_out_list))
431
- self.peak_list = []
432
- self.peaks['peaks'] = {}
433
- new_number_of_peaks = 0
434
-
435
- peaks, prop = scipy.signal.find_peaks(self.peak_model, width=5)
436
- print(len(peaks), number_of_peaks, len(peaks)>= number_of_peaks)
437
- if len(peaks) >= number_of_peaks:
438
- if self.dataset.data_type.name == 'SPECTRUM':
439
- spectrum = np.array(self.dataset)
440
- else:
441
- spectrum = self.dataset.view.get_spectrum()
442
- for i in range(number_of_peaks):
443
- self.peak_list.append((f'Peak {i+1}', i))
444
- p = [self.energy_scale[peaks[i]], np.float32(spectrum[peaks[i]]), np.sqrt(prop['widths'][i])]
445
- if p[1]>0:
446
- self.peaks['peaks'][str(new_number_of_peaks)] = {'position': p[0], 'amplitude': p[1], 'width': p[2], 'type': 'Gauss',
447
- 'asymmetry': 0}
448
- new_number_of_peaks += 1
449
- else:
450
- for i in range(number_of_peaks):
451
- self.peak_list.append((f'Peak {i+1}', i))
452
- p = self.peak_out_list[i]
453
- if p[1]>0:
454
- self.peaks['peaks'][str(new_number_of_peaks)] = {'position': p[0], 'amplitude': p[1], 'width': p[2], 'type': 'Gauss',
455
- 'asymmetry': 0}
456
- new_number_of_peaks += 1
457
- self.sidebar[5, 0].value = str(new_number_of_peaks)
458
- self.peak_list.append((f'add peak', -1))
459
-
460
- self.sidebar[7, 0].options = self.peak_list
461
- self.sidebar[7, 0].value = 0
462
-
463
- #eels_tools.find_associated_edges(self.dataset)
464
- #self.find_white_lines()
465
-
466
- self.update()
467
- self.plot()
468
-
469
- def smooth(self, value=0):
470
- """Fit lots of Gaussian to spectrum and let the program sort it out
471
-
472
- We sort the peaks by area under the Gaussians, assuming that small areas mean noise.
473
-
474
- """
475
- iterations = self.sidebar[4, 0].value
476
- self.sidebar[5, 0].value = 0
477
-
478
- if self.key == self.datasets['_relationship']['low_loss']:
479
- if 'resolution_function' in self.datasets['_relationship'].keys():
480
- self.model = np.array(self.datasets['resolution_function'])
481
-
482
-
483
- self.peak_model, self.peak_out_list, number_of_peaks = smooth(self.dataset-self.model, iterations, advanced_present)
484
-
485
- spec_dim = ft.get_dimensions_by_type('SPECTRAL', self.dataset)[0]
486
- if spec_dim[1][0] > 0:
487
- self.model = self.dataset.metadata['edges']['model']['spectrum']
488
- elif 'model' in self.dataset.metadata:
489
- self.model = self.dataset.metadata['model']
490
- else:
491
- self.model = np.zeros(len(spec_dim[1]))
492
-
493
- self.dataset.metadata['peak_fit']['edge_model'] = self.model
494
- self.model = self.model + self.peak_model
495
- self.dataset.metadata['peak_fit']['peak_model'] = self.peak_model
496
- self.dataset.metadata['peak_fit']['peak_out_list'] = self.peak_out_list
497
-
498
- peaks, prop = scipy.signal.find_peaks(self.peak_model, width=5)
499
-
500
- self.sidebar[5, 0].value = str(len(peaks))
501
- self.update()
502
- self.plot()
503
-
504
- def make_model(self):
505
- p_peaks = []
506
- for key, peak in self.peaks['peaks'].items():
507
- if key.isdigit():
508
- p_peaks.append(peak['position'])
509
- p_peaks.append(peak['amplitude'])
510
- p_peaks.append(peak['width'])
511
-
512
-
513
- # set the energy scale and fit start and end points
514
- energy_scale = np.array(self.energy_scale)
515
- start_channel = np.searchsorted(energy_scale, self.peaks['fit_start'])
516
- end_channel = np.searchsorted(energy_scale, self.peaks['fit_end'])
517
- energy_scale = self.energy_scale # [start_channel:end_channel]
518
- # select the core loss model if it exists. Otherwise, we will fit to the full spectrum.
519
-
520
- p_peaks = np.array(p_peaks, dtype=np.float64)
521
-
522
- fit = eels_tools.gmm(energy_scale, p_peaks) # , False)
523
- self.peak_model = fit
524
- #self.peak_model[start_channel:end_channel] = fit
525
- """if 'edge_model' in self.dataset.metadata['peak_fit']:
526
- self.model = self.dataset.metadata['peak_fit']['edge_model'] + self.peak_model
527
- else:
528
- self.model = np.zeros(self.dataset.shape)
529
- """
530
- self.model = fit
531
-
532
- def modify_peak_position(self, value=-1):
533
- peak_index = self.sidebar[7, 0].value
534
- self.peaks['peaks'][str(peak_index)]['position'] = self.sidebar[9,0].value
535
- self.make_model()
536
- self.plot()
537
-
538
- def modify_peak_amplitude(self, value=-1):
539
- peak_index = self.sidebar[7, 0].value
540
- self.peaks['peaks'][str(peak_index)]['amplitude'] = self.sidebar[10,0].value
541
- self.make_model()
542
- self.plot()
543
-
544
- def modify_peak_width(self, value=-1):
545
- peak_index = self.sidebar[7, 0].value
546
- self.peaks['peaks'][str(peak_index)]['width'] = self.sidebar[11,0].value
547
- self.make_model()
548
- self.plot()
549
-
550
- def peak_selection(self, change=None):
551
- options = list(self.sidebar[7,0].options)
552
-
553
- if self.sidebar[7, 0].value < 0:
554
- options.insert(-1, (f'Peak {len(options)}', len(options)-1))
555
- self.sidebar[7, 0].value = 0
556
- self.sidebar[7,0].options = options
557
- self.sidebar[7, 0].value = int(len(options)-2)
558
-
559
- self.update()
560
-
561
- def set_action(self):
562
- self.sidebar[1, 0].observe(self.set_fit_area, names='value')
563
- self.sidebar[2, 0].observe(self.set_fit_area, names='value')
564
-
565
- self.sidebar[4, 2].on_click(self.smooth)
566
- self.sidebar[7,0].observe(self.peak_selection)
567
- self.sidebar[5,2].on_click(self.find_peaks)
568
-
569
- self.sidebar[6, 0].on_click(self.fit_peaks)
570
- self.sidebar[9, 0].observe(self.modify_peak_position, names='value')
571
- self.sidebar[10, 0].observe(self.modify_peak_amplitude, names='value')
572
- self.sidebar[11, 0].observe(self.modify_peak_width, names='value')
573
-
574
-
575
-
576
-
577
- if Qt_available:
578
- class PeakFitDialog(QtWidgets.QDialog):
579
- """
580
- EELS Input Dialog for ELNES Analysis
581
- """
582
-
583
- def __init__(self, datasets=None):
584
- super().__init__(None, QtCore.Qt.WindowStaysOnTopHint)
585
-
586
- if datasets is None:
587
- # make a dummy dataset
588
- datasets = ft.make_dummy_dataset('spectrum')
589
- if not isinstance(datasets, dict):
590
- datasets= {'Channel_000': datasets}
591
-
592
- self.dataset = datasets[list(datasets.keys())[0]]
593
- self.datasets = datasets
594
- # Create an instance of the GUI
595
- if 'low_loss' in self.dataset.metadata:
596
- mode = 'low_loss'
597
- else:
598
- mode = 'core_loss'
599
-
600
- self.ui = peak_dlg.UiDialog(self, mode=mode)
601
-
602
- self.set_action()
603
-
604
- self.energy_scale = np.array([])
605
- self.peak_out_list = []
606
- self.p_out = []
607
- self.axis = None
608
- self.show_regions = False
609
- self.show()
610
-
611
-
612
-
613
- if not isinstance(self.dataset, sidpy.Dataset):
614
- raise TypeError('dataset has to be a sidpy dataset')
615
- self.spec_dim = ft.get_dimensions_by_type('spectral', self.dataset)
616
- if len(self.spec_dim) != 1:
617
- raise TypeError('We need exactly one SPECTRAL dimension')
618
- self.spec_dim = self.spec_dim[0]
619
- self.energy_scale = self.spec_dim[1].values.copy()
620
-
621
- if 'peak_fit' not in self.dataset.metadata:
622
- self.dataset.metadata['peak_fit'] = {}
623
- if 'edges' in self.dataset.metadata:
624
- if 'fit_area' in self.dataset.metadata['edges']:
625
- self.dataset.metadata['peak_fit']['fit_start'] = \
626
- self.dataset.metadata['edges']['fit_area']['fit_start']
627
- self.dataset.metadata['peak_fit']['fit_end'] = self.dataset.metadata['edges']['fit_area']['fit_end']
628
- self.dataset.metadata['peak_fit']['peaks'] = {'0': {'position': self.energy_scale[1],
629
- 'amplitude': 1000.0, 'width': 1.0,
630
- 'type': 'Gauss', 'asymmetry': 0}}
631
-
632
-
633
- self.peaks = self.dataset.metadata['peak_fit']
634
- if 'fit_start' not in self.peaks:
635
- self.peaks['fit_start'] = self.energy_scale[1]
636
- self.peaks['fit_end'] = self.energy_scale[-2]
637
-
638
- if 'peak_model' in self.peaks:
639
- self.peak_model = self.peaks['peak_model']
640
- self.model = self.peak_model
641
- if 'edge_model' in self.peaks:
642
- self.model = self.model + self.peaks['edge_model']
643
- else:
644
- self.model = np.array([])
645
- self.peak_model = np.array([])
646
- if 'peak_out_list' in self.peaks:
647
- self.peak_out_list = self.peaks['peak_out_list']
648
- self.set_peak_list()
649
-
650
- # check whether a core loss analysis has been done previously
651
- if not hasattr(self, 'core_loss') and 'edges' in self.dataset.metadata:
652
- self.core_loss = True
653
- else:
654
- self.core_loss = False
655
-
656
- self.update()
657
- self.dataset.plot()
658
-
659
- if self.dataset.data_type.name == 'SPECTRAL_IMAGE':
660
- if 'SI_bin_x' not in self.dataset.metadata['experiment']:
661
- self.dataset.metadata['experiment']['SI_bin_x'] = 1
662
- self.dataset.metadata['experiment']['SI_bin_y'] = 1
663
- bin_x = self.dataset.metadata['experiment']['SI_bin_x']
664
- bin_y = self.dataset.metadata['experiment']['SI_bin_y']
665
-
666
- self.dataset.view.set_bin([bin_x, bin_y])
667
-
668
- if hasattr(self.dataset.view, 'axes'):
669
- self.axis = self.dataset.view.axes[-1]
670
- elif hasattr(self.dataset.view, 'axis'):
671
- self.axis = self.dataset.view.axis
672
- self.figure = self.axis.figure
673
-
674
- if not advanced_present:
675
- self.ui.iteration_list = ['0']
676
- self.ui.smooth_list.clear()
677
- self.ui.smooth_list.addItems(self.ui.iteration_list)
678
- self.ui.smooth_list.setCurrentIndex(0)
679
-
680
- if 'low_loss' in self.dataset.metadata:
681
- self.ui.iteration_list = ['0']
682
-
683
-
684
- self.figure.canvas.mpl_connect('button_press_event', self.plot)
685
-
686
-
687
- self.plot()
688
-
689
- def update(self):
690
- # self.setWindowTitle('update')
691
- self.ui.edit1.setText(f"{self.peaks['fit_start']:.2f}")
692
- self.ui.edit2.setText(f"{self.peaks['fit_end']:.2f}")
693
-
694
- peak_index = self.ui.list3.currentIndex()
695
- if str(peak_index) not in self.peaks['peaks']:
696
- self.peaks['peaks'][str(peak_index)] = {'position': self.energy_scale[1], 'amplitude': 1000.0,
697
- 'width': 1.0, 'type': 'Gauss', 'asymmetry': 0}
698
- self.ui.list4.setCurrentText(self.peaks['peaks'][str(peak_index)]['type'])
699
- if 'associated_edge' in self.peaks['peaks'][str(peak_index)]:
700
- self.ui.unit3.setText(self.peaks['peaks'][str(peak_index)]['associated_edge'])
701
- else:
702
- self.ui.unit3.setText('')
703
- self.ui.edit5.setText(f"{self.peaks['peaks'][str(peak_index)]['position']:.2f}")
704
- self.ui.edit6.setText(f"{self.peaks['peaks'][str(peak_index)]['amplitude']:.2f}")
705
- self.ui.edit7.setText(f"{self.peaks['peaks'][str(peak_index)]['width']:.2f}")
706
- if 'asymmetry' not in self.peaks['peaks'][str(peak_index)]:
707
- self.peaks['peaks'][str(peak_index)]['asymmetry'] = 0.
708
- self.ui.edit8.setText(f"{self.peaks['peaks'][str(peak_index)]['asymmetry']:.2f}")
709
-
710
- def plot(self):
711
-
712
- spec_dim = ft.get_dimensions_by_type(sidpy.DimensionType.SPECTRAL, self.dataset)
713
- spec_dim = spec_dim[0]
714
- self.energy_scale = spec_dim[1].values
715
- if self.dataset.data_type == sidpy.DataType.SPECTRAL_IMAGE:
716
- spectrum = self.dataset.view.get_spectrum()
717
- self.axis = self.dataset.view.axes[1]
718
- name = 's'
719
- if 'zero_loss' in self.dataset.metadata:
720
- x = self.dataset.view.x
721
- y = self.dataset.view.y
722
- self.energy_scale -= self.dataset.metadata['zero_loss']['shifts'][x, y]
723
- name = f"shift { self.dataset.metadata['zero_loss']['shifts'][x, y]:.3f}"
724
- self.setWindowTitle(f'plot {x}')
725
- else:
726
- spectrum = np.array(self.dataset)
727
- self.axis = self.dataset.view.axis
728
-
729
- x_limit = self.axis.get_xlim()
730
- y_limit = self.axis.get_ylim()
731
- self.axis.clear()
732
-
733
- self.axis.plot(self.energy_scale, spectrum, label='spectrum')
734
- #if 'features' in self.peaks:
735
- zl = self.datasets[self.peaks['features']]
736
- self.axis.plot(self.energy_scale, zl, label='zero_loss')
737
-
738
- if len(self.model) > 1:
739
- self.axis.plot(self.energy_scale, self.model, label='model')
740
- self.axis.plot(self.energy_scale, spectrum - self.model, label='difference')
741
- #self.axis.plot(self.energy_scale, (spectrum - self.model) / np.sqrt(spectrum), label='Poisson')
742
-
743
- self.axis.set_xlim(x_limit)
744
- self.axis.set_ylim(y_limit)
745
-
746
- for index, peak in self.peaks['peaks'].items():
747
- p = [peak['position'], peak['amplitude'], peak['width']]
748
- self.axis.plot(self.energy_scale, eels_tools.gauss(self.energy_scale, p))
749
- self.axis.legend(loc="upper right")
750
- self.axis.figure.canvas.draw_idle()
751
-
752
- def fit_peaks(self):
753
- """Fit spectrum with peaks given in peaks dictionary"""
754
- print('Fitting peaks...')
755
- p_in = []
756
- for key, peak in self.peaks['peaks'].items():
757
- if key.isdigit():
758
- p_in.append(peak['position'])
759
- p_in.append(peak['amplitude'])
760
- p_in.append(peak['width'])
761
-
762
- # check whether we have a spectral image or just a single spectrum
763
- if self.dataset.data_type == sidpy.DataType.SPECTRAL_IMAGE:
764
- spectrum = self.dataset.view.get_spectrum()
765
- else:
766
- spectrum = np.array(self.dataset)
767
- spectrum -= spectrum.min()-1
768
- # set the energy scale and fit start and end points
769
- energy_scale = np.array(self.energy_scale)
770
- """start_channel = np.searchsorted(energy_scale, self.peaks['fit_start'])
771
- end_channel = np.searchsorted(energy_scale, self.peaks['fit_end'])
772
-
773
- energy_scale = self.energy_scale[start_channel:end_channel]
774
- # select the core loss model if it exists. Otherwise, we will fit to the full spectrum.
775
- if 'model' in self.dataset.metadata:
776
- model = self.dataset.metadata['model'][start_channel:end_channel]
777
- elif self.core_loss:
778
- print('Core loss model found. Fitting on top of the model.')
779
- model = self.dataset.metadata['edges']['model']['spectrum'][start_channel:end_channel]
780
- else:
781
- print('No core loss model found. Fitting to the full spectrum.')
782
- model = np.zeros(end_channel - start_channel)
783
-
784
- # if we have a core loss model we will only fit the difference between the model and the data.
785
-
786
-
787
- difference = np.array(spectrum[start_channel:end_channel] - model)
788
- """
789
- difference = spectrum
790
- if self.key == self.datasets['_relationships']['low_loss']:
791
- if 'resolution_function' in self.datasets['_relationships'].keys():
792
- difference -= np.array(self.datasets['_relationships']['resolution_function'])
793
- self.peaks['peaks']['features'] = 'resolution_function'
794
- self.model = np.array(self.datasets['_relationships']['resolution_function'])
795
-
796
- # find the optimum fitting parameters
797
- [self.p_out, _] = scipy.optimize.leastsq(eels_tools.residuals3, np.array(p_in), ftol=1e-3,
798
- args=(energy_scale, difference, False))
799
-
800
- # construct the fit data from the optimized parameters
801
- #self.peak_model = np.zeros(len(self.energy_scale))
802
- #self.model = np.zeros(len(self.energy_scale))
803
- #self.model[start_channel:end_channel] = model
804
- fit = eels_tools.gmm(energy_scale, self.p_out, False)
805
- self.peak_model = fit
806
- #self.peak_model[start_channel:end_channel] = fit
807
- #self.dataset.metadata['peak_fit']['edge_model'] = self.model
808
- self.model = self.model + self.peak_model
809
- self.dataset.metadata['peak_fit']['peak_model'] = self.peak_model
810
-
811
- for key, peak in self.peaks['peaks'].items():
812
- if key.isdigit():
813
- p_index = int(key)*3
814
- self.peaks['peaks'][key] = {'position': self.p_out[p_index],
815
- 'amplitude': self.p_out[p_index+1],
816
- 'width': self.p_out[p_index+2],
817
- 'associated_edge': ''}
818
-
819
- self.find_associated_edges()
820
- self.find_white_lines()
821
- self.update()
822
- self.plot()
823
-
824
- def smooth(self):
825
- """Fit lots of Gaussian to spectrum and let the program sort it out
826
-
827
- We sort the peaks by area under the Gaussians, assuming that small areas mean noise.
828
-
829
- """
830
- if 'edges' in self.dataset.metadata:
831
- if 'model' in self.dataset.metadata['edges']:
832
- self.dataset.metadata['model'] = self.dataset.metadata['edges']['model']
833
- if 'resolution_function' in self.datasets:
834
- self.dataset.metadata['model'] = np.array(self.datasets['resolution_function'])
835
- iterations = int(self.ui.smooth_list.currentIndex())
836
-
837
- if self.key == self.datasets['_relationships']['low_loss']:
838
- if 'resolution_function' in self.datasets['_relationships'].keys():
839
- self.model = np.array(self.datasets['_relationships']['resolution_function'])
840
-
841
-
842
- self.peak_model, self.peak_out_list, number_of_peaks = smooth(self.dataset-self.model, iterations, advanced_present)
843
-
844
- spec_dim = ft.get_dimensions_by_type('SPECTRAL', self.dataset)[0]
845
- if spec_dim[1][0] > 0:
846
- self.model = self.dataset.metadata['edges']['model']['spectrum']
847
- elif 'model' in self.dataset.metadata:
848
- self.model = self.dataset.metadata['model']
849
- else:
850
- self.model = np.zeros(len(spec_dim[1]))
851
-
852
- self.ui.find_edit.setText(str(number_of_peaks))
853
-
854
- self.dataset.metadata['peak_fit']['edge_model'] = self.model
855
- self.model = self.model + self.peak_model
856
- self.dataset.metadata['peak_fit']['peak_model'] = self.peak_model
857
- self.dataset.metadata['peak_fit']['peak_out_list'] = self.peak_out_list
858
-
859
- self.update()
860
- self.plot()
861
-
862
- def find_associated_edges(self):
863
- onsets = []
864
- edges = []
865
- if 'edges' in self.dataset.metadata:
866
- for key, edge in self.dataset.metadata['edges'].items():
867
- if key.isdigit():
868
- element = edge['element']
869
- for sym in edge['all_edges']: # TODO: Could be replaced with exclude
870
- onsets.append(edge['all_edges'][sym]['onset'] + edge['chemical_shift'])
871
- # if 'sym' == edge['symmetry']:
872
- edges.append([key, f"{element}-{sym}", onsets[-1]])
873
- for key, peak in self.peaks['peaks'].items():
874
- if key.isdigit():
875
- distance = self.energy_scale[-1]
876
- index = -1
877
- for ii, onset in enumerate(onsets):
878
- if onset < peak['position'] < onset+50:
879
- if distance > np.abs(peak['position'] - onset):
880
- distance = np.abs(peak['position'] - onset) # TODO: check whether absolute is good
881
- distance_onset = peak['position'] - onset
882
- index = ii
883
- if index >= 0:
884
- peak['associated_edge'] = edges[index][1] # check if more info is necessary
885
- peak['distance_to_onset'] = distance_onset
886
-
887
- def find_white_lines(self):
888
- eels_tools.find_white_lines(self.dataset)
889
-
890
- self.ui.wl_list = []
891
- self.ui.wls_list = []
892
- if len(self.peaks['white_line_ratios']) > 0:
893
- for key in self.peaks['white_line_ratios']:
894
- self.ui.wl_list.append(key)
895
- for key in self.peaks['white_line_sums']:
896
- self.ui.wls_list.append(key)
897
-
898
- self.ui.listwl.clear()
899
- self.ui.listwl.addItems(self.ui.wl_list)
900
- self.ui.listwl.setCurrentIndex(0)
901
- self.ui.unitswl.setText(f"{self.peaks['white_line_ratios'][self.ui.wl_list[0]]:.2f}")
902
-
903
- self.ui.listwls.clear()
904
- self.ui.listwls.addItems(self.ui.wls_list)
905
- self.ui.listwls.setCurrentIndex(0)
906
- self.ui.unitswls.setText(f"{self.peaks['white_line_sums'][self.ui.wls_list[0]]*1e6:.4f} ppm")
907
- else:
908
- self.ui.wl_list.append('Ratio')
909
- self.ui.wls_list.append('Sum')
910
-
911
- self.ui.listwl.clear()
912
- self.ui.listwl.addItems(self.ui.wl_list)
913
- self.ui.listwl.setCurrentIndex(0)
914
- self.ui.unitswl.setText('')
915
-
916
- self.ui.listwls.clear()
917
- self.ui.listwls.addItems(self.ui.wls_list)
918
- self.ui.listwls.setCurrentIndex(0)
919
- self.ui.unitswls.setText('')
920
-
921
- def find_peaks(self):
922
- number_of_peaks = int(str(self.ui.find_edit.displayText()).strip())
923
-
924
- # is now sorted in smooth function
925
- # flat_list = [item for sublist in self.peak_out_list for item in sublist]
926
- # new_list = np.reshape(flat_list, [len(flat_list) // 3, 3])
927
- # arg_list = np.argsort(np.abs(new_list[:, 1]))
928
-
929
- self.ui.peak_list = []
930
- self.peaks['peaks'] = {}
931
- for i in range(number_of_peaks):
932
- self.ui.peak_list.append(f'Peak {i+1}')
933
- p = self.peak_out_list[i]
934
- self.peaks['peaks'][str(i)] = {'position': p[0], 'amplitude': p[1], 'width': p[2], 'type': 'Gauss',
935
- 'asymmetry': 0}
936
-
937
- self.ui.peak_list.append(f'add peak')
938
- self.ui.list3.clear()
939
- self.ui.list3.addItems(self.ui.peak_list)
940
- self.ui.list3.setCurrentIndex(0)
941
- self.find_associated_edges()
942
- self.find_white_lines()
943
-
944
- self.update()
945
- self.plot()
946
-
947
- def set_peak_list(self):
948
- self.ui.peak_list = []
949
- if 'peaks' not in self.peaks:
950
- self.peaks['peaks'] = {}
951
- key = 0
952
- for key in self.peaks['peaks']:
953
- if key.isdigit():
954
- self.ui.peak_list.append(f'Peak {int(key) + 1}')
955
- self.ui.find_edit.setText(str(int(key) + 1))
956
- self.ui.peak_list.append(f'add peak')
957
- self.ui.list3.clear()
958
- self.ui.list3.addItems(self.ui.peak_list)
959
- self.ui.list3.setCurrentIndex(0)
960
-
961
- def on_enter(self):
962
- if self.sender() == self.ui.edit1:
963
- value = float(str(self.ui.edit1.displayText()).strip())
964
- if value < self.energy_scale[0]:
965
- value = self.energy_scale[0]
966
- if value > self.energy_scale[-5]:
967
- value = self.energy_scale[-5]
968
- self.peaks['fit_start'] = value
969
- self.ui.edit1.setText(str(self.peaks['fit_start']))
970
- elif self.sender() == self.ui.edit2:
971
- value = float(str(self.ui.edit2.displayText()).strip())
972
- if value < self.energy_scale[5]:
973
- value = self.energy_scale[5]
974
- if value > self.energy_scale[-1]:
975
- value = self.energy_scale[-1]
976
- self.peaks['fit_end'] = value
977
- self.ui.edit2.setText(str(self.peaks['fit_end']))
978
- elif self.sender() == self.ui.edit5:
979
- value = float(str(self.ui.edit5.displayText()).strip())
980
- peak_index = self.ui.list3.currentIndex()
981
- self.peaks['peaks'][str(peak_index)]['position'] = value
982
- elif self.sender() == self.ui.edit6:
983
- value = float(str(self.ui.edit6.displayText()).strip())
984
- peak_index = self.ui.list3.currentIndex()
985
- self.peaks['peaks'][str(peak_index)]['amplitude'] = value
986
- elif self.sender() == self.ui.edit7:
987
- value = float(str(self.ui.edit7.displayText()).strip())
988
- peak_index = self.ui.list3.currentIndex()
989
- self.peaks['peaks'][str(peak_index)]['width'] = value
990
-
991
- def on_list_enter(self):
992
- self.setWindowTitle(f'list {self.sender}, {self.ui.list_model}')
993
- if self.sender() == self.ui.list3:
994
- if self.ui.list3.currentText().lower() == 'add peak':
995
- peak_index = self.ui.list3.currentIndex()
996
- self.ui.list3.insertItem(peak_index, f'Peak {peak_index+1}')
997
- self.peaks['peaks'][str(peak_index+1)] = {'position': self.energy_scale[1],
998
- 'amplitude': 1000.0, 'width': 1.0,
999
- 'type': 'Gauss', 'asymmetry': 0}
1000
- self.ui.list3.setCurrentIndex(peak_index)
1001
- self.update()
1002
-
1003
- elif self.sender() == self.ui.listwls or self.sender() == self.ui.listwl:
1004
- wl_index = self.sender().currentIndex()
1005
-
1006
- self.ui.listwl.setCurrentIndex(wl_index)
1007
- self.ui.unitswl.setText(f"{self.peaks['white_line_ratios'][self.ui.wl_list[wl_index]]:.2f}")
1008
- self.ui.listwls.setCurrentIndex(wl_index)
1009
- self.ui.unitswls.setText(f"{self.peaks['white_line_sums'][self.ui.wls_list[wl_index]] * 1e6:.4f} ppm")
1010
- elif self.sender() == self.ui.list_model:
1011
- self.setWindowTitle('list 1')
1012
- if self.sender().currentIndex() == 1:
1013
- if 'resolution_function' in self.datasets:
1014
- self.setWindowTitle('list 2')
1015
- self.dataset.metadata['model'] = np.array(self.datasets['resolution_function'])
1016
- else:
1017
- self.ui.list_model.setCurrentIndex(0)
1018
- else:
1019
- self.ui.list_model.setCurrentIndex(0)
1020
- def set_action(self):
1021
- pass
1022
- self.ui.edit1.editingFinished.connect(self.on_enter)
1023
- self.ui.edit2.editingFinished.connect(self.on_enter)
1024
- self.ui.edit5.editingFinished.connect(self.on_enter)
1025
- self.ui.edit6.editingFinished.connect(self.on_enter)
1026
- self.ui.edit7.editingFinished.connect(self.on_enter)
1027
- self.ui.edit8.editingFinished.connect(self.on_enter)
1028
- self.ui.list3.activated[str].connect(self.on_list_enter)
1029
- self.ui.find_button.clicked.connect(self.find_peaks)
1030
- self.ui.smooth_button.clicked.connect(self.smooth)
1031
- self.ui.fit_button.clicked.connect(self.fit_peaks)
1032
- if hasattr(self.ui, 'listwls'):
1033
- self.ui.listwls.activated[str].connect(self.on_list_enter)
1034
- self.ui.listwl.activated[str].connect(self.on_list_enter)
1035
- else:
1036
- self.ui.zl_button.clicked.connect(self.fit_zero_loss)
1037
- self.ui.drude_button.clicked.connect(self.smooth)
1038
- self.ui.list_model.activated[str].connect(self.on_list_enter)
1039
-
1040
- def fit_zero_loss(self):
1041
- """get shift of spectrum form zero-loss peak position"""
1042
- zero_loss_fit_width=0.3
1043
-
1044
- energy_scale = self.dataset.energy_loss
1045
- zl_dataset = self.dataset.copy()
1046
- zl_dataset.title = 'resolution_function'
1047
- shifts = np.zeros(self.dataset.shape[0:2])
1048
- zero_p = np.zeros([self.dataset.shape[0],self.dataset.shape[1],6])
1049
- fwhm_p = np.zeros(self.dataset.shape[0:2])
1050
- bin_x = bin_y = 1
1051
- total_spec = int(self.dataset.shape[0]/bin_x)*int(self.dataset.shape[1]/bin_y)
1052
- self.ui.progress.setMaximum(total_spec)
1053
- self.ui.progress.setValue(0)
1054
- zero_loss_fit_width=0.3
1055
- ind = 0
1056
- for x in range(self.dataset.shape[0]):
1057
- for y in range(self.dataset.shape[1]):
1058
- ind += 1
1059
- self.ui.progress.setValue(ind)
1060
- spectrum = self.dataset[x, y, :]
1061
- fwhm, delta_e = eels_tools.fix_energy_scale(spectrum, energy_scale)
1062
- z_loss, p_zl = eels_tools.resolution_function(energy_scale - delta_e, spectrum, zero_loss_fit_width)
1063
- fwhm2, delta_e2 = eels_tools.fix_energy_scale(z_loss, energy_scale - delta_e)
1064
- shifts[x, y] = delta_e + delta_e2
1065
- zero_p[x,y,:] = p_zl
1066
- zl_dataset[x,y] = z_loss
1067
- fwhm_p[x,y] = fwhm2
1068
-
1069
- zl_dataset.metadata['zero_loss'] = {'parameter': zero_p,
1070
- 'shifts': shifts,
1071
- 'fwhm': fwhm_p}
1072
- self.dataset.metadata['zero_loss'] = {'parameter': zero_p,
1073
- 'shifts': shifts,
1074
- 'fwhm': fwhm_p}
1075
-
1076
- self.datasets['resolution_function'] = zl_dataset
1077
- self.update()
1078
- self.plot()
1079
-
1080
-
1081
-
1082
- def smooth(dataset, iterations, advanced_present):
1083
- from pyTEMlib import advanced_eels_tools
1084
-
1085
- """Gaussian mixture model (non-Bayesian)
1086
-
1087
- Fit lots of Gaussian to spectrum and let the program sort it out
1088
- We sort the peaks by area under the Gaussians, assuming that small areas mean noise.
1089
-
1090
- """
1091
-
1092
- # TODO: add sensitivity to dialog and the two functions below
1093
- #peaks = dataset.metadata['peak_fit']
1094
-
1095
- #peak_model, peak_out_list = eels_tools.find_peaks(dataset, peaks['fit_start'], peaks['fit_end'])
1096
- peak_model, peak_out_list = eels_tools.gaussian_mixture_model(dataset, p_in=None)
1097
-
1098
- #
1099
- # if advanced_present and iterations > 1:
1100
- # peak_model, peak_out_list = advanced_eels_tools.smooth(dataset, peaks['fit_start'],
1101
- # peaks['fit_end'], iterations=iterations)
1102
- # else:
1103
- # peak_model, peak_out_list = eels_tools.find_peaks(dataset, peaks['fit_start'], peaks['fit_end'])
1104
- # peak_out_list = [peak_out_list]
1105
-
1106
- new_list = np.reshape(peak_out_list, [len(peak_out_list) // 3, 3])
1107
- area = np.sqrt(2 * np.pi) * np.abs(new_list[:, 1]) * np.abs(new_list[:, 2] / np.sqrt(2 * np.log(2)))
1108
- arg_list = np.argsort(area)[::-1]
1109
- area = area[arg_list]
1110
- peak_out_list = new_list[arg_list]
1111
-
1112
- number_of_peaks = np.searchsorted(area * -1, -np.average(area))
1113
-
1114
- return peak_model, peak_out_list, number_of_peaks
1115
-
1116
-
1117
- def gauss(x, p): # p[0]==mean, p[1]= amplitude p[2]==fwhm,
1118
- """Gaussian Function
1119
-
1120
- p[0]==mean, p[1]= amplitude p[2]==fwhm
1121
- area = np.sqrt(2* np.pi)* p[1] * np.abs(p[2] / 2.3548)
1122
- FWHM = 2 * np.sqrt(2 np.log(2)) * sigma = 2.3548 * sigma
1123
- sigma = FWHM/3548
1124
- """
1125
- if p[2] == 0:
1126
- return x * 0.
1127
- else:
1128
- return p[1] * np.exp(-(x - p[0]) ** 2 / (2.0 * (p[2] / 2.3548) ** 2))
1129
-