pyTEMlib 0.2023.4.0__py2.py3-none-any.whl → 0.2023.8.0__py2.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.
- pyTEMlib/crystal_tools.py +47 -5
- pyTEMlib/eels_dialog.py +656 -41
- pyTEMlib/eels_dialog_utilities.py +8 -4
- pyTEMlib/eels_dlg.py +4 -3
- pyTEMlib/eels_tools.py +93 -39
- pyTEMlib/file_tools.py +95 -13
- pyTEMlib/graph_tools.py +716 -10
- pyTEMlib/image_dialog.py +1 -1
- pyTEMlib/image_dlg.py +1 -1
- pyTEMlib/image_tools.py +82 -39
- pyTEMlib/info_dialog.py +356 -15
- pyTEMlib/info_dlg.py +1 -1
- pyTEMlib/info_widget.py +655 -0
- pyTEMlib/interactive_eels.py +12 -4
- pyTEMlib/peak_dialog.py +621 -22
- pyTEMlib/peak_dlg.py +1 -1
- pyTEMlib/version.py +2 -2
- pyTEMlib/viz.py +217 -0
- {pyTEMlib-0.2023.4.0.dist-info → pyTEMlib-0.2023.8.0.dist-info}/METADATA +5 -5
- pyTEMlib-0.2023.8.0.dist-info/RECORD +40 -0
- {pyTEMlib-0.2023.4.0.dist-info → pyTEMlib-0.2023.8.0.dist-info}/WHEEL +1 -1
- pyTEMlib-0.2023.4.0.dist-info/RECORD +0 -39
- {pyTEMlib-0.2023.4.0.dist-info → pyTEMlib-0.2023.8.0.dist-info}/LICENSE +0 -0
- {pyTEMlib-0.2023.4.0.dist-info → pyTEMlib-0.2023.8.0.dist-info}/entry_points.txt +0 -0
- {pyTEMlib-0.2023.4.0.dist-info → pyTEMlib-0.2023.8.0.dist-info}/top_level.txt +0 -0
pyTEMlib/eels_dialog.py
CHANGED
|
@@ -8,23 +8,24 @@ try:
|
|
|
8
8
|
from PyQt5 import QtCore, QtWidgets
|
|
9
9
|
except:
|
|
10
10
|
Qt_available = False
|
|
11
|
-
print('Qt dialogs are not available')
|
|
12
|
-
from pyTEMlib import eels_dlg
|
|
11
|
+
# print('Qt dialogs are not available')
|
|
13
12
|
|
|
14
|
-
import numpy as np
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
import numpy as np
|
|
17
15
|
|
|
16
|
+
import ipywidgets
|
|
17
|
+
import IPython.display
|
|
18
|
+
import matplotlib
|
|
18
19
|
import matplotlib.pylab as plt
|
|
19
20
|
import matplotlib.patches as patches
|
|
20
21
|
|
|
21
22
|
from pyTEMlib import file_tools as ft
|
|
23
|
+
from pyTEMlib import eels_tools as eels
|
|
22
24
|
|
|
23
25
|
import sidpy
|
|
24
26
|
|
|
25
|
-
_version = 000
|
|
26
|
-
|
|
27
27
|
if Qt_available:
|
|
28
|
+
from pyTEMlib import eels_dlg
|
|
28
29
|
from pyTEMlib import eels_dialog_utilities
|
|
29
30
|
|
|
30
31
|
class EELSDialog(QtWidgets.QDialog):
|
|
@@ -32,38 +33,48 @@ if Qt_available:
|
|
|
32
33
|
EELS Input Dialog for Chemical Analysis
|
|
33
34
|
"""
|
|
34
35
|
|
|
35
|
-
def __init__(self,
|
|
36
|
+
def __init__(self, datasets=None):
|
|
36
37
|
super().__init__(None, QtCore.Qt.WindowStaysOnTopHint)
|
|
37
38
|
# Create an instance of the GUI
|
|
38
|
-
if
|
|
39
|
+
if datasets is None:
|
|
39
40
|
# make a dummy dataset
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
datasets = {'Channel_000':ft.make_dummy_dataset(sidpy.DataType.SPECTRUM)}
|
|
42
|
+
elif isinstance(datasets, sidpy.Dataset):
|
|
43
|
+
datasets = {'Channel_000': datasets}
|
|
44
|
+
elif isinstance(datasets, dict):
|
|
45
|
+
pass
|
|
46
|
+
else:
|
|
47
|
+
raise TypeError('dataset or first item inhas to be a sidpy dataset')
|
|
48
|
+
self.datasets = datasets
|
|
49
|
+
self.dataset = datasets[list(datasets)[0]]
|
|
50
|
+
|
|
51
|
+
if not isinstance(self.dataset, sidpy.Dataset):
|
|
52
|
+
raise TypeError('dataset or first item inhas to be a sidpy dataset')
|
|
53
|
+
|
|
54
|
+
self.spec_dim = ft.get_dimensions_by_type('spectral', self.dataset)
|
|
44
55
|
if len(self.spec_dim) != 1:
|
|
45
56
|
raise TypeError('We need exactly one SPECTRAL dimension')
|
|
46
57
|
self.spec_dim = self.spec_dim[0]
|
|
47
|
-
|
|
58
|
+
|
|
48
59
|
self.ui = eels_dlg.UiDialog(self)
|
|
49
60
|
# Run the .setup_ui() method to show the GUI
|
|
50
61
|
# self.ui.setup_ui(self)
|
|
51
62
|
|
|
52
63
|
self.set_action()
|
|
53
64
|
|
|
54
|
-
self.dataset = dataset
|
|
55
65
|
self.energy_scale = np.array([])
|
|
56
66
|
self.model = np.array([])
|
|
57
67
|
self.y_scale = 1.0
|
|
58
68
|
self.change_y_scale = 1.0
|
|
69
|
+
self.spectrum_ll = None
|
|
70
|
+
self.low_loss_key = None
|
|
59
71
|
|
|
60
72
|
self.edges = {}
|
|
61
73
|
|
|
62
|
-
|
|
63
74
|
self.show_regions = False
|
|
64
75
|
self.show()
|
|
65
76
|
|
|
66
|
-
self.set_dataset(dataset)
|
|
77
|
+
self.set_dataset(self.dataset)
|
|
67
78
|
initial_elements = []
|
|
68
79
|
|
|
69
80
|
for key in self.edges:
|
|
@@ -86,8 +97,9 @@ if Qt_available:
|
|
|
86
97
|
self.updY = 0
|
|
87
98
|
self.figure.canvas.mpl_connect('button_press_event', self.plot)
|
|
88
99
|
|
|
100
|
+
self.ui.do_fit_button.setFocus()
|
|
89
101
|
self.plot()
|
|
90
|
-
self.ui.
|
|
102
|
+
self.ui.do_fit_button.setFocus()
|
|
91
103
|
|
|
92
104
|
def set_dataset(self, dataset):
|
|
93
105
|
|
|
@@ -145,7 +157,7 @@ if Qt_available:
|
|
|
145
157
|
else:
|
|
146
158
|
dispersion = self.energy_scale[1]-self.energy_scale[0]
|
|
147
159
|
self.ui.edit9.setText(f"{edge['areal_density']*self.y_scale*1e-6/dispersion:.2f}")
|
|
148
|
-
self.ui.unit9.setText(
|
|
160
|
+
self.ui.unit9.setText('atoms/nm²')
|
|
149
161
|
else:
|
|
150
162
|
self.ui.list3.setCurrentIndex(0)
|
|
151
163
|
self.ui.edit4.setText(str(0))
|
|
@@ -192,6 +204,7 @@ if Qt_available:
|
|
|
192
204
|
return False
|
|
193
205
|
|
|
194
206
|
index = self.ui.list3.currentIndex()
|
|
207
|
+
# self.ui.dialog.setWindowTitle(f'{index}, {zz}')
|
|
195
208
|
|
|
196
209
|
if str(index) not in self.edges:
|
|
197
210
|
self.edges[str(index)] = {}
|
|
@@ -211,7 +224,9 @@ if Qt_available:
|
|
|
211
224
|
def on_enter(self):
|
|
212
225
|
sender = self.sender()
|
|
213
226
|
edge_list = self.ui.list3
|
|
227
|
+
# self.ui.dialog.setWindowTitle(f"{sender.objectName()}")
|
|
214
228
|
|
|
229
|
+
|
|
215
230
|
if sender.objectName() == 'fit_start_edit':
|
|
216
231
|
value = float(str(sender.displayText()).strip())
|
|
217
232
|
if value < self.energy_scale[0]:
|
|
@@ -230,9 +245,10 @@ if Qt_available:
|
|
|
230
245
|
sender.setText(str(self.edges['fit_area']['fit_end']))
|
|
231
246
|
elif sender.objectName() == 'element_edit':
|
|
232
247
|
if str(sender.displayText()).strip() == '0':
|
|
233
|
-
sender.setText('PT')
|
|
234
|
-
|
|
235
|
-
|
|
248
|
+
# sender.setText('PT')
|
|
249
|
+
self.pt_dialog.energy_scale = self.energy_scale
|
|
250
|
+
self.pt_dialog.show()
|
|
251
|
+
pass
|
|
236
252
|
else:
|
|
237
253
|
self.update_element(str(sender.displayText()).strip())
|
|
238
254
|
self.update()
|
|
@@ -242,6 +258,9 @@ if Qt_available:
|
|
|
242
258
|
elif sender.objectName() == 'multiplier_edit':
|
|
243
259
|
index = edge_list.currentIndex()
|
|
244
260
|
self.edges[str(index)]['areal_density'] = float(self.ui.edit9.displayText())
|
|
261
|
+
if self.y_scale != 1.0:
|
|
262
|
+
dispersion = self.energy_scale[1]-self.energy_scale[0]
|
|
263
|
+
self.edges[str(index)]['areal_density'] /= self.y_scale * 1e-6 *dispersion
|
|
245
264
|
if 'background' not in self.edges['model']:
|
|
246
265
|
print(' no background')
|
|
247
266
|
return
|
|
@@ -255,6 +274,8 @@ if Qt_available:
|
|
|
255
274
|
if self.show_regions:
|
|
256
275
|
self.plot()
|
|
257
276
|
|
|
277
|
+
|
|
278
|
+
|
|
258
279
|
def sort_elements(self):
|
|
259
280
|
onsets = []
|
|
260
281
|
for index, edge in self.edges.items():
|
|
@@ -281,16 +302,13 @@ if Qt_available:
|
|
|
281
302
|
edge['end_exclude'] = self.energy_scale[-3]
|
|
282
303
|
|
|
283
304
|
def set_elements(self, selected_elements):
|
|
284
|
-
|
|
285
305
|
edge_list = self.ui.list3
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
edge_list.setCurrentIndex(index + 1)
|
|
306
|
+
|
|
307
|
+
for index, elem in enumerate(selected_elements):
|
|
308
|
+
edge_list.setCurrentIndex(index)
|
|
309
|
+
self.update_element(elem)
|
|
310
|
+
|
|
292
311
|
self.sort_elements()
|
|
293
|
-
edge_list.setCurrentIndex(index)
|
|
294
312
|
self.update()
|
|
295
313
|
|
|
296
314
|
def plot(self, event=None):
|
|
@@ -450,6 +468,7 @@ if Qt_available:
|
|
|
450
468
|
|
|
451
469
|
def on_list_enter(self):
|
|
452
470
|
sender = self.sender()
|
|
471
|
+
# self.ui.dialog.setWindowTitle(f"on list eneter {sender.objectName()}")
|
|
453
472
|
|
|
454
473
|
if sender.objectName() == 'edge_list':
|
|
455
474
|
index = self.ui.list3.currentIndex()
|
|
@@ -488,6 +507,8 @@ if Qt_available:
|
|
|
488
507
|
|
|
489
508
|
def on_check(self):
|
|
490
509
|
sender = self.sender()
|
|
510
|
+
# self.ui.dialog.setWindowTitle(f"on_check {sender.objectName()}")
|
|
511
|
+
|
|
491
512
|
|
|
492
513
|
if sender.objectName() == 'edge_check':
|
|
493
514
|
self.show_regions = sender.isChecked()
|
|
@@ -497,25 +518,62 @@ if Qt_available:
|
|
|
497
518
|
self.low_loss()
|
|
498
519
|
elif sender.objectName() == 'probability':
|
|
499
520
|
dispersion = self.energy_scale[1]-self.energy_scale[0]
|
|
521
|
+
old_y_scale = self.y_scale *1.
|
|
500
522
|
if sender.isChecked():
|
|
501
|
-
|
|
502
|
-
|
|
523
|
+
flux_key = None
|
|
524
|
+
spectrum_key = None
|
|
525
|
+
|
|
526
|
+
for key in self.datasets.keys():
|
|
527
|
+
if 'Reference' in key:
|
|
528
|
+
if self.datasets[key].data_type.name == 'IMAGE': # Prefer Ronchigrams
|
|
529
|
+
flux_key = key
|
|
530
|
+
self.dataset.metadata['experiment']['flux_reference_key'] = flux_key
|
|
531
|
+
elif self.datasets[key].data_type.name == 'SPECTRUM':
|
|
532
|
+
spectrum_key = key
|
|
533
|
+
self.dataset.metadata['experiment']['low_loss_key'] = spectrum_key
|
|
534
|
+
if flux_key is None:
|
|
535
|
+
flux_key = spectrum_key
|
|
536
|
+
|
|
537
|
+
# self.ui.dialog.setWindowTitle(f"2nd {self.dataset.metadata['experiment']['flux_ppm']:.2f}")
|
|
538
|
+
if self.dataset.metadata['experiment']['flux_ppm'] > 0:
|
|
539
|
+
# self.ui.dialog.setWindowTitle(f"3rD {self.dataset.metadata['experiment']['flux_ppm']:.2f}")
|
|
540
|
+
self.y_scale = 1/self.dataset.metadata['experiment']['flux_ppm']*dispersion
|
|
541
|
+
elif flux_key is not None:
|
|
542
|
+
self.dataset.metadata['experiment']['flux_ppm'] = (np.array(self.datasets[flux_key])/1e6).sum()
|
|
543
|
+
self.dataset.metadata['experiment']['flux_ppm'] /= self.datasets[flux_key].metadata['experiment']['exposure_time']
|
|
544
|
+
self.dataset.metadata['experiment']['flux_ppm'] *= self.dataset.metadata['experiment']['exposure_time']
|
|
545
|
+
self.y_scale = 1/self.dataset.metadata['experiment']['flux_ppm']*dispersion
|
|
546
|
+
else:
|
|
547
|
+
self.y_scale = 1.0
|
|
503
548
|
else:
|
|
504
549
|
self.y_scale = 1.0
|
|
505
|
-
|
|
550
|
+
|
|
551
|
+
self.change_y_scale = self.y_scale/old_y_scale
|
|
506
552
|
self.update()
|
|
507
553
|
self.plot()
|
|
508
554
|
|
|
509
555
|
def low_loss(self):
|
|
510
556
|
self.edges['use_low_loss'] = self.ui.check10.isChecked()
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
self.
|
|
557
|
+
if self.low_loss_key is None:
|
|
558
|
+
for key in self.datasets.keys():
|
|
559
|
+
if 'Reference' in key:
|
|
560
|
+
if self.datasets[key].data_type.name == 'SPECTRUM':
|
|
561
|
+
self.low_loss_key = key
|
|
562
|
+
self.dataset.metadata['experiment']['low_loss_key'] = self.low_loss_key
|
|
563
|
+
|
|
564
|
+
if self.low_loss_key is None:
|
|
565
|
+
self.low_loss_key = ft.add_dataset_from_file(self.datasets, key_name='Reference')
|
|
566
|
+
self.spectrum_ll = self.datasets[self.low_loss_key]
|
|
567
|
+
if self.spectrum_ll.data_type.name != 'SPECTRUM':
|
|
568
|
+
self.spectrum_ll = None
|
|
569
|
+
self.low_loss_key = None
|
|
570
|
+
|
|
571
|
+
if self.low_loss_key is not None:
|
|
572
|
+
self.spectrum_ll = self.datasets[self.low_loss_key]
|
|
573
|
+
if 'number_of_frames' in self.spectrum_ll.metadata['experiment']:
|
|
574
|
+
self.spectrum_ll.metadata['experiment']['exposure_time'] = \
|
|
575
|
+
self.spectrum_ll.metadata['experiment']['single_exposure_time'] * \
|
|
576
|
+
self.spectrum_ll.metadata['experiment']['number_of_frames']
|
|
519
577
|
|
|
520
578
|
def do_all_button_click(self):
|
|
521
579
|
|
|
@@ -536,7 +594,7 @@ if Qt_available:
|
|
|
536
594
|
self.energy_scale = self.dataset._axes[self.spec_dim].values
|
|
537
595
|
eff_beta = eels.effective_collection_angle(self.energy_scale, alpha, beta, beam_kv)
|
|
538
596
|
if self.edges['use_low_loss']:
|
|
539
|
-
low_loss = self.spectrum_ll/self.spectrum_ll.sum()
|
|
597
|
+
low_loss = np.array(self.spectrum_ll)/self.spectrum_ll.sum()
|
|
540
598
|
else:
|
|
541
599
|
low_loss = None
|
|
542
600
|
|
|
@@ -620,6 +678,9 @@ if Qt_available:
|
|
|
620
678
|
self.plot()
|
|
621
679
|
|
|
622
680
|
def do_auto_id_button_click(self):
|
|
681
|
+
# self.ui.dialog.setWindowTitle(f"auto id ")
|
|
682
|
+
self.ui.do_fit_button.setFocus()
|
|
683
|
+
|
|
623
684
|
if '0' not in self.edges:
|
|
624
685
|
self.edges['0'] ={}
|
|
625
686
|
found_edges = eels.auto_id_edges(self.dataset)
|
|
@@ -746,3 +807,557 @@ if Qt_available:
|
|
|
746
807
|
else:
|
|
747
808
|
legline.set_alpha(0.2)
|
|
748
809
|
self.fig.canvas.draw()
|
|
810
|
+
|
|
811
|
+
def get_sidebar():
|
|
812
|
+
side_bar = ipywidgets.GridspecLayout(13, 3,width='auto', grid_gap="0px")
|
|
813
|
+
|
|
814
|
+
|
|
815
|
+
row = 0
|
|
816
|
+
side_bar[row, :3] = ipywidgets.ToggleButton(description='Fit Area',
|
|
817
|
+
layout=ipywidgets.Layout(width='auto', grid_area='header'),
|
|
818
|
+
tooltip='Shows fit regions and regions excluded from fit',
|
|
819
|
+
button_style='info') #ipywidgets.ButtonStyle(button_color='lightblue'))
|
|
820
|
+
row += 1
|
|
821
|
+
side_bar[row, :2] = ipywidgets.FloatText(value=7.5,description='Fit Start:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
|
|
822
|
+
side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='20px'))
|
|
823
|
+
row += 1
|
|
824
|
+
side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Fit End:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
|
|
825
|
+
side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='20px'))
|
|
826
|
+
|
|
827
|
+
row += 1
|
|
828
|
+
|
|
829
|
+
side_bar[row, :3] = ipywidgets.Button(description='Elements',
|
|
830
|
+
layout=ipywidgets.Layout(width='auto', grid_area='header'),
|
|
831
|
+
style=ipywidgets.ButtonStyle(button_color='lightblue'))
|
|
832
|
+
row += 1
|
|
833
|
+
side_bar[row, :2] = ipywidgets.Dropdown(
|
|
834
|
+
options=[('Edge 1', 0), ('Edge 2', 1), ('Edge 3', 2), ('Edge 4', 3),('Add Edge', -1)],
|
|
835
|
+
value=0,
|
|
836
|
+
description='Edges:',
|
|
837
|
+
disabled=False,
|
|
838
|
+
layout=ipywidgets.Layout(width='200px'))
|
|
839
|
+
"""side_bar[row,2] = ipywidgets.ToggleButton(
|
|
840
|
+
description='Regions',
|
|
841
|
+
disabled=False,
|
|
842
|
+
button_style='', # 'success', 'info', 'warning', 'danger' or ''
|
|
843
|
+
tooltip='Shows fit regions and regions excluded from fit',
|
|
844
|
+
layout=ipywidgets.Layout(width='100px')
|
|
845
|
+
)
|
|
846
|
+
"""
|
|
847
|
+
row += 1
|
|
848
|
+
side_bar[row, :2] = ipywidgets.IntText(value=7.5,description='Z:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
|
|
849
|
+
side_bar[row, 2] = ipywidgets.widgets.Label(value="", layout=ipywidgets.Layout(width='100px'))
|
|
850
|
+
row += 1
|
|
851
|
+
side_bar[row, :2] = ipywidgets.Dropdown(
|
|
852
|
+
options=['K1','L3', 'M5', 'M3', 'M1', 'N7', 'N5', 'N3', 'N1'],
|
|
853
|
+
value='K1',
|
|
854
|
+
description='Symmetry:',
|
|
855
|
+
disabled=False,
|
|
856
|
+
layout=ipywidgets.Layout(width='200px'))
|
|
857
|
+
row += 1
|
|
858
|
+
side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Onset:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
|
|
859
|
+
side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='100px'))
|
|
860
|
+
row += 1
|
|
861
|
+
side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Excl.Start:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
|
|
862
|
+
side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='100px'))
|
|
863
|
+
row += 1
|
|
864
|
+
side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Excl.End:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
|
|
865
|
+
side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='100px'))
|
|
866
|
+
row += 1
|
|
867
|
+
side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Mutliplier:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
|
|
868
|
+
side_bar[row, 2] = ipywidgets.widgets.Label(value="a.u.", layout=ipywidgets.Layout(width='100px'))
|
|
869
|
+
row += 1
|
|
870
|
+
|
|
871
|
+
side_bar[row, :3] = ipywidgets.Button(description='Quantification',
|
|
872
|
+
layout=ipywidgets.Layout(width='auto', grid_area='header'),
|
|
873
|
+
style=ipywidgets.ButtonStyle(button_color='lightblue'))
|
|
874
|
+
|
|
875
|
+
row += 1
|
|
876
|
+
side_bar[row,0] = ipywidgets.ToggleButton(
|
|
877
|
+
description='Probabiity',
|
|
878
|
+
disabled=False,
|
|
879
|
+
button_style='', # 'success', 'info', 'warning', 'danger' or ''
|
|
880
|
+
tooltip='Changes y-axis to probability of flux is given',
|
|
881
|
+
layout=ipywidgets.Layout(width='100px')
|
|
882
|
+
)
|
|
883
|
+
side_bar[row,1] = ipywidgets.ToggleButton(
|
|
884
|
+
description='Conv.LL',
|
|
885
|
+
disabled=False,
|
|
886
|
+
button_style='', # 'success', 'info', 'warning', 'danger' or ''
|
|
887
|
+
tooltip='Changes y-axis to probability of flux is given',
|
|
888
|
+
layout=ipywidgets.Layout(width='100px')
|
|
889
|
+
)
|
|
890
|
+
side_bar[row,2] = ipywidgets.ToggleButton(
|
|
891
|
+
description='Show Edges',
|
|
892
|
+
disabled=False,
|
|
893
|
+
button_style='', # 'success', 'info', 'warning', 'danger' or ''
|
|
894
|
+
tooltip='Changes y-axis to probability of flux is given',
|
|
895
|
+
layout=ipywidgets.Layout(width='100px')
|
|
896
|
+
)
|
|
897
|
+
return side_bar
|
|
898
|
+
|
|
899
|
+
|
|
900
|
+
class CompositionWidget(object):
|
|
901
|
+
def __init__(self, datasets=None):
|
|
902
|
+
self.datasets = datasets
|
|
903
|
+
if not isinstance(datasets, dict):
|
|
904
|
+
raise TypeError('dataset or first item inhas to be a sidpy dataset')
|
|
905
|
+
|
|
906
|
+
self.sidebar = get_sidebar()
|
|
907
|
+
self.dataset = datasets[list(datasets)[0]]
|
|
908
|
+
if not isinstance(self.dataset, sidpy.Dataset):
|
|
909
|
+
raise TypeError('dataset or first item inhas to be a sidpy dataset')
|
|
910
|
+
self.spec_dim = ft.get_dimensions_by_type('spectral', self.dataset)
|
|
911
|
+
if len(self.spec_dim) != 1:
|
|
912
|
+
raise TypeError('We need exactly one SPECTRAL dimension')
|
|
913
|
+
self.spec_dim = self.spec_dim[0]
|
|
914
|
+
#self.energy_scale = self.dataset._axes[self.spec_dim]
|
|
915
|
+
|
|
916
|
+
self.energy_scale = self.spec_dim[1]
|
|
917
|
+
self.model = np.array([])
|
|
918
|
+
self.y_scale = 1.0
|
|
919
|
+
self.change_y_scale = 1.0
|
|
920
|
+
self.spectrum_ll = None
|
|
921
|
+
self.low_loss_key = None
|
|
922
|
+
|
|
923
|
+
self.edges = {}
|
|
924
|
+
|
|
925
|
+
self.show_regions = False
|
|
926
|
+
|
|
927
|
+
with plt.ioff():
|
|
928
|
+
self.fig = plt.figure()
|
|
929
|
+
self.fig.canvas.toolbar_position = 'right'
|
|
930
|
+
self.fig.canvas.toolbar_visible = True
|
|
931
|
+
self.key = list(self.datasets.keys())[0]
|
|
932
|
+
self.set_dataset()
|
|
933
|
+
self.set_action()
|
|
934
|
+
self.y_scale = 1.0
|
|
935
|
+
self.change_y_scale = 1.0
|
|
936
|
+
self.plot(scale=False)
|
|
937
|
+
self.selector = matplotlib.widgets.SpanSelector(self.fig.gca(), self.line_select_callback,
|
|
938
|
+
direction="horizontal",
|
|
939
|
+
interactive=True,
|
|
940
|
+
props=dict(facecolor='blue', alpha=0.2))
|
|
941
|
+
self.start_cursor = ipywidgets.FloatText(value=0, description='Start:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
|
|
942
|
+
self.end_cursor = ipywidgets.FloatText(value=0, description='End:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
|
|
943
|
+
self.panel = ipywidgets.VBox([ipywidgets.HBox([ipywidgets.Label('',layout=ipywidgets.Layout(width='100px')), ipywidgets.Label('Cursor:'),
|
|
944
|
+
self.start_cursor,ipywidgets.Label('eV'),
|
|
945
|
+
self.end_cursor, ipywidgets.Label('eV')]),
|
|
946
|
+
self.fig.canvas])
|
|
947
|
+
|
|
948
|
+
self.app_layout = ipywidgets.AppLayout(
|
|
949
|
+
left_sidebar=self.sidebar,
|
|
950
|
+
center=self.panel,
|
|
951
|
+
footer=None,#message_bar,
|
|
952
|
+
pane_heights=[0, 10, 0],
|
|
953
|
+
pane_widths=[4, 10, 0],
|
|
954
|
+
)
|
|
955
|
+
IPython.display.display(self.app_layout)
|
|
956
|
+
|
|
957
|
+
def line_select_callback(self, x_min, x_max):
|
|
958
|
+
self.start_cursor.value = np.round(x_min,3)
|
|
959
|
+
self.end_cursor.value = np.round(x_max, 3)
|
|
960
|
+
self.start_channel = np.searchsorted(self.datasets[self.key].energy_loss, self.start_cursor.value)
|
|
961
|
+
self.end_channel = np.searchsorted(self.datasets[self.key].energy_loss, self.end_cursor.value)
|
|
962
|
+
|
|
963
|
+
def plot(self, scale=True):
|
|
964
|
+
|
|
965
|
+
ylim = self.fig.gca().get_ylim()
|
|
966
|
+
|
|
967
|
+
ax = self.fig.gca()
|
|
968
|
+
ax.clear()
|
|
969
|
+
ax.plot(self.energy_scale, self.datasets[self.key]*self.y_scale, label=self.datasets[self.key].title)
|
|
970
|
+
|
|
971
|
+
ax.set_xlabel(self.datasets[self.key].labels[0])
|
|
972
|
+
ax.set_ylabel(self.datasets[self.key].data_descriptor)
|
|
973
|
+
ax.ticklabel_format(style='sci', scilimits=(-2, 3))
|
|
974
|
+
if scale:
|
|
975
|
+
ax.set_ylim(np.array(ylim)*self.change_y_scale)
|
|
976
|
+
self.change_y_scale = 1.0
|
|
977
|
+
if self.y_scale != 1.:
|
|
978
|
+
ax.set_ylabel('scattering probability (ppm/eV)')
|
|
979
|
+
self.selector = matplotlib.widgets.SpanSelector(self.fig.gca(), self.line_select_callback,
|
|
980
|
+
direction="horizontal",
|
|
981
|
+
interactive=True,
|
|
982
|
+
props=dict(facecolor='blue', alpha=0.2))
|
|
983
|
+
|
|
984
|
+
if len(self.model) > 1:
|
|
985
|
+
ax.plot(self.energy_scale, self.model*self.y_scale, label='model')
|
|
986
|
+
difference_spec = self.datasets[self.key] - self.model
|
|
987
|
+
ax.plot(self.energy_scale, difference_spec*self.y_scale, label='difference')
|
|
988
|
+
# axis.plot(self.energy_scale, (self.datasets[key] - self.model) / np.sqrt(self.datasets[key])*self.y_scale, label='Poisson')
|
|
989
|
+
|
|
990
|
+
|
|
991
|
+
ax.legend()
|
|
992
|
+
|
|
993
|
+
if self.sidebar[12, 2].value:
|
|
994
|
+
self.show_edges()
|
|
995
|
+
if self.sidebar[0, 0].value:
|
|
996
|
+
self.plot_regions()
|
|
997
|
+
self.fig.canvas.draw_idle()
|
|
998
|
+
|
|
999
|
+
|
|
1000
|
+
def plot_regions(self):
|
|
1001
|
+
axis = self.fig.gca()
|
|
1002
|
+
y_min, y_max = axis.get_ylim()
|
|
1003
|
+
height = y_max - y_min
|
|
1004
|
+
|
|
1005
|
+
rect = []
|
|
1006
|
+
if 'fit_area' in self.edges:
|
|
1007
|
+
color = 'blue'
|
|
1008
|
+
alpha = 0.2
|
|
1009
|
+
x_min = self.edges['fit_area']['fit_start']
|
|
1010
|
+
width = self.edges['fit_area']['fit_end'] - x_min
|
|
1011
|
+
rect.append(patches.Rectangle((x_min, y_min), width, height,
|
|
1012
|
+
edgecolor=color, alpha=alpha, facecolor=color))
|
|
1013
|
+
axis.add_patch(rect[0])
|
|
1014
|
+
axis.text(x_min, y_max, 'fit region', verticalalignment='top')
|
|
1015
|
+
color = 'red'
|
|
1016
|
+
alpha = 0.5
|
|
1017
|
+
|
|
1018
|
+
for key in self.edges:
|
|
1019
|
+
if key.isdigit():
|
|
1020
|
+
x_min = self.edges[key]['start_exclude']
|
|
1021
|
+
width = self.edges[key]['end_exclude']-x_min
|
|
1022
|
+
rect.append(patches.Rectangle((x_min, y_min), width, height,
|
|
1023
|
+
edgecolor=color, alpha=alpha, facecolor=color))
|
|
1024
|
+
axis.add_patch(rect[-1])
|
|
1025
|
+
axis.text(x_min, y_max, f"exclude\n edge {int(key)+1}", verticalalignment='top')
|
|
1026
|
+
|
|
1027
|
+
def show_edges(self):
|
|
1028
|
+
axis = self.fig.gca()
|
|
1029
|
+
x_min, x_max = axis.get_xlim()
|
|
1030
|
+
y_min, y_max = axis.get_ylim()
|
|
1031
|
+
|
|
1032
|
+
for key, edge in self.edges.items():
|
|
1033
|
+
i = 0
|
|
1034
|
+
if key.isdigit():
|
|
1035
|
+
element = edge['element']
|
|
1036
|
+
for sym in edge['all_edges']:
|
|
1037
|
+
x = edge['all_edges'][sym]['onset'] + edge['chemical_shift']
|
|
1038
|
+
if x_min < x < x_max:
|
|
1039
|
+
axis.text(x, y_max, '\n' * i + f"{element}-{sym}",
|
|
1040
|
+
verticalalignment='top', color='black')
|
|
1041
|
+
axis.axvline(x, ymin=0, ymax=1, color='gray')
|
|
1042
|
+
i += 1
|
|
1043
|
+
|
|
1044
|
+
|
|
1045
|
+
|
|
1046
|
+
|
|
1047
|
+
def set_dataset(self, index=0):
|
|
1048
|
+
if 'edges' not in self.dataset.metadata or self.dataset.metadata['edges'] == {}:
|
|
1049
|
+
self.dataset.metadata['edges'] = {'0': {}, 'model': {}, 'use_low_loss': False}
|
|
1050
|
+
|
|
1051
|
+
self.edges = self.dataset.metadata['edges']
|
|
1052
|
+
if '0' not in self.edges:
|
|
1053
|
+
self.edges['0'] = {}
|
|
1054
|
+
|
|
1055
|
+
if 'fit_area' not in self.edges:
|
|
1056
|
+
self.edges['fit_area'] = {}
|
|
1057
|
+
if 'fit_start' not in self.edges['fit_area']:
|
|
1058
|
+
self.sidebar[1,0].value = np.round(self.energy_scale[50], 3)
|
|
1059
|
+
self.edges['fit_area']['fit_start'] = self.sidebar[1,0].value
|
|
1060
|
+
else:
|
|
1061
|
+
self.sidebar[1,0].value = np.round(self.edges['fit_area']['fit_start'],3)
|
|
1062
|
+
if 'fit_end' not in self.edges['fit_area']:
|
|
1063
|
+
self.sidebar[2,0].value = np.round(self.energy_scale[-2], 3)
|
|
1064
|
+
self.edges['fit_area']['fit_end'] = self.sidebar[2,0].value
|
|
1065
|
+
else:
|
|
1066
|
+
self.sidebar[2,0].value = np.round(self.edges['fit_area']['fit_end'],3)
|
|
1067
|
+
|
|
1068
|
+
if self.dataset.data_type.name == 'SPECTRAL_IMAGE':
|
|
1069
|
+
if 'SI_bin_x' not in self.dataset.metadata['experiment']:
|
|
1070
|
+
self.dataset.metadata['experiment']['SI_bin_x'] = 1
|
|
1071
|
+
self.dataset.metadata['experiment']['SI_bin_y'] = 1
|
|
1072
|
+
|
|
1073
|
+
bin_x = self.dataset.metadata['experiment']['SI_bin_x']
|
|
1074
|
+
bin_y = self.dataset.metadata['experiment']['SI_bin_y']
|
|
1075
|
+
# self.dataset.view.set_bin([bin_x, bin_y])
|
|
1076
|
+
self.update()
|
|
1077
|
+
|
|
1078
|
+
def update_element(self, z=0, index=-1):
|
|
1079
|
+
# We check whether this element is already in the
|
|
1080
|
+
if z == 0:
|
|
1081
|
+
z = self.sidebar[5,0].value
|
|
1082
|
+
|
|
1083
|
+
zz = eels.get_z(z)
|
|
1084
|
+
for key, edge in self.edges.items():
|
|
1085
|
+
if key.isdigit():
|
|
1086
|
+
if 'z' in edge:
|
|
1087
|
+
if zz == edge['z']:
|
|
1088
|
+
return False
|
|
1089
|
+
|
|
1090
|
+
major_edge = ''
|
|
1091
|
+
minor_edge = ''
|
|
1092
|
+
all_edges = {}
|
|
1093
|
+
x_section = eels.get_x_sections(zz)
|
|
1094
|
+
edge_start = 10 # int(15./ft.get_slope(self.energy_scale)+0.5)
|
|
1095
|
+
for key in x_section:
|
|
1096
|
+
if len(key) == 2 and key[0] in ['K', 'L', 'M', 'N', 'O'] and key[1].isdigit():
|
|
1097
|
+
if self.energy_scale[edge_start] < x_section[key]['onset'] < self.energy_scale[-edge_start]:
|
|
1098
|
+
if key in ['K1', 'L3', 'M5']:
|
|
1099
|
+
major_edge = key
|
|
1100
|
+
elif key in self.sidebar[6,0].options:
|
|
1101
|
+
if minor_edge == '':
|
|
1102
|
+
minor_edge = key
|
|
1103
|
+
if int(key[-1]) % 2 > 0:
|
|
1104
|
+
if int(minor_edge[-1]) % 2 == 0 or key[-1] > minor_edge[-1]:
|
|
1105
|
+
minor_edge = key
|
|
1106
|
+
|
|
1107
|
+
all_edges[key] = {'onset': x_section[key]['onset']}
|
|
1108
|
+
|
|
1109
|
+
if major_edge != '':
|
|
1110
|
+
key = major_edge
|
|
1111
|
+
elif minor_edge != '':
|
|
1112
|
+
key = minor_edge
|
|
1113
|
+
else:
|
|
1114
|
+
print(f'Could not find no edge of {zz} in spectrum')
|
|
1115
|
+
return False
|
|
1116
|
+
if index == -1:
|
|
1117
|
+
index = self.sidebar[4, 0].value
|
|
1118
|
+
# self.ui.dialog.setWindowTitle(f'{index}, {zz}')
|
|
1119
|
+
|
|
1120
|
+
if str(index) not in self.edges:
|
|
1121
|
+
self.edges[str(index)] = {}
|
|
1122
|
+
|
|
1123
|
+
start_exclude = x_section[key]['onset'] - x_section[key]['excl before']
|
|
1124
|
+
end_exclude = x_section[key]['onset'] + x_section[key]['excl after']
|
|
1125
|
+
|
|
1126
|
+
self.edges[str(index)] = {'z': zz, 'symmetry': key, 'element': eels.elements[zz],
|
|
1127
|
+
'onset': x_section[key]['onset'], 'end_exclude': end_exclude,
|
|
1128
|
+
'start_exclude': start_exclude}
|
|
1129
|
+
self.edges[str(index)]['all_edges'] = all_edges
|
|
1130
|
+
self.edges[str(index)]['chemical_shift'] = 0.0
|
|
1131
|
+
self.edges[str(index)]['areal_density'] = 0.0
|
|
1132
|
+
self.edges[str(index)]['original_onset'] = self.edges[str(index)]['onset']
|
|
1133
|
+
return True
|
|
1134
|
+
|
|
1135
|
+
|
|
1136
|
+
|
|
1137
|
+
def sort_elements(self):
|
|
1138
|
+
onsets = []
|
|
1139
|
+
for index, edge in self.edges.items():
|
|
1140
|
+
if index.isdigit():
|
|
1141
|
+
onsets.append(float(edge['onset']))
|
|
1142
|
+
|
|
1143
|
+
arg_sorted = np.argsort(onsets)
|
|
1144
|
+
edges = self.edges.copy()
|
|
1145
|
+
for index, i_sorted in enumerate(arg_sorted):
|
|
1146
|
+
self.edges[str(index)] = edges[str(i_sorted)].copy()
|
|
1147
|
+
|
|
1148
|
+
index = 0
|
|
1149
|
+
edge = self.edges['0']
|
|
1150
|
+
dispersion = self.energy_scale[1]-self.energy_scale[0]
|
|
1151
|
+
|
|
1152
|
+
while str(index + 1) in self.edges:
|
|
1153
|
+
next_edge = self.edges[str(index + 1)]
|
|
1154
|
+
if edge['end_exclude'] > next_edge['start_exclude'] - 5 * dispersion:
|
|
1155
|
+
edge['end_exclude'] = next_edge['start_exclude'] - 5 * dispersion
|
|
1156
|
+
edge = next_edge
|
|
1157
|
+
index += 1
|
|
1158
|
+
|
|
1159
|
+
if edge['end_exclude'] > self.energy_scale[-3]:
|
|
1160
|
+
edge['end_exclude'] = self.energy_scale[-3]
|
|
1161
|
+
|
|
1162
|
+
def set_elements(self, selected_elements):
|
|
1163
|
+
|
|
1164
|
+
for index, elem in enumerate(selected_elements):
|
|
1165
|
+
self.sidebar[4, 0].value =index
|
|
1166
|
+
self.update_element(elem)
|
|
1167
|
+
|
|
1168
|
+
# self.sort_elements()
|
|
1169
|
+
self.update()
|
|
1170
|
+
|
|
1171
|
+
|
|
1172
|
+
|
|
1173
|
+
def set_element(self, elem):
|
|
1174
|
+
self.update_element(self.sidebar[5, 0].value)
|
|
1175
|
+
# self.sort_elements()
|
|
1176
|
+
self.update()
|
|
1177
|
+
|
|
1178
|
+
def cursor2energy_scale(self, value):
|
|
1179
|
+
|
|
1180
|
+
dispersion = (self.end_cursor.value - self.start_cursor.value) / (self.end_channel - self.start_channel)
|
|
1181
|
+
self.datasets[self.key].energy_loss *= (self.sidebar[3, 0].value/dispersion)
|
|
1182
|
+
self.sidebar[3, 0].value = dispersion
|
|
1183
|
+
offset = self.start_cursor.value - self.start_channel * dispersion
|
|
1184
|
+
self.datasets[self.key].energy_loss += (self.sidebar[2, 0].value-self.datasets[self.key].energy_loss[0])
|
|
1185
|
+
self.sidebar[2, 0].value = offset
|
|
1186
|
+
self.plot()
|
|
1187
|
+
|
|
1188
|
+
def set_fit_area(self, value):
|
|
1189
|
+
if self.sidebar[1,0].value > self.sidebar[2,0].value:
|
|
1190
|
+
self.sidebar[1,0].value = self.sidebar[2,0].value -1
|
|
1191
|
+
if self.sidebar[1,0].value < self.energy_scale[0]:
|
|
1192
|
+
self.sidebar[1,0].value = self.energy_scale[0]
|
|
1193
|
+
if self.sidebar[2,0].value > self.energy_scale[-1]:
|
|
1194
|
+
self.sidebar[2,0].value = self.energy_scale[-1]
|
|
1195
|
+
self.edges['fit_area']['fit_start'] = self.sidebar[1,0].value
|
|
1196
|
+
self.edges['fit_area']['fit_end'] = self.sidebar[2,0].value
|
|
1197
|
+
|
|
1198
|
+
self.plot()
|
|
1199
|
+
|
|
1200
|
+
def set_y_scale(self, value):
|
|
1201
|
+
self.change_y_scale = 1/self.y_scale
|
|
1202
|
+
if self.sidebar[12, 0].value:
|
|
1203
|
+
dispersion = self.energy_scale[1] - self.energy_scale[0]
|
|
1204
|
+
self.y_scale = 1/self.dataset.metadata['experiment']['flux_ppm'] * dispersion
|
|
1205
|
+
else:
|
|
1206
|
+
self.y_scale = 1.0
|
|
1207
|
+
|
|
1208
|
+
self.change_y_scale *= self.y_scale
|
|
1209
|
+
self.update()
|
|
1210
|
+
self.plot()
|
|
1211
|
+
|
|
1212
|
+
def find_elements(self, value=0):
|
|
1213
|
+
|
|
1214
|
+
if '0' not in self.edges:
|
|
1215
|
+
self.edges['0'] ={}
|
|
1216
|
+
found_edges = eels.auto_id_edges(self.dataset)
|
|
1217
|
+
|
|
1218
|
+
to_delete = []
|
|
1219
|
+
if len(found_edges) >0:
|
|
1220
|
+
for key in self.edges:
|
|
1221
|
+
if key.isdigit():
|
|
1222
|
+
to_delete.append(key)
|
|
1223
|
+
for key in to_delete:
|
|
1224
|
+
del self.edges[key]
|
|
1225
|
+
if len(to_delete) > 0:
|
|
1226
|
+
self.edges['0'] = {}
|
|
1227
|
+
|
|
1228
|
+
selected_elements = []
|
|
1229
|
+
for key in found_edges:
|
|
1230
|
+
selected_elements.append(key)
|
|
1231
|
+
self.set_elements(selected_elements)
|
|
1232
|
+
|
|
1233
|
+
self.update()
|
|
1234
|
+
|
|
1235
|
+
def update(self, index=0):
|
|
1236
|
+
|
|
1237
|
+
index = self.sidebar[4,0].value # which edge
|
|
1238
|
+
if index < 0:
|
|
1239
|
+
options = list(self.sidebar[4,0].options)
|
|
1240
|
+
options.insert(-1, (f'Edge {len(self.sidebar[4,0].options)}', len(self.sidebar[4,0].options)-1))
|
|
1241
|
+
self.sidebar[4,0].options= options
|
|
1242
|
+
self.sidebar[4,0].value = len(self.sidebar[4,0].options)-2
|
|
1243
|
+
if str(index) not in self.edges:
|
|
1244
|
+
self.edges[str(index)] = {'z': 0, 'element': 'x', 'symmetry': 'K1', 'onset': 0, 'start_exclude': 0, 'end_exclude':0,
|
|
1245
|
+
'areal_density': 0}
|
|
1246
|
+
if 'z' not in self.edges[str(index)]:
|
|
1247
|
+
self.edges[str(index)] = {'z': 0, 'element': 'x', 'symmetry': 'K1', 'onset': 0, 'start_exclude': 0, 'end_exclude':0,
|
|
1248
|
+
'areal_density': 0}
|
|
1249
|
+
edge = self.edges[str(index)]
|
|
1250
|
+
|
|
1251
|
+
self.sidebar[5,0].value = edge['z']
|
|
1252
|
+
self.sidebar[5,2].value = edge['element']
|
|
1253
|
+
self.sidebar[6,0].value = edge['symmetry']
|
|
1254
|
+
self.sidebar[7,0].value = edge['onset']
|
|
1255
|
+
self.sidebar[8,0].value = edge['start_exclude']
|
|
1256
|
+
self.sidebar[9,0].value = edge['end_exclude']
|
|
1257
|
+
if self.y_scale == 1.0:
|
|
1258
|
+
self.sidebar[10, 0].value = edge['areal_density']
|
|
1259
|
+
self.sidebar[10, 2].value = 'a.u.'
|
|
1260
|
+
else:
|
|
1261
|
+
dispersion = self.energy_scale[1]-self.energy_scale[0]
|
|
1262
|
+
self.sidebar[10, 0].value = np.round(edge['areal_density']/self.dataset.metadata['experiment']['flux_ppm']*1e-6, 2)
|
|
1263
|
+
self.sidebar[10, 2].value = 'atoms/nm²'
|
|
1264
|
+
|
|
1265
|
+
|
|
1266
|
+
def do_fit(self, value=0):
|
|
1267
|
+
if 'experiment' in self.dataset.metadata:
|
|
1268
|
+
exp = self.dataset.metadata['experiment']
|
|
1269
|
+
if 'convergence_angle' not in exp:
|
|
1270
|
+
raise ValueError('need a convergence_angle in experiment of metadata dictionary ')
|
|
1271
|
+
alpha = exp['convergence_angle']
|
|
1272
|
+
beta = exp['collection_angle']
|
|
1273
|
+
beam_kv = exp['acceleration_voltage']
|
|
1274
|
+
|
|
1275
|
+
else:
|
|
1276
|
+
raise ValueError('need a experiment parameter in metadata dictionary')
|
|
1277
|
+
|
|
1278
|
+
eff_beta = eels.effective_collection_angle(self.energy_scale, alpha, beta, beam_kv)
|
|
1279
|
+
|
|
1280
|
+
self.low_loss = None
|
|
1281
|
+
if self.sidebar[12, 1].value:
|
|
1282
|
+
for key in self.datasets.keys():
|
|
1283
|
+
if key != self.key:
|
|
1284
|
+
if isinstance(self.datasets[key], sidpy.Dataset):
|
|
1285
|
+
if self.datasets[key].data_type.name == 'SPECTRUM':
|
|
1286
|
+
if self.datasets[key].energy_loss[0] < 0:
|
|
1287
|
+
self.low_loss = self.datasets[key]/self.datasets[key].sum()
|
|
1288
|
+
|
|
1289
|
+
edges = eels.make_cross_sections(self.edges, np.array(self.energy_scale), beam_kv, eff_beta, self.low_loss)
|
|
1290
|
+
|
|
1291
|
+
if self.dataset.data_type == sidpy.DataType.SPECTRAL_IMAGE:
|
|
1292
|
+
spectrum = self.dataset.view.get_spectrum()
|
|
1293
|
+
else:
|
|
1294
|
+
spectrum = self.dataset
|
|
1295
|
+
self.edges = eels.fit_edges2(spectrum, self.energy_scale, edges)
|
|
1296
|
+
areal_density = []
|
|
1297
|
+
elements = []
|
|
1298
|
+
for key in edges:
|
|
1299
|
+
if key.isdigit(): # only edges have numbers in that dictionary
|
|
1300
|
+
elements.append(edges[key]['element'])
|
|
1301
|
+
areal_density.append(edges[key]['areal_density'])
|
|
1302
|
+
areal_density = np.array(areal_density)
|
|
1303
|
+
out_string = '\nRelative composition: \n'
|
|
1304
|
+
for i, element in enumerate(elements):
|
|
1305
|
+
out_string += f'{element}: {areal_density[i] / areal_density.sum() * 100:.1f}% '
|
|
1306
|
+
|
|
1307
|
+
self.model = self.edges['model']['spectrum']
|
|
1308
|
+
self.update()
|
|
1309
|
+
self.plot()
|
|
1310
|
+
|
|
1311
|
+
def modify_onset(self, value=-1):
|
|
1312
|
+
edge_index = self.sidebar[4, 0].value
|
|
1313
|
+
edge = self.edges[str(edge_index)]
|
|
1314
|
+
edge['onset'] = self.sidebar[7,0].value
|
|
1315
|
+
edge['chemical_shift'] = edge['onset'] - edge['original_onset']
|
|
1316
|
+
self.update()
|
|
1317
|
+
|
|
1318
|
+
|
|
1319
|
+
def modify_start_exclude(self, value=-1):
|
|
1320
|
+
edge_index = self.sidebar[4, 0].value
|
|
1321
|
+
edge = self.edges[str(edge_index)]
|
|
1322
|
+
edge['start_exclude'] = self.sidebar[8,0].value
|
|
1323
|
+
self.plot()
|
|
1324
|
+
|
|
1325
|
+
def modify_end_exclude(self, value=-1):
|
|
1326
|
+
edge_index = self.sidebar[4, 0].value
|
|
1327
|
+
edge = self.edges[str(edge_index)]
|
|
1328
|
+
edge['end_exclude'] = self.sidebar[9,0].value
|
|
1329
|
+
self.plot()
|
|
1330
|
+
|
|
1331
|
+
def modify_areal_density(self, value=-1):
|
|
1332
|
+
edge_index = self.sidebar[4, 0].value
|
|
1333
|
+
edge = self.edges[str(edge_index)]
|
|
1334
|
+
|
|
1335
|
+
edge['areal_density'] = self.sidebar[10, 0].value
|
|
1336
|
+
if self.y_scale != 1.0:
|
|
1337
|
+
dispersion = self.energy_scale[1]-self.energy_scale[0]
|
|
1338
|
+
edge['areal_density'] = self.sidebar[10, 0].value *self.dataset.metadata['experiment']['flux_ppm']/1e-6
|
|
1339
|
+
|
|
1340
|
+
self.model = self.edges['model']['background']
|
|
1341
|
+
for key in self.edges:
|
|
1342
|
+
if key.isdigit():
|
|
1343
|
+
self.model = self.model + self.edges[key]['areal_density'] * self.edges[key]['data']
|
|
1344
|
+
self.plot()
|
|
1345
|
+
|
|
1346
|
+
def set_action(self):
|
|
1347
|
+
self.sidebar[1, 0].observe(self.set_fit_area, names='value')
|
|
1348
|
+
self.sidebar[2, 0].observe(self.set_fit_area, names='value')
|
|
1349
|
+
|
|
1350
|
+
self.sidebar[3, 0].on_click(self.find_elements)
|
|
1351
|
+
self.sidebar[4, 0].observe(self.update)
|
|
1352
|
+
self.sidebar[5, 0].observe(self.set_element, names='value')
|
|
1353
|
+
|
|
1354
|
+
self.sidebar[7, 0].observe(self.modify_onset, names='value')
|
|
1355
|
+
self.sidebar[8, 0].observe(self.modify_start_exclude, names='value')
|
|
1356
|
+
self.sidebar[9, 0].observe(self.modify_end_exclude, names='value')
|
|
1357
|
+
self.sidebar[10, 0].observe(self.modify_areal_density, names='value')
|
|
1358
|
+
|
|
1359
|
+
self.sidebar[11, 0].on_click(self.do_fit)
|
|
1360
|
+
self.sidebar[12, 2].observe(self.plot)
|
|
1361
|
+
self.sidebar[0, 0].observe(self.plot)
|
|
1362
|
+
|
|
1363
|
+
self.sidebar[12,0].observe(self.set_y_scale)
|