pyTEMlib 0.2023.8.0__py2.py3-none-any.whl → 0.2024.2.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/config_dir.py +0 -1
- pyTEMlib/crystal_tools.py +22 -26
- pyTEMlib/eds_tools.py +499 -46
- pyTEMlib/eels_dialog.py +284 -899
- pyTEMlib/eels_dialog_utilities.py +218 -341
- pyTEMlib/eels_tools.py +1526 -1583
- pyTEMlib/file_tools.py +52 -48
- pyTEMlib/graph_tools.py +3 -4
- pyTEMlib/image_tools.py +171 -41
- pyTEMlib/info_widget.py +618 -276
- pyTEMlib/kinematic_scattering.py +77 -512
- pyTEMlib/peak_dialog.py +162 -288
- pyTEMlib/version.py +2 -2
- pyTEMlib/xrpa_x_sections.py +173 -97
- {pyTEMlib-0.2023.8.0.dist-info → pyTEMlib-0.2024.2.0.dist-info}/LICENSE +1 -1
- {pyTEMlib-0.2023.8.0.dist-info → pyTEMlib-0.2024.2.0.dist-info}/METADATA +2 -2
- pyTEMlib-0.2024.2.0.dist-info/RECORD +35 -0
- {pyTEMlib-0.2023.8.0.dist-info → pyTEMlib-0.2024.2.0.dist-info}/WHEEL +1 -1
- pyTEMlib/eels_dlg.py +0 -252
- pyTEMlib/info_dialog.py +0 -665
- pyTEMlib/info_dlg.py +0 -239
- pyTEMlib/interactive_eels.py +0 -35
- pyTEMlib/viz.py +0 -481
- pyTEMlib-0.2023.8.0.dist-info/RECORD +0 -40
- {pyTEMlib-0.2023.8.0.dist-info → pyTEMlib-0.2024.2.0.dist-info}/entry_points.txt +0 -0
- {pyTEMlib-0.2023.8.0.dist-info → pyTEMlib-0.2024.2.0.dist-info}/top_level.txt +0 -0
|
@@ -6,23 +6,18 @@ Author: Gerd Duscher
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import numpy as np
|
|
9
|
-
Qt_available = True
|
|
10
|
-
try:
|
|
11
|
-
from PyQt5 import QtCore, QtGui, QtWidgets
|
|
12
|
-
|
|
13
|
-
except:
|
|
14
|
-
Qt_available = False
|
|
15
|
-
# print('Qt dialogs are not available')
|
|
16
9
|
|
|
17
10
|
import sidpy
|
|
11
|
+
import matplotlib
|
|
12
|
+
import matplotlib.pyplot as plt
|
|
13
|
+
|
|
18
14
|
import matplotlib.patches as patches
|
|
19
15
|
from matplotlib.widgets import RectangleSelector, SpanSelector
|
|
20
16
|
|
|
21
17
|
import h5py # TODO: needs to go
|
|
22
|
-
import matplotlib.pyplot as plt
|
|
23
18
|
|
|
24
19
|
from IPython.display import display
|
|
25
|
-
import ipywidgets
|
|
20
|
+
import ipywidgets
|
|
26
21
|
|
|
27
22
|
from pyTEMlib import eels_tools as eels
|
|
28
23
|
from pyTEMlib import file_tools as ft
|
|
@@ -32,319 +27,6 @@ all_edges = ['K1', 'L1', 'L2', 'L3', 'M1', 'M2', 'M3', 'M4', 'M5', 'N1', 'N2', '
|
|
|
32
27
|
'O3', 'O4', 'O5', 'O6', 'O7', 'P1', 'P2', 'P3']
|
|
33
28
|
first_close_edges = ['K1', 'L3', 'M5', 'M3', 'N5', 'N3']
|
|
34
29
|
|
|
35
|
-
if Qt_available:
|
|
36
|
-
|
|
37
|
-
class PeriodicTableDialog(QtWidgets.QDialog):
|
|
38
|
-
""" Modal dialog to get a selection of elements.
|
|
39
|
-
|
|
40
|
-
Elements that are not having a valid cross-sections are disabled.
|
|
41
|
-
|
|
42
|
-
Parameters
|
|
43
|
-
----------
|
|
44
|
-
initial_elements: list of str
|
|
45
|
-
the elements that are already selected
|
|
46
|
-
energy_scale: list or numpy array
|
|
47
|
-
energy-scale of spectrum/spectra to determine likely edges
|
|
48
|
-
|
|
49
|
-
Returns
|
|
50
|
-
-------
|
|
51
|
-
list of strings: elements.
|
|
52
|
-
|
|
53
|
-
Example
|
|
54
|
-
-------
|
|
55
|
-
>> PT_dialog = periodic_table_dialog(None, ['Mn', 'O'])
|
|
56
|
-
>> if PT_dialog.exec_() == periodic_table_dialog.Accepted:
|
|
57
|
-
>> selected_elements = PT_dialog.get_output()
|
|
58
|
-
>> print(selected_elements)
|
|
59
|
-
"""
|
|
60
|
-
|
|
61
|
-
signal_selected = QtCore.pyqtSignal(list)
|
|
62
|
-
|
|
63
|
-
def __init__(self, initial_elements=None, energy_scale=None, parent=None):
|
|
64
|
-
super(PeriodicTableDialog, self).__init__(None, QtCore.Qt.WindowStaysOnTopHint)
|
|
65
|
-
|
|
66
|
-
if initial_elements is None:
|
|
67
|
-
initial_elements = [' ']
|
|
68
|
-
self.initial_elements = initial_elements
|
|
69
|
-
if energy_scale is None:
|
|
70
|
-
energy_scale = [100., 150., 200.]
|
|
71
|
-
self.parent = parent
|
|
72
|
-
self._output = []
|
|
73
|
-
self.elements_selected = initial_elements
|
|
74
|
-
self.energy_scale = np.array(energy_scale)
|
|
75
|
-
|
|
76
|
-
self.setWindowTitle("Periodic Table")
|
|
77
|
-
likely_edges = get_likely_edges(self.energy_scale)
|
|
78
|
-
self.likely_edges = likely_edges
|
|
79
|
-
|
|
80
|
-
# GD:font = wx.Font(10, wx.MODERN, wx.NORMAL, wx.BOLD)
|
|
81
|
-
self.buttons1 = []
|
|
82
|
-
self.button = []
|
|
83
|
-
self.pt_info = get_periodic_table_info()
|
|
84
|
-
self.init_ui()
|
|
85
|
-
|
|
86
|
-
for button in self.button:
|
|
87
|
-
if button.text() in initial_elements:
|
|
88
|
-
button.toggle()
|
|
89
|
-
pass
|
|
90
|
-
|
|
91
|
-
def on_close(self):
|
|
92
|
-
self.get_output()
|
|
93
|
-
self.signal_selected[list].emit(self._output)
|
|
94
|
-
self.accept()
|
|
95
|
-
|
|
96
|
-
def get_output(self):
|
|
97
|
-
self._output = []
|
|
98
|
-
for btn in self.button:
|
|
99
|
-
if btn.isChecked():
|
|
100
|
-
self._output.append(btn.text())
|
|
101
|
-
|
|
102
|
-
def exec_(self):
|
|
103
|
-
super(PeriodicTableDialog, self).exec_()
|
|
104
|
-
return self._output
|
|
105
|
-
|
|
106
|
-
def init_ui(self):
|
|
107
|
-
|
|
108
|
-
v_sizer = QtWidgets.QVBoxLayout()
|
|
109
|
-
g_sizer = QtWidgets.QGridLayout()
|
|
110
|
-
|
|
111
|
-
main_group = QtWidgets.QWidget()
|
|
112
|
-
|
|
113
|
-
color1 = "background-color: lightblue;\n"
|
|
114
|
-
color1l = "background-color: dodgerblue;\n"
|
|
115
|
-
color2 = "background-color: coral;\n"
|
|
116
|
-
|
|
117
|
-
for symbol, parameter in self.pt_info.items():
|
|
118
|
-
self.button.append(QtWidgets.QPushButton(symbol))
|
|
119
|
-
if parameter['PT_row'] > 7:
|
|
120
|
-
self.button[-1].setStyleSheet(color2)
|
|
121
|
-
elif '*' in symbol:
|
|
122
|
-
self.button[-1].setStyleSheet(color2)
|
|
123
|
-
else:
|
|
124
|
-
if symbol in self.likely_edges:
|
|
125
|
-
self.button[-1].setStyleSheet(color1l)
|
|
126
|
-
else:
|
|
127
|
-
self.button[-1].setStyleSheet(color1)
|
|
128
|
-
if parameter['Z'] == 0:
|
|
129
|
-
self.button[-1].setEnabled(False)
|
|
130
|
-
self.button[-1].setFixedWidth(50)
|
|
131
|
-
self.button[-1].setCheckable(True)
|
|
132
|
-
g_sizer.addWidget(self.button[-1], parameter['PT_row'], parameter['PT_col'])
|
|
133
|
-
main_group.setLayout(g_sizer)
|
|
134
|
-
|
|
135
|
-
v_sizer.addWidget(main_group)
|
|
136
|
-
self.setLayout(v_sizer)
|
|
137
|
-
|
|
138
|
-
ok_button = QtWidgets.QPushButton('OK')
|
|
139
|
-
ok_button.clicked.connect(self.on_close)
|
|
140
|
-
|
|
141
|
-
v_sizer.addWidget(ok_button)
|
|
142
|
-
self.setLayout(v_sizer)
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
class EnergySelector(QtWidgets.QDialog):
|
|
146
|
-
"""Dialog and cursor to set energy scale"""
|
|
147
|
-
|
|
148
|
-
signal_selected = QtCore.pyqtSignal(bool)
|
|
149
|
-
|
|
150
|
-
def __init__(self, dset=None):
|
|
151
|
-
super(EnergySelector, self).__init__(None, QtCore.Qt.WindowStaysOnTopHint)
|
|
152
|
-
|
|
153
|
-
if not isinstance(dset, sidpy.Dataset):
|
|
154
|
-
return
|
|
155
|
-
if dset is None:
|
|
156
|
-
return
|
|
157
|
-
if dset.view is None:
|
|
158
|
-
return
|
|
159
|
-
self.dataset = dset
|
|
160
|
-
|
|
161
|
-
if hasattr(dset.view, 'axis'):
|
|
162
|
-
self.axis = dset.view.axis
|
|
163
|
-
# self.setWindowTitle('p')
|
|
164
|
-
elif hasattr(dset.view, 'axes'):
|
|
165
|
-
self.axis = dset.view.axes[1]
|
|
166
|
-
else:
|
|
167
|
-
return
|
|
168
|
-
|
|
169
|
-
self.spec_dim = -1
|
|
170
|
-
for dim, axis in self.dataset._axes.items():
|
|
171
|
-
if axis.dimension_type == sidpy.DimensionType.SPECTRAL:
|
|
172
|
-
self.spec_dim = dim
|
|
173
|
-
if self.spec_dim < 0:
|
|
174
|
-
raise TypeError('We need at least one SPECTRAL dimension')
|
|
175
|
-
|
|
176
|
-
self.energy_scale = self.dataset._axes[self.spec_dim].values
|
|
177
|
-
self.dispersion = self.energy_scale[1] - self.energy_scale[0]
|
|
178
|
-
self.offset = self.energy_scale[0]
|
|
179
|
-
self.spectrum = np.zeros(2)
|
|
180
|
-
|
|
181
|
-
self.change = 0
|
|
182
|
-
|
|
183
|
-
self.x_min = self.energy_scale[int(len(self.energy_scale)/4)]
|
|
184
|
-
self.x_max = self.energy_scale[int(len(self.energy_scale) / 4*3)]
|
|
185
|
-
self.setWindowTitle("Select Energy")
|
|
186
|
-
|
|
187
|
-
valid_float = QtGui.QDoubleValidator()
|
|
188
|
-
|
|
189
|
-
layout = QtWidgets.QGridLayout()
|
|
190
|
-
layout.setVerticalSpacing(2)
|
|
191
|
-
self.label1 = QtWidgets.QLabel('Start:')
|
|
192
|
-
self.edit1 = QtWidgets.QLineEdit('0')
|
|
193
|
-
self.edit1.setValidator(valid_float)
|
|
194
|
-
self.unit1 = QtWidgets.QLabel('eV')
|
|
195
|
-
|
|
196
|
-
self.label2 = QtWidgets.QLabel('End:')
|
|
197
|
-
self.edit2 = QtWidgets.QLineEdit('0')
|
|
198
|
-
self.edit2.setValidator(valid_float)
|
|
199
|
-
self.unit2 = QtWidgets.QLabel('eV')
|
|
200
|
-
|
|
201
|
-
self.label3 = QtWidgets.QLabel('Dispersion:')
|
|
202
|
-
self.edit3 = QtWidgets.QLineEdit('0')
|
|
203
|
-
self.edit3.setValidator(valid_float)
|
|
204
|
-
self.unit3 = QtWidgets.QLabel('eV')
|
|
205
|
-
|
|
206
|
-
self.edit1.editingFinished.connect(self.on_enter)
|
|
207
|
-
self.edit2.editingFinished.connect(self.on_enter)
|
|
208
|
-
self.edit3.editingFinished.connect(self.on_enter)
|
|
209
|
-
|
|
210
|
-
layout.addWidget(self.label1, 0, 0)
|
|
211
|
-
layout.addWidget(self.edit1, 0, 1)
|
|
212
|
-
layout.addWidget(self.unit1, 0, 2)
|
|
213
|
-
|
|
214
|
-
layout.addWidget(self.label2, 1, 0)
|
|
215
|
-
layout.addWidget(self.edit2, 1, 1)
|
|
216
|
-
layout.addWidget(self.unit2, 1, 2)
|
|
217
|
-
|
|
218
|
-
layout.addWidget(self.label3, 2, 0)
|
|
219
|
-
layout.addWidget(self.edit3, 2, 1)
|
|
220
|
-
layout.addWidget(self.unit3, 2, 2)
|
|
221
|
-
|
|
222
|
-
self.ok_button = QtWidgets.QPushButton('OK')
|
|
223
|
-
self.ok_button.clicked.connect(self.on_close)
|
|
224
|
-
self.cancel_button = QtWidgets.QPushButton('Cancel')
|
|
225
|
-
self.cancel_button.clicked.connect(self.on_close)
|
|
226
|
-
|
|
227
|
-
layout.addWidget(self.ok_button, 3, 0)
|
|
228
|
-
layout.addWidget(self.cancel_button, 3, 2)
|
|
229
|
-
|
|
230
|
-
self.setLayout(layout)
|
|
231
|
-
self.edit1.setFocus()
|
|
232
|
-
self.plot()
|
|
233
|
-
|
|
234
|
-
self.selector = SpanSelector(self.axis, self.line_select_callback,
|
|
235
|
-
direction="horizontal",
|
|
236
|
-
interactive=True,
|
|
237
|
-
props=dict(facecolor='blue', alpha=0.2))
|
|
238
|
-
self.edit1.setText(f'{self.x_min:.3f}')
|
|
239
|
-
self.edit2.setText(f'{self.x_max:.3f}')
|
|
240
|
-
self.edit3.setText(f'{self.dispersion:.4f}')
|
|
241
|
-
self.update()
|
|
242
|
-
|
|
243
|
-
def line_select_callback(self, eclick, erelease):
|
|
244
|
-
y_min, y_max = self.axis.get_ylim()
|
|
245
|
-
self.x_min = self.selector.extents[0]
|
|
246
|
-
self.x_max = self.selector.extents[1]
|
|
247
|
-
# self.selector.extents = (self.x_min, self.x_max, y_min, y_max)
|
|
248
|
-
|
|
249
|
-
self.edit1.setText(f'{self.x_min:.3f}')
|
|
250
|
-
self.edit2.setText(f'{self.x_max:.3f}')
|
|
251
|
-
|
|
252
|
-
def on_enter(self):
|
|
253
|
-
sender = self.sender()
|
|
254
|
-
|
|
255
|
-
if sender == self.edit1:
|
|
256
|
-
value = float(str(sender.displayText()).strip())
|
|
257
|
-
if value == self.x_min:
|
|
258
|
-
return
|
|
259
|
-
self.change = value - self.x_min
|
|
260
|
-
self.x_min += self.change
|
|
261
|
-
self.x_max += self.change
|
|
262
|
-
self.offset += self.change
|
|
263
|
-
|
|
264
|
-
self.edit1.setText(f"{self.x_min:.2f}")
|
|
265
|
-
self.edit2.setText(f"{self.x_max:.2f}")
|
|
266
|
-
|
|
267
|
-
self.energy_scale = np.arange(len(self.energy_scale)) * self.dispersion + self.offset
|
|
268
|
-
|
|
269
|
-
self.update()
|
|
270
|
-
# self.axis.draw()
|
|
271
|
-
# self.setWindowTitle(f'shift, {self.change}, {self.x_min}')
|
|
272
|
-
|
|
273
|
-
elif sender == self.edit2:
|
|
274
|
-
value = float(str(sender.displayText()).strip())
|
|
275
|
-
if value == self.x_max:
|
|
276
|
-
return
|
|
277
|
-
start_channel = np.searchsorted(self.energy_scale, self.x_min)
|
|
278
|
-
end_channel = np.searchsorted(self.energy_scale, self.x_max)
|
|
279
|
-
|
|
280
|
-
self.x_max = value
|
|
281
|
-
|
|
282
|
-
if end_channel - start_channel != 0:
|
|
283
|
-
self.dispersion = (self.x_max - self.x_min) / (end_channel - start_channel)
|
|
284
|
-
self.offset = self.x_min - start_channel * self.dispersion
|
|
285
|
-
self.edit2.setText(f"{self.x_max:.3f}")
|
|
286
|
-
self.edit3.setText(f"{self.dispersion:.4f}")
|
|
287
|
-
self.energy_scale = np.arange(len(self.energy_scale)) * self.dispersion + self.offset
|
|
288
|
-
|
|
289
|
-
self.update()
|
|
290
|
-
# self.axis.draw()
|
|
291
|
-
# self.setWindowTitle(f'range, {self.change}, {self.dispersion}')
|
|
292
|
-
|
|
293
|
-
elif sender == self.edit3:
|
|
294
|
-
value = float(str(sender.displayText()).strip())
|
|
295
|
-
if self.dispersion == value:
|
|
296
|
-
return
|
|
297
|
-
|
|
298
|
-
start_channel = np.searchsorted(self.energy_scale, self.x_min)
|
|
299
|
-
end_channel = np.searchsorted(self.energy_scale, self.x_max)
|
|
300
|
-
self.dispersion = value
|
|
301
|
-
self.energy_scale = np.arange(len(self.energy_scale)) * self.dispersion + self.offset
|
|
302
|
-
self.x_min = self.energy_scale[start_channel]
|
|
303
|
-
self.x_max = self.energy_scale[end_channel]
|
|
304
|
-
self.update()
|
|
305
|
-
# self.axis.draw()
|
|
306
|
-
self.edit3.setText(f"{self.dispersion:.3f}")
|
|
307
|
-
self.change = 0
|
|
308
|
-
|
|
309
|
-
def on_close(self):
|
|
310
|
-
sender = self.sender()
|
|
311
|
-
if sender == self.ok_button:
|
|
312
|
-
pass
|
|
313
|
-
self.dataset.set_dimension(self.spec_dim, sidpy.Dimension(self.energy_scale, name='energy_scale',
|
|
314
|
-
units='eV', quantity='energy loss',
|
|
315
|
-
dimension_type='spectral'))
|
|
316
|
-
else:
|
|
317
|
-
pass
|
|
318
|
-
self.selector.set_visible(False)
|
|
319
|
-
self.signal_selected[bool].emit(True)
|
|
320
|
-
self.accept()
|
|
321
|
-
|
|
322
|
-
def plot(self):
|
|
323
|
-
if self.dataset.data_type == sidpy.DataType.SPECTRAL_IMAGE:
|
|
324
|
-
self.spectrum = self.dataset.view.get_spectrum()
|
|
325
|
-
else:
|
|
326
|
-
self.spectrum = np.array(self.dataset)
|
|
327
|
-
x_limit = self.axis.get_xlim()
|
|
328
|
-
y_limit = self.axis.get_ylim()
|
|
329
|
-
|
|
330
|
-
self.axis.clear()
|
|
331
|
-
self.cplot = self.axis.plot(self.energy_scale, self.spectrum, label='spectrum')
|
|
332
|
-
self.axis.set_xlim(x_limit)
|
|
333
|
-
self.axis.set_ylim(y_limit)
|
|
334
|
-
|
|
335
|
-
self.axis.figure.canvas.draw()
|
|
336
|
-
|
|
337
|
-
def update(self):
|
|
338
|
-
x_limit = self.axis.get_xlim()
|
|
339
|
-
y_limit = self.axis.get_ylim()
|
|
340
|
-
self.selector.extents = (self.x_min, self.x_max)
|
|
341
|
-
|
|
342
|
-
x_limit = np.array(x_limit) + self.change
|
|
343
|
-
|
|
344
|
-
self.cplot[0].set_data(self.energy_scale, self.spectrum)
|
|
345
|
-
self.axis.set_xlim(x_limit)
|
|
346
|
-
self.axis.set_ylim(y_limit)
|
|
347
|
-
self.axis.figure.canvas.draw()
|
|
348
30
|
|
|
349
31
|
|
|
350
32
|
class RegionSelector(object):
|
|
@@ -553,6 +235,201 @@ def get_likely_edges(energy_scale):
|
|
|
553
235
|
|
|
554
236
|
return likely_edges
|
|
555
237
|
|
|
238
|
+
|
|
239
|
+
class SpectrumPlot(sidpy.viz.dataset_viz.CurveVisualizer):
|
|
240
|
+
def __init__(self, dset, spectrum_number=0, figure=None, **kwargs):
|
|
241
|
+
with plt.ioff():
|
|
242
|
+
self.figure = plt.figure()
|
|
243
|
+
self.figure.canvas.toolbar_position = 'right'
|
|
244
|
+
self.figure.canvas.toolbar_visible = True
|
|
245
|
+
|
|
246
|
+
super().__init__(dset, spectrum_number=spectrum_number, figure=self.figure, **kwargs)
|
|
247
|
+
try:
|
|
248
|
+
self.dataset = self.dset
|
|
249
|
+
except:
|
|
250
|
+
pass
|
|
251
|
+
self.start_cursor = ipywidgets.FloatText(value=0, description='Start:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
|
|
252
|
+
self.end_cursor = ipywidgets.FloatText(value=0, description='End:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
|
|
253
|
+
self.panel = ipywidgets.VBox([ipywidgets.HBox([ipywidgets.Label('',layout=ipywidgets.Layout(width='100px')), ipywidgets.Label('Cursor:'),
|
|
254
|
+
self.start_cursor,ipywidgets.Label('eV'),
|
|
255
|
+
self.end_cursor, ipywidgets.Label('eV')]),
|
|
256
|
+
self.figure.canvas])
|
|
257
|
+
|
|
258
|
+
self.selector = matplotlib.widgets.SpanSelector(self.axis, self.line_select_callback,
|
|
259
|
+
direction="horizontal",
|
|
260
|
+
interactive=True,
|
|
261
|
+
props=dict(facecolor='blue', alpha=0.2))
|
|
262
|
+
|
|
263
|
+
def line_select_callback(self, x_min, x_max):
|
|
264
|
+
self.start_cursor.value = np.round(x_min, 3)
|
|
265
|
+
self.end_cursor.value = np.round(x_max, 3)
|
|
266
|
+
self.start_channel = np.searchsorted(self.dataset.energy_loss, self.start_cursor.value)
|
|
267
|
+
self.end_channel = np.searchsorted(self.dataset.energy_loss, self.end_cursor.value)
|
|
268
|
+
|
|
269
|
+
def plot(self, scale=True, additional_spectra=None):
|
|
270
|
+
self.dataset = self.dset
|
|
271
|
+
self.energy_scale = self.dataset.energy_loss.values
|
|
272
|
+
x_limit = self.axis.get_xlim()
|
|
273
|
+
y_limit = np.array(self.axis.get_ylim())
|
|
274
|
+
|
|
275
|
+
self.axis.clear()
|
|
276
|
+
|
|
277
|
+
self.axis.plot(self.energy_scale, self.dataset*self.y_scale, label='spectrum')
|
|
278
|
+
|
|
279
|
+
if additional_spectra is not None:
|
|
280
|
+
if isinstance(additional_spectra, dict):
|
|
281
|
+
for key, spectrum in additional_spectra.items():
|
|
282
|
+
self.axis.plot(self.energy_scale, spectrum*self.y_scale, label=key)
|
|
283
|
+
|
|
284
|
+
self.axis.set_xlabel(self.dataset.labels[0])
|
|
285
|
+
self.axis.set_ylabel(self.dataset.data_descriptor)
|
|
286
|
+
self.axis.ticklabel_format(style='sci', scilimits=(-2, 3))
|
|
287
|
+
if scale:
|
|
288
|
+
self.axis.set_ylim(np.array(y_limit)*self.change_y_scale)
|
|
289
|
+
|
|
290
|
+
self.change_y_scale = 1.0
|
|
291
|
+
if self.y_scale != 1.:
|
|
292
|
+
self.axis.set_ylabel('scattering probability (ppm/eV)')
|
|
293
|
+
self.selector = matplotlib.widgets.SpanSelector(self.axis, self.line_select_callback,
|
|
294
|
+
direction="horizontal",
|
|
295
|
+
interactive=True,
|
|
296
|
+
props=dict(facecolor='blue', alpha=0.2))
|
|
297
|
+
self.axis.legend()
|
|
298
|
+
self.figure.canvas.draw_idle()
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
class SIPlot(sidpy.viz.dataset_viz.SpectralImageVisualizerBase):
|
|
302
|
+
def __init__(self, dset, figure=None, horizontal=True, **kwargs):
|
|
303
|
+
if figure is None:
|
|
304
|
+
with plt.ioff():
|
|
305
|
+
self.figure = plt.figure()
|
|
306
|
+
else:
|
|
307
|
+
self.figure = figure
|
|
308
|
+
self.figure.canvas.toolbar_position = 'right'
|
|
309
|
+
self.figure.canvas.toolbar_visible = True
|
|
310
|
+
self.dset = dset
|
|
311
|
+
super().__init__(self.dset, figure=self.figure, horizontal=horizontal, **kwargs)
|
|
312
|
+
|
|
313
|
+
self.start_cursor = ipywidgets.FloatText(value=0, description='Start:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
|
|
314
|
+
self.end_cursor = ipywidgets.FloatText(value=0, description='End:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
|
|
315
|
+
self.panel = ipywidgets.VBox([ipywidgets.HBox([ipywidgets.Label('',layout=ipywidgets.Layout(width='100px')), ipywidgets.Label('Cursor:'),
|
|
316
|
+
self.start_cursor,ipywidgets.Label('eV'),
|
|
317
|
+
self.end_cursor, ipywidgets.Label('eV')]),
|
|
318
|
+
self.figure.canvas])
|
|
319
|
+
self.axis = self.axes[-1]
|
|
320
|
+
self.selector = matplotlib.widgets.SpanSelector(self.axis, self.line_select_callback,
|
|
321
|
+
direction="horizontal",
|
|
322
|
+
interactive=True,
|
|
323
|
+
props=dict(facecolor='blue', alpha=0.2))
|
|
324
|
+
|
|
325
|
+
def line_select_callback(self, x_min, x_max):
|
|
326
|
+
self.start_cursor.value = np.round(x_min, 3)
|
|
327
|
+
self.end_cursor.value = np.round(x_max, 3)
|
|
328
|
+
self.start_channel = np.searchsorted(self.dataset.energy_loss, self.start_cursor.value)
|
|
329
|
+
self.end_channel = np.searchsorted(self.dataset.energy_loss, self.end_cursor.value)
|
|
330
|
+
|
|
331
|
+
def plot(self, scale=True, additional_spectra=None):
|
|
332
|
+
|
|
333
|
+
xlim = self.axes[1].get_xlim()
|
|
334
|
+
ylim = self.axes[1].get_ylim()
|
|
335
|
+
self.axes[1].clear()
|
|
336
|
+
self.get_spectrum()
|
|
337
|
+
if len(self.energy_scale)!=self.spectrum.shape[0]:
|
|
338
|
+
self.spectrum = self.spectrum.T
|
|
339
|
+
self.axes[1].plot(self.energy_scale, self.spectrum.compute(), label='experiment')
|
|
340
|
+
if additional_spectra is not None:
|
|
341
|
+
if isinstance(additional_spectra, dict):
|
|
342
|
+
for key, spectrum in additional_spectra.items():
|
|
343
|
+
self.axes[1].plot(self.energy_scale, spectrum, label=key)
|
|
344
|
+
|
|
345
|
+
if self.set_title:
|
|
346
|
+
self.axes[1].set_title('spectrum {}, {}'.format(self.x, self.y))
|
|
347
|
+
self.fig.tight_layout()
|
|
348
|
+
self.selector = matplotlib.widgets.SpanSelector(self.axes[1], self.line_select_callback,
|
|
349
|
+
direction="horizontal",
|
|
350
|
+
interactive=True,
|
|
351
|
+
props=dict(facecolor='blue', alpha=0.2))
|
|
352
|
+
|
|
353
|
+
self.axes[1].set_xlim(xlim)
|
|
354
|
+
self.axes[1].set_ylim(ylim)
|
|
355
|
+
self.axes[1].set_xlabel(self.xlabel)
|
|
356
|
+
self.axes[1].set_ylabel(self.ylabel)
|
|
357
|
+
|
|
358
|
+
self.fig.canvas.draw_idle()
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def get_periodic_table_widget(energy_scale=None):
|
|
362
|
+
|
|
363
|
+
if energy_scale is None:
|
|
364
|
+
energy_scale = [100., 150., 200.]
|
|
365
|
+
|
|
366
|
+
likely_edges = get_likely_edges(energy_scale)
|
|
367
|
+
|
|
368
|
+
pt_info = get_periodic_table_info()
|
|
369
|
+
table = ipywidgets.GridspecLayout(10, 18,width= '60%', grid_gap="0px")
|
|
370
|
+
for symbol, parameter in pt_info.items():
|
|
371
|
+
#print(parameter['PT_row'], parameter['PT_col'])
|
|
372
|
+
if parameter['PT_row'] > 7:
|
|
373
|
+
color = 'warning'
|
|
374
|
+
elif '*' in symbol:
|
|
375
|
+
color = 'warning'
|
|
376
|
+
else:
|
|
377
|
+
if symbol in likely_edges:
|
|
378
|
+
color = 'primary'
|
|
379
|
+
else:
|
|
380
|
+
color = 'info'
|
|
381
|
+
table[parameter['PT_row'], parameter['PT_col']] = ipywidgets.ToggleButton(description=symbol,
|
|
382
|
+
value=False,
|
|
383
|
+
button_style=color,
|
|
384
|
+
layout=ipywidgets.Layout(width='auto'),
|
|
385
|
+
style={"button_width": "30px"})
|
|
386
|
+
return table
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
class PeriodicTableWidget(object):
|
|
390
|
+
""" ipywidget to get a selection of elements.
|
|
391
|
+
|
|
392
|
+
Elements that are not having a valid cross-sections are disabled.
|
|
393
|
+
|
|
394
|
+
Parameters
|
|
395
|
+
----------
|
|
396
|
+
initial_elements: list of str
|
|
397
|
+
the elements that are already selected
|
|
398
|
+
energy_scale: list or numpy array
|
|
399
|
+
energy-scale of spectrum/spectra to determine likely edges
|
|
400
|
+
|
|
401
|
+
Returns
|
|
402
|
+
-------
|
|
403
|
+
list of strings: elements.
|
|
404
|
+
use get_output() function
|
|
405
|
+
"""
|
|
406
|
+
|
|
407
|
+
def __init__(self, initial_elements=None, energy_scale=None):
|
|
408
|
+
|
|
409
|
+
if initial_elements is None:
|
|
410
|
+
initial_elements = [' ']
|
|
411
|
+
self.elements_selected = initial_elements
|
|
412
|
+
if energy_scale is None:
|
|
413
|
+
energy_scale = [100., 150., 200.]
|
|
414
|
+
self._output = []
|
|
415
|
+
self.energy_scale = np.array(energy_scale)
|
|
416
|
+
self.pt_info = get_periodic_table_info()
|
|
417
|
+
|
|
418
|
+
self.periodic_table = get_periodic_table_widget(energy_scale)
|
|
419
|
+
self.update()
|
|
420
|
+
|
|
421
|
+
def get_output(self):
|
|
422
|
+
self.elements_selected = []
|
|
423
|
+
for symbol, parameter in self.pt_info.items():
|
|
424
|
+
if self.periodic_table[parameter['PT_row'], parameter['PT_col']].value == True: # [parameter['PT_row'], parameter['PT_col']]
|
|
425
|
+
self.elements_selected.append(self.periodic_table[parameter['PT_row'], parameter['PT_col']].description)
|
|
426
|
+
return self.elements_selected
|
|
427
|
+
|
|
428
|
+
def update(self):
|
|
429
|
+
for symbol, parameter in self.pt_info.items():
|
|
430
|
+
if str(self.periodic_table[parameter['PT_row'], parameter['PT_col']].description) in list(self.elements_selected):
|
|
431
|
+
self.periodic_table[parameter['PT_row'], parameter['PT_col']].value = True
|
|
432
|
+
|
|
556
433
|
|
|
557
434
|
|
|
558
435
|
|
|
@@ -651,15 +528,15 @@ class InteractiveSpectrumImage(object):
|
|
|
651
528
|
|
|
652
529
|
def __init__(self, data_source, horizontal=True):
|
|
653
530
|
|
|
654
|
-
box_layout =
|
|
531
|
+
box_layout = ipywidgets.Layout(display='flex',
|
|
655
532
|
flex_flow='row',
|
|
656
533
|
align_items='stretch',
|
|
657
534
|
width='100%')
|
|
658
535
|
|
|
659
536
|
words = ['fix_energy', 'fit_zero_loss', 'fit_low_loss', 'fit_composition', 'fit_ELNES']
|
|
660
537
|
|
|
661
|
-
self.buttons = [
|
|
662
|
-
box =
|
|
538
|
+
self.buttons = [ipywidgets.ToggleButton(value=False, description=word, disabled=False) for word in words]
|
|
539
|
+
box = ipywidgets.Box(children=self.buttons, layout=box_layout)
|
|
663
540
|
display(box)
|
|
664
541
|
|
|
665
542
|
# MAKE Dictionary
|
|
@@ -1198,13 +1075,13 @@ class EdgesAtCursor(object):
|
|
|
1198
1075
|
|
|
1199
1076
|
|
|
1200
1077
|
def make_box_layout():
|
|
1201
|
-
return
|
|
1078
|
+
return ipywidgets.Layout(border='solid 1px black', margin='0px 10px 10px 0px', padding='5px 5px 5px 5px')
|
|
1202
1079
|
|
|
1203
1080
|
|
|
1204
|
-
class plot_EELS(
|
|
1081
|
+
class plot_EELS(ipywidgets.HBox):
|
|
1205
1082
|
def __init__(self, dataset):
|
|
1206
1083
|
super().__init__()
|
|
1207
|
-
output =
|
|
1084
|
+
output = ipywidgets.Output()
|
|
1208
1085
|
self.dataset = dataset
|
|
1209
1086
|
self.spec_dim = 0
|
|
1210
1087
|
initial_color = '#FF00DD'
|
|
@@ -1226,48 +1103,48 @@ class plot_EELS(widgets.HBox):
|
|
|
1226
1103
|
self.fig.canvas.mpl_connect('pick_event', self.on_legend_pick)
|
|
1227
1104
|
|
|
1228
1105
|
# define widgets
|
|
1229
|
-
int_slider =
|
|
1106
|
+
int_slider = ipywidgets.IntSlider(
|
|
1230
1107
|
value=1,
|
|
1231
1108
|
min=0,
|
|
1232
1109
|
max=10,
|
|
1233
1110
|
step=1,
|
|
1234
1111
|
description='freq'
|
|
1235
1112
|
)
|
|
1236
|
-
self.offset =
|
|
1113
|
+
self.offset = ipywidgets.Text(
|
|
1237
1114
|
value='0',
|
|
1238
1115
|
width=5,
|
|
1239
1116
|
description='offset',
|
|
1240
1117
|
continuous_update=False
|
|
1241
1118
|
)
|
|
1242
|
-
self.dispersion =
|
|
1119
|
+
self.dispersion = ipywidgets.Text(
|
|
1243
1120
|
value='0',
|
|
1244
1121
|
width=5,
|
|
1245
1122
|
description='dispersion',
|
|
1246
1123
|
continuous_update=False
|
|
1247
1124
|
)
|
|
1248
1125
|
|
|
1249
|
-
self.exposure =
|
|
1126
|
+
self.exposure = ipywidgets.Text(
|
|
1250
1127
|
value='0',
|
|
1251
1128
|
width=5,
|
|
1252
1129
|
description='exposure',
|
|
1253
1130
|
continuous_update=False
|
|
1254
1131
|
)
|
|
1255
1132
|
|
|
1256
|
-
button_energy_scale =
|
|
1257
|
-
button_elements_at_cursor =
|
|
1258
|
-
button_main_elements =
|
|
1133
|
+
button_energy_scale = ipywidgets.Button(description='Cursor')
|
|
1134
|
+
button_elements_at_cursor = ipywidgets.Button(description='Elements Cursor')
|
|
1135
|
+
button_main_elements = ipywidgets.Button(description='Main Elements')
|
|
1259
1136
|
|
|
1260
|
-
controls =
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1137
|
+
controls = ipywidgets.VBox([
|
|
1138
|
+
ipywidgets.HBox([self.offset, ipywidgets.Label('eV')]),
|
|
1139
|
+
ipywidgets.HBox([self.dispersion, ipywidgets.Label('eV/channel')]),
|
|
1140
|
+
ipywidgets.HBox([self.exposure, ipywidgets.Label('s')]),
|
|
1264
1141
|
button_energy_scale,
|
|
1265
|
-
|
|
1142
|
+
ipywidgets.HBox([button_elements_at_cursor, button_main_elements])
|
|
1266
1143
|
])
|
|
1267
1144
|
|
|
1268
1145
|
controls.layout = make_box_layout()
|
|
1269
1146
|
|
|
1270
|
-
out_box =
|
|
1147
|
+
out_box = ipywidgets.Box([output])
|
|
1271
1148
|
output.layout = make_box_layout()
|
|
1272
1149
|
|
|
1273
1150
|
# observe stuff
|