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.

@@ -0,0 +1,655 @@
1
+ import numpy as np
2
+ import sidpy
3
+
4
+
5
+ import pyTEMlib.eels_dialog_utilities as ieels
6
+ import pyTEMlib.file_tools as ft
7
+ from pyTEMlib.microscope import microscope
8
+ import ipywidgets
9
+ import matplotlib.pylab as plt
10
+ import matplotlib
11
+
12
+ from IPython.display import display
13
+
14
+
15
+ from pyTEMlib import file_tools
16
+ from pyTEMlib import eels_tools
17
+
18
+ def get_info_sidebar():
19
+ side_bar = ipywidgets.GridspecLayout(17, 3,width='auto', grid_gap="0px")
20
+
21
+ side_bar[0, :2] = ipywidgets.Dropdown(
22
+ options=[('None', 0)],
23
+ value=0,
24
+ description='Main Dataset:',
25
+ disabled=False)
26
+
27
+ row = 1
28
+ side_bar[row, :3] = ipywidgets.Button(description='Energy Scale',
29
+ layout=ipywidgets.Layout(width='auto', grid_area='header'),
30
+ style=ipywidgets.ButtonStyle(button_color='lightblue'))
31
+ row += 1
32
+ side_bar[row, :2] = ipywidgets.FloatText(value=7.5,description='Offset:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
33
+ side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='20px'))
34
+ row += 1
35
+ side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Dispersion:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
36
+ side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='20px'))
37
+
38
+ row += 1
39
+ side_bar[row, :3] = ipywidgets.Button(description='Microscope',
40
+ layout=ipywidgets.Layout(width='auto', grid_area='header'),
41
+ style=ipywidgets.ButtonStyle(button_color='lightblue'))
42
+ row += 1
43
+ side_bar[row, :2] = ipywidgets.FloatText(value=7.5,description='Conv.Angle:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
44
+ side_bar[row, 2] = ipywidgets.widgets.Label(value="mrad", layout=ipywidgets.Layout(width='100px'))
45
+ row += 1
46
+ side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Coll.Angle:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
47
+ side_bar[row, 2] = ipywidgets.widgets.Label(value="mrad", layout=ipywidgets.Layout(width='100px'))
48
+ row += 1
49
+ side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Acc Voltage:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
50
+ side_bar[row, 2] = ipywidgets.widgets.Label(value="keV", layout=ipywidgets.Layout(width='100px'))
51
+ row += 1
52
+
53
+ side_bar[row, :3] = ipywidgets.Button(description='Quantification',
54
+ layout=ipywidgets.Layout(width='auto', grid_area='header'),
55
+ style=ipywidgets.ButtonStyle(button_color='lightblue'))
56
+ row+=1
57
+ side_bar[row, :2] = ipywidgets.Dropdown(
58
+ options=[('None', 0)],
59
+ value=0,
60
+ description='Reference:',
61
+ disabled=False)
62
+ side_bar[row,2] = ipywidgets.ToggleButton(
63
+ description='Probability',
64
+ disabled=False,
65
+ button_style='', # 'success', 'info', 'warning', 'danger' or ''
66
+ tooltip='Changes y-axis to probability if flux is given',
67
+ layout=ipywidgets.Layout(width='100px'))
68
+ row += 1
69
+ side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Exp_Time:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
70
+ side_bar[row, 2] = ipywidgets.widgets.Label(value="s", layout=ipywidgets.Layout(width='100px'))
71
+ row += 1
72
+ side_bar[row, :2] = ipywidgets.FloatText(value=7.5,description='Flux:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
73
+ side_bar[row, 2] = ipywidgets.widgets.Label(value="Mcounts", layout=ipywidgets.Layout(width='100px'))
74
+ row += 1
75
+ side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Conversion:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
76
+ side_bar[row, 2] = ipywidgets.widgets.Label(value=r"e$^-$/counts", layout=ipywidgets.Layout(width='100px'))
77
+ row += 1
78
+ side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Current:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
79
+ side_bar[row, 2] = ipywidgets.widgets.Label(value="pA", layout=ipywidgets.Layout(width='100px') )
80
+
81
+ row += 1
82
+
83
+ side_bar[row, :3] = ipywidgets.Button(description='Spectrum Image',
84
+ layout=ipywidgets.Layout(width='auto', grid_area='header'),
85
+ style=ipywidgets.ButtonStyle(button_color='lightblue'))
86
+
87
+ row += 1
88
+ side_bar[row, :2] = ipywidgets.IntText(value=1, description='bin X:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
89
+ row += 1
90
+ side_bar[row, :2] = ipywidgets.IntText(value=1, description='bin X:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
91
+
92
+ for i in range(14, 17):
93
+ side_bar[i, 0].layout.display = "none"
94
+ return side_bar
95
+
96
+ from sidpy.io.interface_utils import open_file_dialog
97
+ class EELSWidget(object):
98
+ def __init__(self, datasets, sidebar, tab_title = None):
99
+
100
+ self.datasets = datasets
101
+ self.dataset = None
102
+
103
+ if not isinstance(sidebar, list):
104
+ tab = ipywidgets.Tab()
105
+ tab.children = [ft.FileWidget(), sidebar]
106
+ tab.titles = ['Load', 'Info']
107
+ else:
108
+ tab = sidebar
109
+
110
+ self.sidebar = sidebar
111
+ with plt.ioff():
112
+ self.figure = plt.figure()
113
+
114
+ self.figure.canvas.toolbar_position = 'right'
115
+ self.figure.canvas.toolbar_visible = True
116
+
117
+ self.start_cursor = ipywidgets.FloatText(value=0, description='Start:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
118
+ self.end_cursor = ipywidgets.FloatText(value=0, description='End:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
119
+ self.panel = ipywidgets.VBox([ipywidgets.HBox([ipywidgets.Label('',layout=ipywidgets.Layout(width='100px')), ipywidgets.Label('Cursor:'),
120
+ self.start_cursor,ipywidgets.Label('eV'),
121
+ self.end_cursor, ipywidgets.Label('eV')]),
122
+ self.figure.canvas])
123
+
124
+
125
+ self.app_layout = ipywidgets.AppLayout(
126
+ left_sidebar=tab,
127
+ center=self.panel,
128
+ footer=None,#message_bar,
129
+ pane_heights=[0, 10, 0],
130
+ pane_widths=[4, 10, 0],
131
+ )
132
+ self.set_dataset()
133
+
134
+ display(self.app_layout)
135
+
136
+ def plot(self, scale=True):
137
+ self.figure.clear()
138
+ self.energy_scale = self.dataset.energy_loss.values
139
+
140
+ if self.dataset.data_type.name == 'SPECTRUM':
141
+ self.axis = self.figure.subplots(ncols=1)
142
+ else:
143
+ self.plot_spectrum_image()
144
+ self.axis = self.axes[-1]
145
+ self.spectrum = self.get_spectrum()
146
+
147
+ self.plot_spectrum()
148
+
149
+ def plot_spectrum(self):
150
+ self.axis.plot(self.energy_scale, self.spectrum, label='spectrum')
151
+ x_limit = self.axis.get_xlim()
152
+ y_limit = np.array(self.axis.get_ylim())
153
+ self.xlabel = self.datasets[self.key].labels[0]
154
+ self.ylabel = self.datasets[self.key].data_descriptor
155
+ self.axis.set_xlabel(self.datasets[self.key].labels[0])
156
+ self.axis.set_ylabel(self.datasets[self.key].data_descriptor)
157
+ self.axis.ticklabel_format(style='sci', scilimits=(-2, 3))
158
+ #if scale:
159
+ # self.axis.set_ylim(np.array(y_limit)*self.change_y_scale)
160
+ self.change_y_scale = 1.0
161
+ if self.y_scale != 1.:
162
+ self.axis.set_ylabel('scattering probability (ppm/eV)')
163
+ self.selector = matplotlib.widgets.SpanSelector(self.axis, self.line_select_callback,
164
+ direction="horizontal",
165
+ interactive=True,
166
+ props=dict(facecolor='blue', alpha=0.2))
167
+ self.axis.legend()
168
+ if self.dataset.data_type.name == 'SPECTRUM':
169
+ self.axis.set_title(self.dataset.title)
170
+ else:
171
+ self.axis.set_title(f'spectrum {self.x}, {self.y}')
172
+ self.figure.canvas.draw_idle()
173
+
174
+ def _update(self, ev=None):
175
+
176
+ xlim = np.array(self.axes[1].get_xlim())
177
+ ylim = np.array(self.axes[1].get_ylim())
178
+ self.axes[1].clear()
179
+ self.get_spectrum()
180
+ if len(self.energy_scale)!=self.spectrum.shape[0]:
181
+ self.spectrum = self.spectrum.T
182
+ self.axes[1].plot(self.energy_scale, self.spectrum.compute(), label='experiment')
183
+
184
+ self.axes[1].set_title(f'spectrum {self.x}, {self.y}')
185
+ self.figure.tight_layout()
186
+ self.selector = matplotlib.widgets.SpanSelector(self.axis, self.line_select_callback,
187
+ direction="horizontal",
188
+ interactive=True,
189
+ props=dict(facecolor='blue', alpha=0.2))
190
+
191
+ self.axes[1].set_xlim(xlim)
192
+ self.axes[1].set_ylim(ylim*self.change_y_scale)
193
+ self.axes[1].set_xlabel(self.xlabel)
194
+ self.axes[1].set_ylabel(self.ylabel)
195
+ self.change_y_scale = 1.0
196
+ self.figure.canvas.draw_idle()
197
+
198
+ def _onclick(self, event):
199
+ self.event = event
200
+ if event.inaxes in [self.axes[0]]:
201
+ x = int(event.xdata)
202
+ y = int(event.ydata)
203
+
204
+ x = int(x - self.rectangle[0])
205
+ y = int(y - self.rectangle[2])
206
+
207
+ if x >= 0 and y >= 0:
208
+ if x <= self.rectangle[1] and y <= self.rectangle[3]:
209
+ self.x = int(x / (self.rect.get_width() / self.bin_x))
210
+ self.y = int(y / (self.rect.get_height() / self.bin_y))
211
+ image_dims = self.dataset.get_dimensions_by_type(sidpy.DimensionType.SPATIAL)
212
+
213
+ if self.x + self.bin_x > self.dataset.shape[image_dims[0]]:
214
+ self.x = self.dataset.shape[image_dims[0]] - self.bin_x
215
+ if self.y + self.bin_y > self.dataset.shape[image_dims[1]]:
216
+ self.y = self.dataset.shape[image_dims[1]] - self.bin_y
217
+
218
+ self.rect.set_xy([self.x * self.rect.get_width() / self.bin_x + self.rectangle[0],
219
+ self.y * self.rect.get_height() / self.bin_y + self.rectangle[2]])
220
+ # self.get_spectrum()
221
+ self._update()
222
+ else:
223
+ if event.dblclick:
224
+ bottom = float(self.spectrum.min())
225
+ if bottom < 0:
226
+ bottom *= 1.02
227
+ else:
228
+ bottom *= 0.98
229
+ top = float(self.spectrum.max())
230
+ if top > 0:
231
+ top *= 1.02
232
+ else:
233
+ top *= 0.98
234
+ self.axis.set_ylim(bottom=bottom, top=top)
235
+
236
+ def get_spectrum(self):
237
+ if self.dataset.data_type == sidpy.DataType.SPECTRUM:
238
+ self.spectrum = self.dataset.copy()
239
+ else:
240
+ image_dims = self.dataset.get_dimensions_by_type(sidpy.DimensionType.SPATIAL)
241
+ if self.x > self.dataset.shape[image_dims[0]] - self.bin_x:
242
+ self.x = self.dataset.shape[image_dims[0]] - self.bin_x
243
+ if self.y > self.dataset.shape[image_dims[1]] - self.bin_y:
244
+ self.y = self.dataset.shape[image_dims[1]] - self.bin_y
245
+ selection = []
246
+ self.axis.clear()
247
+ for dim, axis in self.dataset._axes.items():
248
+ # print(dim, axis.dimension_type)
249
+ if axis.dimension_type == sidpy.DimensionType.SPATIAL:
250
+ if dim == image_dims[0]:
251
+ selection.append(slice(self.x, self.x + self.bin_x))
252
+ else:
253
+ selection.append(slice(self.y, self.y + self.bin_y))
254
+
255
+ elif axis.dimension_type == sidpy.DimensionType.SPECTRAL:
256
+ selection.append(slice(None))
257
+ elif axis.dimension_type == sidpy.DimensionType.CHANNEL:
258
+ selection.append(slice(None))
259
+ else:
260
+ selection.append(slice(0, 1))
261
+
262
+ self.spectrum = self.dataset[tuple(selection)].mean(axis=tuple(image_dims))
263
+
264
+ self.spectrum *= self.y_scale
265
+
266
+ return self.spectrum.squeeze()
267
+
268
+ def plot_spectrum_image(self):
269
+ self.axes = self.figure.subplots(ncols=2)
270
+ self.axis = self.axes[-1]
271
+
272
+ spec_dim = self.dataset.get_dimensions_by_type(sidpy.DimensionType.SPECTRAL)
273
+ if len(spec_dim) != 1:
274
+ raise ValueError('Only one spectral dimension')
275
+
276
+ channel_dim = self.dataset.get_dimensions_by_type(sidpy.DimensionType.CHANNEL)
277
+ channel_dim =[]
278
+ if len(channel_dim) > 1:
279
+ raise ValueError('Maximal one channel dimension')
280
+
281
+ if len(channel_dim) > 0:
282
+ self.image = self.dataset.mean(axis=(spec_dim[0] ,channel_dim[0]))
283
+ else:
284
+ self.image = self.dataset.mean(axis=(spec_dim[0]))
285
+
286
+ self.rect = matplotlib.patches.Rectangle((0, 0), self.bin_x, self.bin_y, linewidth=1, edgecolor='r',
287
+ facecolor='red', alpha=0.2)
288
+ size_x = self.image.shape[0]
289
+ size_y = self.image.shape[1]
290
+ self.extent = [0, size_x, size_y, 0]
291
+ self.rectangle = [0, size_x, 0, size_y]
292
+ self.axes[0].imshow(self.image.T, extent=self.extent)
293
+ self.axes[0].set_aspect('equal')
294
+ self.axes[0].add_patch(self.rect)
295
+ self.cid = self.axes[0].figure.canvas.mpl_connect('button_press_event', self._onclick)
296
+
297
+
298
+ def line_select_callback(self, x_min, x_max):
299
+ self.start_cursor.value = np.round(x_min, 3)
300
+ self.end_cursor.value = np.round(x_max, 3)
301
+ self.start_channel = np.searchsorted(self.datasets[self.key].energy_loss, self.start_cursor.value)
302
+ self.end_channel = np.searchsorted(self.datasets[self.key].energy_loss, self.end_cursor.value)
303
+
304
+ def set_dataset(self, index=0):
305
+
306
+ if len(self.datasets) == 0:
307
+ data_set = sidpy.Dataset.from_array([0, 1], name='generic')
308
+ data_set.set_dimension(0, sidpy.Dimension([0,1], 'energy_loss', units='channel', quantity='generic',
309
+ dimension_type='spectral'))
310
+ data_set.data_type = 'spectrum'
311
+ data_set.metadata= {'experiment':{'convergence_angle': 0,
312
+ 'collection_angle': 0,
313
+ 'acceleration_voltage':0,
314
+ 'exposure_time':0}}
315
+ self.datasets={'Channel_000': data_set}
316
+ index = 0
317
+
318
+ dataset_index = index
319
+
320
+ self.key = list(self.datasets)[dataset_index]
321
+ self.dataset = self.datasets[self.key]
322
+
323
+ self._udpate_sidbar()
324
+ self.y_scale = 1.0
325
+ self.change_y_scale = 1.0
326
+ self.x = 0
327
+ self.y = 0
328
+ self.bin_x = 1
329
+ self.bin_y = 1
330
+ self.count = 0
331
+
332
+ self.plot()
333
+
334
+ def _udpate_sidbar(self):
335
+ pass
336
+
337
+
338
+ def set_energy_scale(self, value):
339
+ dispersion = self.datasets[self.key].energy_loss[1] - self.datasets[self.key].energy_loss[0]
340
+ self.datasets[self.key].energy_loss *= (self.sidebar[3, 0].value/dispersion)
341
+ self.datasets[self.key].energy_loss += (self.sidebar[2, 0].value-self.datasets[self.key].energy_loss[0])
342
+ self.plot()
343
+
344
+ def set_y_scale(self, value):
345
+ self.count += 1
346
+ self.change_y_scale = 1.0/self.y_scale
347
+ if self.sidebar[9,2].value:
348
+ dispersion = self.datasets[self.key].energy_loss[1] - self.datasets[self.key].energy_loss[0]
349
+ self.y_scale = 1/self.datasets[self.key].metadata['experiment']['flux_ppm'] * dispersion
350
+ self.ylabel='scattering probability (ppm)'
351
+ else:
352
+ self.y_scale = 1.0
353
+ self.ylabel='intensity (counts)'
354
+ self.change_y_scale *= self.y_scale
355
+ self._update()
356
+
357
+ class InfoWidget(EELSWidget):
358
+ def __init__(self, datasets):
359
+
360
+ sidebar = get_info_sidebar()
361
+ super().__init__(datasets, sidebar)
362
+ self.set_action()
363
+
364
+ def set_flux(self, value):
365
+ self.datasets[self.key].metadata['experiment']['exposure_time'] = self.sidebar[10,0].value
366
+ if self.sidebar[9,0].value < 0:
367
+ self.datasets[self.key].metadata['experiment']['flux_ppm'] = 0.
368
+ else:
369
+ key = list(self.datasets.keys())[self.sidebar[9,0].value]
370
+ self.datasets[self.key].metadata['experiment']['flux_ppm'] = (np.array(self.datasets[key])*1e-6).sum() / self.datasets[key].metadata['experiment']['exposure_time']
371
+ self.datasets[self.key].metadata['experiment']['flux_ppm'] *= self.datasets[self.key].metadata['experiment']['exposure_time']
372
+ self.sidebar[11,0].value = np.round(self.datasets[self.key].metadata['experiment']['flux_ppm'], 2)
373
+
374
+ def set_microscope_parameter(self, value):
375
+ self.datasets[self.key].metadata['experiment']['convergence_angle'] = self.sidebar[5,0].value
376
+ self.datasets[self.key].metadata['experiment']['collection_angle'] = self.sidebar[6,0].value
377
+ self.datasets[self.key].metadata['experiment']['acceleration_voltage'] = self.sidebar[7,0].value*1000
378
+
379
+ def cursor2energy_scale(self, value):
380
+ dispersion = (self.end_cursor.value - self.start_cursor.value) / (self.end_channel - self.start_channel)
381
+ self.datasets[self.key].energy_loss *= (self.sidebar[3, 0].value/dispersion)
382
+ self.sidebar[3, 0].value = dispersion
383
+ offset = self.start_cursor.value - self.start_channel * dispersion
384
+ self.datasets[self.key].energy_loss += (self.sidebar[2, 0].value-self.datasets[self.key].energy_loss[0])
385
+ self.sidebar[2, 0].value = offset
386
+ self.plot()
387
+
388
+ def set_binning(self, value):
389
+ if 'SPECTRAL' in self.dataset.data_type.name:
390
+ bin_x = self.sidebar[15,0].value
391
+ bin_y = self.sidebar[16,0].value
392
+ self.dataset.view.set_bin([bin_x, bin_y])
393
+ self.datasets[self.key].metadata['experiment']['SI_bin_x'] = bin_x
394
+ self.datasets[self.key].metadata['experiment']['SI_bin_y'] = bin_y
395
+
396
+ def _udpate_sidbar(self):
397
+ spectrum_list = []
398
+ reference_list =[('None', -1)]
399
+ for index, key in enumerate(self.datasets.keys()):
400
+ if 'Reference' not in key:
401
+ if 'SPECTR' in self.datasets[key].data_type.name:
402
+ spectrum_list.append((f'{key}: {self.datasets[key].title}', index))
403
+ reference_list.append((f'{key}: {self.datasets[key].title}', index))
404
+
405
+ self.sidebar[0,0].options = spectrum_list
406
+ self.sidebar[9,0].options = reference_list
407
+
408
+ if 'SPECTRUM' in self.dataset.data_type.name:
409
+ for i in range(14, 17):
410
+ self.sidebar[i, 0].layout.display = "none"
411
+ else:
412
+ for i in range(14, 17):
413
+ self.sidebar[i, 0].layout.display = "flex"
414
+ #self.sidebar[0,0].value = dataset_index #f'{self.key}: {self.datasets[self.key].title}'
415
+ self.sidebar[2,0].value = np.round(self.datasets[self.key].energy_loss[0], 3)
416
+ self.sidebar[3,0].value = np.round(self.datasets[self.key].energy_loss[1] - self.datasets[self.key].energy_loss[0], 4)
417
+ self.sidebar[5,0].value = np.round(self.datasets[self.key].metadata['experiment']['convergence_angle'], 1)
418
+ self.sidebar[6,0].value = np.round(self.datasets[self.key].metadata['experiment']['collection_angle'], 1)
419
+ self.sidebar[7,0].value = np.round(self.datasets[self.key].metadata['experiment']['acceleration_voltage']/1000, 1)
420
+ self.sidebar[10,0].value = np.round(self.datasets[self.key].metadata['experiment']['exposure_time'], 4)
421
+ if 'flux_ppm' not in self.datasets[self.key].metadata['experiment']:
422
+ self.datasets[self.key].metadata['experiment']['flux_ppm'] = 0
423
+ self.sidebar[11,0].value = self.datasets[self.key].metadata['experiment']['flux_ppm']
424
+ if 'count_conversion' not in self.datasets[self.key].metadata['experiment']:
425
+ self.datasets[self.key].metadata['experiment']['count_conversion'] = 1
426
+ self.sidebar[12,0].value = self.datasets[self.key].metadata['experiment']['count_conversion']
427
+ if 'beam_current' not in self.datasets[self.key].metadata['experiment']:
428
+ self.datasets[self.key].metadata['experiment']['beam_current'] = 0
429
+ self.sidebar[13,0].value = self.datasets[self.key].metadata['experiment']['beam_current']
430
+
431
+ def update_dataset(self):
432
+ dataset_index = self.sidebar[0, 0].value
433
+ self.set_dataset(dataset_index)
434
+
435
+ def set_action(self):
436
+ self.sidebar[0,0].observe(self.update_dataset)
437
+ self.sidebar[1,0].on_click(self.cursor2energy_scale)
438
+ self.sidebar[2,0].observe(self.set_energy_scale, names='value')
439
+ self.sidebar[3,0].observe(self.set_energy_scale, names='value')
440
+ self.sidebar[5,0].observe(self.set_microscope_parameter)
441
+ self.sidebar[6,0].observe(self.set_microscope_parameter)
442
+ self.sidebar[7,0].observe(self.set_microscope_parameter)
443
+ self.sidebar[9,0].observe(self.set_flux)
444
+ self.sidebar[9,2].observe(self.set_y_scale, names='value')
445
+ self.sidebar[10,0].observe(self.set_flux)
446
+ self.sidebar[15,0].observe(self.set_binning)
447
+ self.sidebar[16,0].observe(self.set_binning)
448
+
449
+ def get_low_loss_sidebar():
450
+ side_bar = ipywidgets.GridspecLayout(17, 3,width='auto', grid_gap="0px")
451
+
452
+ side_bar[0, :2] = ipywidgets.Dropdown(
453
+ options=[('None', 0)],
454
+ value=0,
455
+ description='Main Dataset:',
456
+ disabled=False)
457
+
458
+ row = 1
459
+ side_bar[row, :3] = ipywidgets.Button(description='Fix Energy Scale',
460
+ layout=ipywidgets.Layout(width='auto', grid_area='header'),
461
+ style=ipywidgets.ButtonStyle(button_color='lightblue'))
462
+ row += 1
463
+ side_bar[row, :2] = ipywidgets.FloatText(value=7.5,description='Offset:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
464
+ side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='20px'))
465
+ row += 1
466
+ side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Dispersion:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
467
+ side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='20px'))
468
+
469
+ row += 1
470
+ side_bar[row, :3] = ipywidgets.Button(description='Resolution_function',
471
+ layout=ipywidgets.Layout(width='auto', grid_area='header'),
472
+ style=ipywidgets.ButtonStyle(button_color='lightblue'))
473
+ row += 1
474
+ side_bar[row, :2] = ipywidgets.FloatText(value=0.3, description='Fit Window:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
475
+ side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='100px'))
476
+ row += 1
477
+ side_bar[row,:2] = ipywidgets.ToggleButton(
478
+ description='Show Resolution Function',
479
+ disabled=False,
480
+ button_style='', # 'success', 'info', 'warning', 'danger' or ''
481
+ tooltip='Changes y-axis to probability if flux is given',
482
+ layout=ipywidgets.Layout(width='100px'))
483
+ side_bar[row,2] = ipywidgets.ToggleButton(
484
+ description='Probability',
485
+ disabled=False,
486
+ button_style='', # 'success', 'info', 'warning', 'danger' or ''
487
+ tooltip='Changes y-axis to probability if flux is given',
488
+ layout=ipywidgets.Layout(width='100px'))
489
+ row += 2
490
+
491
+ side_bar[row, :3] = ipywidgets.Button(description='Drude Fit',
492
+ layout=ipywidgets.Layout(width='auto', grid_area='header'),
493
+ style=ipywidgets.ButtonStyle(button_color='lightblue'))
494
+ row+=1
495
+ side_bar[row, :2] = ipywidgets.Dropdown(
496
+ options=[('None', 0)],
497
+ value=0,
498
+ description='Reference:',
499
+ disabled=False)
500
+ side_bar[row,2] = ipywidgets.ToggleButton(
501
+ description='Probability',
502
+ disabled=False,
503
+ button_style='', # 'success', 'info', 'warning', 'danger' or ''
504
+ tooltip='Changes y-axis to probability if flux is given',
505
+ layout=ipywidgets.Layout(width='100px'))
506
+ row += 1
507
+ side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Exp_Time:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
508
+ side_bar[row, 2] = ipywidgets.widgets.Label(value="s", layout=ipywidgets.Layout(width='100px'))
509
+ row += 1
510
+ side_bar[row, :2] = ipywidgets.FloatText(value=7.5,description='Flux:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
511
+ side_bar[row, 2] = ipywidgets.widgets.Label(value="Mcounts", layout=ipywidgets.Layout(width='100px'))
512
+ row += 1
513
+ side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Conversion:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
514
+ side_bar[row, 2] = ipywidgets.widgets.Label(value=r"e$^-$/counts", layout=ipywidgets.Layout(width='100px'))
515
+ row += 1
516
+ side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Current:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
517
+ side_bar[row, 2] = ipywidgets.widgets.Label(value="pA", layout=ipywidgets.Layout(width='100px') )
518
+
519
+ row += 1
520
+
521
+ side_bar[row, :3] = ipywidgets.Button(description='Spectrum Image',
522
+ layout=ipywidgets.Layout(width='auto', grid_area='header'),
523
+ style=ipywidgets.ButtonStyle(button_color='lightblue'))
524
+
525
+ row += 1
526
+ side_bar[row, :2] = ipywidgets.IntText(value=1, description='bin X:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
527
+ row += 1
528
+ side_bar[row, :2] = ipywidgets.IntText(value=1, description='bin X:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
529
+
530
+ for i in range(14, 17):
531
+ pass
532
+ # side_bar[i, 0].layout.display = "none"
533
+ return side_bar
534
+
535
+ class LowLossWidget(EELSWidget):
536
+ def __init__(self, datasets):
537
+ sidebar = get_low_loss_sidebar()
538
+ super().__init__(datasets, sidebar)
539
+ self.sidebar[3,0].value = self.energy_scale[0]
540
+ self.sidebar[4,0].value = self.energy_scale[1] - self.energy_scale[0]
541
+
542
+ self.set_action()
543
+
544
+ def _udpate_sidbar(self):
545
+ spectrum_list = []
546
+ reference_list =[('None', -1)]
547
+ for index, key in enumerate(self.datasets.keys()):
548
+ if 'Reference' not in key:
549
+ if 'SPECTR' in self.datasets[key].data_type.name:
550
+ spectrum_list.append((f'{key}: {self.datasets[key].title}', index))
551
+ reference_list.append((f'{key}: {self.datasets[key].title}', index))
552
+
553
+ self.sidebar[0,0].options = spectrum_list
554
+ self.sidebar[9,0].options = reference_list
555
+
556
+ if 'SPECTRUM' in self.dataset.data_type.name:
557
+ for i in range(14, 17):
558
+ self.sidebar[i, 0].layout.display = "none"
559
+ else:
560
+ for i in range(14, 17):
561
+ self.sidebar[i, 0].layout.display = "flex"
562
+
563
+ def get_resolution_function(self, value):
564
+ self.datasets['resolution_functions'] = eels_tools.get_resolution_functions(self.dataset, zero_loss_fit_width=self.sidebar[5,0].value)
565
+ if 'low_loss' not in self.dataset.metadata:
566
+ self.dataset.metadata['low_loss'] = {}
567
+ self.dataset.metadata['low_loss'].update(self.datasets['resolution_functions'].metadata['low_loss'])
568
+ self.sidebar[6,0].value = True
569
+
570
+ def update_dataset(self):
571
+ dataset_index = self.sidebar[0, 0].value
572
+ self.set_dataset(dataset_index)
573
+
574
+ def set_action(self):
575
+ self.sidebar[0,0].observe(self.update_dataset)
576
+ self.sidebar[1,0].on_click(self.fix_energy_scale)
577
+ self.sidebar[2,0].observe(self.set_energy_scale, names='value')
578
+ self.sidebar[3,0].observe(self.set_energy_scale, names='value')
579
+ self.sidebar[4,0].on_click(self.get_resolution_function)
580
+ self.sidebar[6,2].observe(self.set_y_scale, names='value')
581
+ self.sidebar[6,0].observe(self._update, names='value')
582
+
583
+ def fix_energy_scale(self, value=0):
584
+ self.dataset = eels_tools.shift_on_same_scale(self.dataset)
585
+ self.datasets[self.key] = self.dataset
586
+ if 'resolution_functions' in self.datasets:
587
+ self.datasets['resolution_functions'] = eels_tools.shift_on_same_scale(self.datasets['resolution_functions'])
588
+ self._update()
589
+
590
+
591
+ def set_y_scale(self, value):
592
+ self.change_y_scale = 1.0/self.y_scale
593
+ if self.sidebar[6,2].value:
594
+ dispersion = self.dataset.energy_loss[1] - self.dataset.energy_loss[0]
595
+ if self.dataset.data_type.name == 'SPECTRUM':
596
+ sum = self.dataset.sum()
597
+ else:
598
+ image_dims = self.dataset.get_dimensions_by_type(sidpy.DimensionType.SPATIAL)
599
+ sum = np.average(self.dataset, axis=image_dims).sum()
600
+
601
+ self.y_scale = 1/sum * dispersion * 1e6
602
+ # self.datasets[self.key].metadata['experiment']['flux_ppm'] * dispersion
603
+ self.ylabel='scattering probability (ppm)'
604
+ else:
605
+ self.y_scale = 1.0
606
+ self.ylabel='intensity (counts)'
607
+ self.change_y_scale *= self.y_scale
608
+ self._update()
609
+
610
+ def _update(self, ev=0):
611
+ super()._update(ev)
612
+ if self.sidebar[6,0].value:
613
+ if 'resolution_functions' in self.datasets:
614
+ resolution_function = self.get_additional_spectrum('resolution_functions')
615
+ self.axis.plot(self.energy_scale, resolution_function, label='resolution_function')
616
+ self.axis.legend()
617
+
618
+ def get_additional_spectrum(self, key):
619
+ if key not in self.datasets.keys():
620
+ return
621
+
622
+ if self.datasets[key].data_type == sidpy.DataType.SPECTRUM:
623
+ self.spectrum = self.datasets[key].copy()
624
+ else:
625
+ image_dims = self.datasets[key].get_dimensions_by_type(sidpy.DimensionType.SPATIAL)
626
+ selection = []
627
+ for dim, axis in self.datasets[key]._axes.items():
628
+ # print(dim, axis.dimension_type)
629
+ if axis.dimension_type == sidpy.DimensionType.SPATIAL:
630
+ if dim == image_dims[0]:
631
+ selection.append(slice(self.x, self.x + self.bin_x))
632
+ else:
633
+ selection.append(slice(self.y, self.y + self.bin_y))
634
+
635
+ elif axis.dimension_type == sidpy.DimensionType.SPECTRAL:
636
+ selection.append(slice(None))
637
+ elif axis.dimension_type == sidpy.DimensionType.CHANNEL:
638
+ selection.append(slice(None))
639
+ else:
640
+ selection.append(slice(0, 1))
641
+
642
+ self.spectrum = self.datasets[key][tuple(selection)].mean(axis=tuple(image_dims))
643
+
644
+ self.spectrum *= self.y_scale
645
+
646
+ return self.spectrum.squeeze()
647
+
648
+ def set_binning(self, value):
649
+ if 'SPECTRAL' in self.dataset.data_type.name:
650
+ bin_x = self.sidebar[15,0].value
651
+ bin_y = self.sidebar[16,0].value
652
+ self.dataset.view.set_bin([bin_x, bin_y])
653
+ self.datasets[self.key].metadata['experiment']['SI_bin_x'] = bin_x
654
+ self.datasets[self.key].metadata['experiment']['SI_bin_y'] = bin_y
655
+
@@ -14,14 +14,22 @@ except:
14
14
  Qt_available = False
15
15
  print('Qt dialogs are not available')
16
16
 
17
+ from pyTEMlib import eels_dialog
18
+ from pyTEMlib import info_dialog
19
+ from pyTEMlib import peak_dialog
20
+
17
21
  if Qt_available:
18
- from pyTEMlib import eels_dialog
19
-
20
- from pyTEMlib import info_dialog
21
- from pyTEMlib import peak_dialog
22
22
  from pyTEMlib.eels_dialog_utilities import *
23
23
 
24
24
  CompositionDialog = eels_dialog.EELSDialog
25
25
  CurveVisualizer = eels_dialog.CurveVisualizer
26
26
  InfoDialog = info_dialog.InfoDialog
27
27
  PeakFitDialog = peak_dialog.PeakFitDialog
28
+ else:
29
+ CompositionDialog = eels_dialog.CompositionWidget
30
+ InfoDialog = info_dialog.InfoWidget
31
+ PeakFitDialog = peak_dialog.PeakFitWidget
32
+
33
+ InfoWidget = info_dialog.InfoWidget
34
+ CompositionWidget = eels_dialog.CompositionWidget
35
+ PeakFitWidget = peak_dialog.PeakFitWidget