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/eels_dialog.py CHANGED
@@ -3,813 +3,98 @@ QT dialog window for EELS compositional analysis
3
3
 
4
4
  Author: Gerd Duscher
5
5
  """
6
- Qt_available = True
7
- try:
8
- from PyQt5 import QtCore, QtWidgets
9
- except:
10
- Qt_available = False
11
- # print('Qt dialogs are not available')
12
6
 
13
7
 
14
8
  import numpy as np
9
+ import warnings
15
10
 
16
11
  import ipywidgets
17
12
  import IPython.display
13
+ # from IPython.display import display
18
14
  import matplotlib
19
15
  import matplotlib.pylab as plt
20
16
  import matplotlib.patches as patches
21
17
 
22
18
  from pyTEMlib import file_tools as ft
23
19
  from pyTEMlib import eels_tools as eels
20
+ from pyTEMlib import eels_dialog_utilities
24
21
 
25
22
  import sidpy
26
23
 
27
- if Qt_available:
28
- from pyTEMlib import eels_dlg
29
- from pyTEMlib import eels_dialog_utilities
30
-
31
- class EELSDialog(QtWidgets.QDialog):
32
- """
33
- EELS Input Dialog for Chemical Analysis
34
- """
35
-
36
- def __init__(self, datasets=None):
37
- super().__init__(None, QtCore.Qt.WindowStaysOnTopHint)
38
- # Create an instance of the GUI
39
- if datasets is None:
40
- # make a dummy dataset
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)
55
- if len(self.spec_dim) != 1:
56
- raise TypeError('We need exactly one SPECTRAL dimension')
57
- self.spec_dim = self.spec_dim[0]
58
-
59
- self.ui = eels_dlg.UiDialog(self)
60
- # Run the .setup_ui() method to show the GUI
61
- # self.ui.setup_ui(self)
62
-
63
- self.set_action()
64
-
65
- self.energy_scale = np.array([])
66
- self.model = np.array([])
67
- self.y_scale = 1.0
68
- self.change_y_scale = 1.0
69
- self.spectrum_ll = None
70
- self.low_loss_key = None
71
-
72
- self.edges = {}
73
-
74
- self.show_regions = False
75
- self.show()
76
-
77
- self.set_dataset(self.dataset)
78
- initial_elements = []
79
-
80
- for key in self.edges:
81
- if key.isdigit():
82
- if 'element' in self.edges[key]:
83
- initial_elements.append(self.edges[key]['element'])
84
-
85
- self.pt_dialog = eels_dialog_utilities.PeriodicTableDialog(energy_scale=self.energy_scale,
86
- initial_elements=initial_elements)
87
- self.pt_dialog.signal_selected[list].connect(self.set_elements)
88
-
89
- self.dataset.plot()
90
-
91
- if hasattr(self.dataset.view, 'axes'):
92
- self.axis = self.dataset.view.axes[-1]
93
- elif hasattr(self.dataset.view, 'axis'):
94
- self.axis = self.dataset.view.axis
95
-
96
- self.figure = self.axis.figure
97
- self.updY = 0
98
- self.figure.canvas.mpl_connect('button_press_event', self.plot)
99
-
100
- self.ui.do_fit_button.setFocus()
101
- self.plot()
102
- self.ui.do_fit_button.setFocus()
103
-
104
- def set_dataset(self, dataset):
105
-
106
- self.dataset = dataset
107
- if 'edges' not in self.dataset.metadata or self.dataset.metadata['edges'] == {}:
108
- self.dataset.metadata['edges'] = {'0': {}, 'model': {}, 'use_low_loss': False}
109
- self.edges = self.dataset.metadata['edges']
110
-
111
- spec_dim = ft.get_dimensions_by_type('spectral', dataset)[0]
112
-
113
- if len(spec_dim) == 0:
114
- raise TypeError('We need at least one SPECTRAL dimension')
115
-
116
- self.spec_dim = spec_dim[0]
117
- self.energy_scale = dataset._axes[self.spec_dim].values
118
- self.ui.edit2.setText(f"{self.energy_scale[-2]:.3f}")
119
-
120
- if 'fit_area' not in self.edges:
121
- self.edges['fit_area'] = {}
122
- if 'fit_start' not in self.edges['fit_area']:
123
- self.ui.edit1.setText(f"{self.energy_scale[50]:.3f}")
124
- self.edges['fit_area']['fit_start'] = float(self.ui.edit1.displayText())
125
- else:
126
- self.ui.edit1.setText(f"{self.edges['fit_area']['fit_start']:.3f}")
127
- if 'fit_end' not in self.edges['fit_area']:
128
- self.ui.edit2.setText(f"{self.energy_scale[-2]:.3f}")
129
- self.edges['fit_area']['fit_end'] = float(self.ui.edit2.displayText())
130
- else:
131
- self.ui.edit2.setText(f"{self.edges['fit_area']['fit_end']:.3f}")
132
-
133
- if self.dataset.data_type.name == 'SPECTRAL_IMAGE':
134
- if 'SI_bin_x' not in self.dataset.metadata['experiment']:
135
- self.dataset.metadata['experiment']['SI_bin_x'] = 1
136
- self.dataset.metadata['experiment']['SI_bin_y'] = 1
137
-
138
- bin_x = self.dataset.metadata['experiment']['SI_bin_x']
139
- bin_y = self.dataset.metadata['experiment']['SI_bin_y']
140
- self.dataset.view.set_bin([bin_x, bin_y])
141
- self.update()
142
-
143
- def update(self):
144
- index = self.ui.list3.currentIndex() # which edge
145
- edge = self.edges[str(index)]
146
-
147
- if 'z' in edge:
148
- self.ui.list5.setCurrentIndex(self.ui.edge_sym.index(edge['symmetry']))
149
- self.ui.edit4.setText(str(edge['z']))
150
- self.ui.unit4.setText(edge['element'])
151
- self.ui.edit6.setText(f"{edge['onset']:.2f}")
152
- self.ui.edit7.setText(f"{edge['start_exclude']:.2f}")
153
- self.ui.edit8.setText(f"{edge['end_exclude']:.2f}")
154
- if self.y_scale == 1.0:
155
- self.ui.edit9.setText(f"{edge['areal_density']:.2e}")
156
- self.ui.unit9.setText('a.u.')
157
- else:
158
- dispersion = self.energy_scale[1]-self.energy_scale[0]
159
- self.ui.edit9.setText(f"{edge['areal_density']*self.y_scale*1e-6/dispersion:.2f}")
160
- self.ui.unit9.setText('atoms/nm²')
161
- else:
162
- self.ui.list3.setCurrentIndex(0)
163
- self.ui.edit4.setText(str(0))
164
- self.ui.unit4.setText(' ')
165
- self.ui.edit6.setText(f"{0:.2f}")
166
- self.ui.edit7.setText(f"{0:.2f}")
167
- self.ui.edit8.setText(f"{0:.2f}")
168
- self.ui.edit9.setText(f"{0:.2e}")
169
-
170
- def update_element(self, z):
171
- # We check whether this element is already in the
172
- zz = eels.get_z(z)
173
- for key, edge in self.edges.items():
174
- if key.isdigit():
175
- if 'z' in edge:
176
- if zz == edge['z']:
177
- return False
178
-
179
- major_edge = ''
180
- minor_edge = ''
181
- all_edges = {}
182
- x_section = eels.get_x_sections(zz)
183
- edge_start = 10 # int(15./ft.get_slope(self.energy_scale)+0.5)
184
- for key in x_section:
185
- if len(key) == 2 and key[0] in ['K', 'L', 'M', 'N', 'O'] and key[1].isdigit():
186
- if self.energy_scale[edge_start] < x_section[key]['onset'] < self.energy_scale[-edge_start]:
187
- if key in ['K1', 'L3', 'M5']:
188
- major_edge = key
189
- elif key in self.ui.edge_sym:
190
- if minor_edge == '':
191
- minor_edge = key
192
- if int(key[-1]) % 2 > 0:
193
- if int(minor_edge[-1]) % 2 == 0 or key[-1] > minor_edge[-1]:
194
- minor_edge = key
195
-
196
- all_edges[key] = {'onset': x_section[key]['onset']}
197
-
198
- if major_edge != '':
199
- key = major_edge
200
- elif minor_edge != '':
201
- key = minor_edge
202
- else:
203
- print(f'Could not find no edge of {zz} in spectrum')
204
- return False
205
-
206
- index = self.ui.list3.currentIndex()
207
- # self.ui.dialog.setWindowTitle(f'{index}, {zz}')
208
-
209
- if str(index) not in self.edges:
210
- self.edges[str(index)] = {}
211
-
212
- start_exclude = x_section[key]['onset'] - x_section[key]['excl before']
213
- end_exclude = x_section[key]['onset'] + x_section[key]['excl after']
214
-
215
- self.edges[str(index)] = {'z': zz, 'symmetry': key, 'element': eels.elements[zz],
216
- 'onset': x_section[key]['onset'], 'end_exclude': end_exclude,
217
- 'start_exclude': start_exclude}
218
- self.edges[str(index)]['all_edges'] = all_edges
219
- self.edges[str(index)]['chemical_shift'] = 0.0
220
- self.edges[str(index)]['areal_density'] = 0.0
221
- self.edges[str(index)]['original_onset'] = self.edges[str(index)]['onset']
222
- return True
223
-
224
- def on_enter(self):
225
- sender = self.sender()
226
- edge_list = self.ui.list3
227
- # self.ui.dialog.setWindowTitle(f"{sender.objectName()}")
228
-
229
-
230
- if sender.objectName() == 'fit_start_edit':
231
- value = float(str(sender.displayText()).strip())
232
- if value < self.energy_scale[0]:
233
- value = self.energy_scale[0]
234
- if value > self.energy_scale[-5]:
235
- value = self.energy_scale[-5]
236
- self.edges['fit_area']['fit_start'] = value
237
- sender.setText(str(self.edges['fit_area']['fit_start']))
238
- elif sender.objectName() == 'fit_end_edit':
239
- value = float(str(sender.displayText()).strip())
240
- if value < self.energy_scale[5]:
241
- value = self.energy_scale[5]
242
- if value > self.energy_scale[-1]:
243
- value = self.energy_scale[-1]
244
- self.edges['fit_area']['fit_end'] = value
245
- sender.setText(str(self.edges['fit_area']['fit_end']))
246
- elif sender.objectName() == 'element_edit':
247
- if str(sender.displayText()).strip() == '0':
248
- # sender.setText('PT')
249
- self.pt_dialog.energy_scale = self.energy_scale
250
- self.pt_dialog.show()
251
- pass
252
- else:
253
- self.update_element(str(sender.displayText()).strip())
254
- self.update()
255
- elif sender.objectName() in ['onset_edit', 'excl_start_edit', 'excl_end_edit']:
256
- self.check_area_consistency()
257
-
258
- elif sender.objectName() == 'multiplier_edit':
259
- index = edge_list.currentIndex()
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
264
- if 'background' not in self.edges['model']:
265
- print(' no background')
266
- return
267
- self.model = self.edges['model']['background']
268
- for key in self.edges:
269
- if key.isdigit():
270
- self.model = self.model + self.edges[key]['areal_density'] * self.edges[key]['data']
271
- self.plot()
272
- else:
273
- return
274
- if self.show_regions:
275
- self.plot()
276
-
277
-
278
-
279
- def sort_elements(self):
280
- onsets = []
281
- for index, edge in self.edges.items():
282
- if index.isdigit():
283
- onsets.append(float(edge['onset']))
284
-
285
- arg_sorted = np.argsort(onsets)
286
- edges = self.edges.copy()
287
- for index, i_sorted in enumerate(arg_sorted):
288
- self.edges[str(index)] = edges[str(i_sorted)].copy()
289
-
290
- index = 0
291
- edge = self.edges['0']
292
- dispersion = self.energy_scale[1]-self.energy_scale[0]
293
-
294
- while str(index + 1) in self.edges:
295
- next_edge = self.edges[str(index + 1)]
296
- if edge['end_exclude'] > next_edge['start_exclude'] - 5 * dispersion:
297
- edge['end_exclude'] = next_edge['start_exclude'] - 5 * dispersion
298
- edge = next_edge
299
- index += 1
300
-
301
- if edge['end_exclude'] > self.energy_scale[-3]:
302
- edge['end_exclude'] = self.energy_scale[-3]
303
-
304
- def set_elements(self, selected_elements):
305
- edge_list = self.ui.list3
306
-
307
- for index, elem in enumerate(selected_elements):
308
- edge_list.setCurrentIndex(index)
309
- self.update_element(elem)
310
-
311
- self.sort_elements()
312
- self.update()
313
-
314
- def plot(self, event=None):
315
- self.energy_scale = self.dataset._axes[self.spec_dim].values
316
- if self.dataset.data_type == sidpy.DataType.SPECTRAL_IMAGE:
317
- spectrum = self.dataset.view.get_spectrum()
318
- self.axis = self.dataset.view.axes[1]
319
- else:
320
- spectrum = np.array(self.dataset)
321
- self.axis = self.dataset.view.axis
322
-
323
- if self.ui.select10.isChecked():
324
- if 'experiment' in self.dataset.metadata:
325
- exp = self.dataset.metadata['experiment']
326
- if 'convergence_angle' not in exp:
327
- raise ValueError('need a convergence_angle in experiment of metadata dictionary ')
328
- alpha = exp['convergence_angle']
329
- beta = exp['collection_angle']
330
- beam_kv = exp['acceleration_voltage']
331
-
332
- eff_beta = eels.effective_collection_angle(self.energy_scale, alpha, beta, beam_kv)
333
- edges = eels.make_cross_sections(self.edges, np.array(self.energy_scale), beam_kv, eff_beta)
334
- self.edges = eels.fit_edges2(spectrum, self.energy_scale, edges)
335
- areal_density = []
336
- elements = []
337
- for key in edges:
338
- if key.isdigit(): # only edges have numbers in that dictionary
339
- elements.append(edges[key]['element'])
340
- areal_density.append(edges[key]['areal_density'])
341
- areal_density = np.array(areal_density)
342
- out_string = '\nRelative composition: \n'
343
- for i, element in enumerate(elements):
344
- out_string += f'{element}: {areal_density[i] / areal_density.sum() * 100:.1f}% '
345
-
346
- self.model = self.edges['model']['spectrum']
347
- self.update()
348
-
349
- x_limit = self.axis.get_xlim()
350
- y_limit = np.array(self.axis.get_ylim())*self.change_y_scale
351
- self.change_y_scale = 1.0
352
-
353
- self.axis.clear()
354
-
355
- line1, = self.axis.plot(self.energy_scale, spectrum*self.y_scale, label='spectrum')
356
- lines = [line1]
357
-
358
- def onpick(event):
359
- # on the pick event, find the orig line corresponding to the
360
- # legend proxy line, and toggle the visibility
361
- leg_line = event.artist
362
- orig_line = lined[legline]
363
- vis = not origline.get_visible()
364
- orig_line.set_visible(vis)
365
- # Change the alpha on the line in the legend, so we can see what lines
366
- # have been toggled
367
- if vis:
368
- leg_line.set_alpha(1.0)
369
- else:
370
- leg_line.set_alpha(0.2)
371
- self.figure.canvas.draw()
372
-
373
- if len(self.model) > 1:
374
- line2, = self.axis.plot(self.energy_scale, self.model*self.y_scale, label='model')
375
- line3, = self.axis.plot(self.energy_scale, (spectrum - self.model)*self.y_scale, label='difference')
376
- line4, = self.axis.plot(self.energy_scale, (spectrum - self.model) / np.sqrt(spectrum)*self.y_scale, label='Poisson')
377
- lines = [line1, line2, line3, line4]
378
- lined = dict()
379
-
380
- legend = self.axis.legend(loc='upper right', fancybox=True, shadow=True)
381
-
382
- legend.get_frame().set_alpha(0.4)
383
- for legline, origline in zip(legend.get_lines(), lines):
384
- legline.set_picker(5) # 5 pts tolerance
385
- lined[legline] = origline
386
- self.figure.canvas.mpl_connect('pick_event', onpick)
387
- self.axis.set_xlim(x_limit)
388
- self.axis.set_ylim(y_limit)
389
-
390
- if self.y_scale != 1.:
391
- self.axis.set_ylabel('scattering intensity (ppm)')
392
- else:
393
- self.axis.set_ylabel('intensity (counts)')
394
- self.axis.set_xlabel('energy_loss (eV)')
395
-
396
-
397
- if self.ui.show_edges.isChecked():
398
- self.show_edges()
399
- if self.show_regions:
400
- self.plot_regions()
401
- self.figure.canvas.draw_idle()
402
-
403
- def plot_regions(self):
404
- y_min, y_max = self.axis.get_ylim()
405
- height = y_max - y_min
406
-
407
- rect = []
408
- if 'fit_area' in self.edges:
409
- color = 'blue'
410
- alpha = 0.2
411
- x_min = self.edges['fit_area']['fit_start']
412
- width = self.edges['fit_area']['fit_end'] - x_min
413
- rect.append(patches.Rectangle((x_min, y_min), width, height,
414
- edgecolor=color, alpha=alpha, facecolor=color))
415
- self.axis.add_patch(rect[0])
416
- self.axis.text(x_min, y_max, 'fit region', verticalalignment='top')
417
- color = 'red'
418
- alpha = 0.5
419
- for key in self.edges:
420
- if key.isdigit():
421
- x_min = self.edges[key]['start_exclude']
422
- width = self.edges[key]['end_exclude']-x_min
423
- rect.append(patches.Rectangle((x_min, y_min), width, height,
424
- edgecolor=color, alpha=alpha, facecolor=color))
425
- self.axis.add_patch(rect[-1])
426
- self.axis.text(x_min, y_max, f"exclude\n edge {int(key)+1}", verticalalignment='top')
427
-
428
- def show_edges(self):
429
- x_min, x_max = self.axis.get_xlim()
430
- y_min, y_max = self.axis.get_ylim()
431
-
432
- for key, edge in self.edges.items():
433
- i = 0
434
- if key.isdigit():
435
- element = edge['element']
436
- for sym in edge['all_edges']:
437
- x = edge['all_edges'][sym]['onset'] + edge['chemical_shift']
438
- if x_min < x < x_max:
439
- self.axis.text(x, y_max, '\n' * i + f"{element}-{sym}",
440
- verticalalignment='top', color='black')
441
- self.axis.axvline(x, ymin=0, ymax=1, color='gray')
442
- i += 1
443
-
444
- def check_area_consistency(self):
445
- if self.dataset is None:
446
- return
447
- onset = float(self.ui.edit6.displayText())
448
- excl_start = float(self.ui.edit7.displayText())
449
- excl_end = float(self.ui.edit8.displayText())
450
- if onset < self.energy_scale[2]:
451
- onset = self.energy_scale[2]
452
- excl_start = self.energy_scale[2]
453
- if onset > self.energy_scale[-2]:
454
- onset = self.energy_scale[-2]
455
- excl_end = self.energy_scale[-2]
456
- if excl_start > onset:
457
- excl_start = onset
458
- if excl_end < onset:
459
- excl_end = onset
460
-
461
- index = self.ui.list3.currentIndex()
462
- self.edges[str(index)]['chemical_shift'] = onset - self.edges[str(index)]['original_onset']
463
- self.edges[str(index)]['onset'] = onset
464
- self.edges[str(index)]['end_exclude'] = excl_end
465
- self.edges[str(index)]['start_exclude'] = excl_start
466
-
467
- self.update()
468
-
469
- def on_list_enter(self):
470
- sender = self.sender()
471
- # self.ui.dialog.setWindowTitle(f"on list eneter {sender.objectName()}")
472
-
473
- if sender.objectName() == 'edge_list':
474
- index = self.ui.list3.currentIndex()
475
-
476
- number_of_edges = 0
477
- for key in self.edges:
478
- if key.isdigit():
479
- if int(key) > number_of_edges:
480
- number_of_edges = int(key)
481
- number_of_edges += 1
482
- if index > number_of_edges:
483
- index = number_of_edges
484
- self.ui.list3.setCurrentIndex(index)
485
- if str(index) not in self.edges:
486
- self.edges[str(index)] = {'z': 0, 'symmetry': 'K1', 'element': 'H', 'onset': 0, 'end_exclude': 0,
487
- 'start_exclude': 0, 'areal_density': 0}
488
-
489
- self.update()
490
- elif sender.objectName() == 'symmetry_list':
491
- sym = self.ui.list5.currentText()
492
- index = self.ui.list3.currentIndex()
493
- zz = self.edges[str(index)]['z']
494
- if zz > 1:
495
- x_section = eels.get_x_sections(zz)
496
- if sym in x_section:
497
- start_exclude = x_section[sym]['onset'] - x_section[sym]['excl before']
498
- end_exclude = x_section[sym]['onset'] + x_section[sym]['excl after']
499
- self.edges[str(index)].update({'symmetry': sym, 'onset': x_section[sym]['onset'],
500
- 'end_exclude': end_exclude, 'start_exclude': start_exclude})
501
- self.edges[str(index)]['chemical_shift'] = 0.0
502
- self.edges[str(index)]['areal_density'] = 0.0
503
- self.edges[str(index)]['original_onset'] = self.edges[index]['onset']
504
- self.update()
505
- elif sender.objectName() == 'symmetry_method':
506
- self.ui.select5.setCurrentIndex(0)
507
-
508
- def on_check(self):
509
- sender = self.sender()
510
- # self.ui.dialog.setWindowTitle(f"on_check {sender.objectName()}")
511
-
512
-
513
- if sender.objectName() == 'edge_check':
514
- self.show_regions = sender.isChecked()
515
- elif sender.objectName() == 'conv_ll':
516
- self.edges['use_low_loss'] = self.ui.check10.isChecked()
517
- if self.ui.check10.isChecked():
518
- self.low_loss()
519
- elif sender.objectName() == 'probability':
520
- dispersion = self.energy_scale[1]-self.energy_scale[0]
521
- old_y_scale = self.y_scale *1.
522
- if sender.isChecked():
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
548
- else:
549
- self.y_scale = 1.0
550
-
551
- self.change_y_scale = self.y_scale/old_y_scale
552
- self.update()
553
- self.plot()
554
-
555
- def low_loss(self):
556
- self.edges['use_low_loss'] = self.ui.check10.isChecked()
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']
577
-
578
- def do_all_button_click(self):
579
-
580
- if self.dataset.data_type.name != 'SPECTRAL_IMAGE':
581
- self.do_fit_button_click()
582
- return
583
-
584
- if 'experiment' in self.dataset.metadata:
585
- exp = self.dataset.metadata['experiment']
586
- if 'convergence_angle' not in exp:
587
- raise ValueError('need a convergence_angle in experiment of metadata dictionary ')
588
- alpha = exp['convergence_angle']
589
- beta = exp['collection_angle']
590
- beam_kv = exp['acceleration_voltage']
591
- else:
592
- raise ValueError('need a experiment parameter in metadata dictionary')
593
24
 
594
- self.energy_scale = self.dataset._axes[self.spec_dim].values
595
- eff_beta = eels.effective_collection_angle(self.energy_scale, alpha, beta, beam_kv)
596
- if self.edges['use_low_loss']:
597
- low_loss = np.array(self.spectrum_ll)/self.spectrum_ll.sum()
598
- else:
599
- low_loss = None
600
-
601
- edges = eels.make_cross_sections(self.edges, np.array(self.energy_scale), beam_kv, eff_beta,
602
- low_loss=low_loss)
25
+ class CurveVisualizer(object):
26
+ """Plots a sidpy.Dataset with spectral dimension-type
603
27
 
604
- view = self.dataset.view
605
- bin_x = view.bin_x
606
- bin_y = view.bin_y
607
-
608
- start_x = view.x
609
- start_y = view.y
610
-
611
- number_of_edges = 0
612
- for key in self.edges:
613
- if key.isdigit():
614
- number_of_edges += 1
615
-
616
- results = np.zeros([int(self.dataset.shape[0]/bin_x), int(self.dataset.shape[1]/bin_y), number_of_edges])
617
- total_spec = int(self.dataset.shape[0]/bin_x)*int(self.dataset.shape[1]/bin_y)
618
- self.ui.progress.setMaximum(total_spec)
619
- self.ui.progress.setValue(0)
620
- ind = 0
621
- for x in range(int(self.dataset.shape[0]/bin_x)):
622
-
623
- for y in range(int(self.dataset.shape[1]/bin_y)):
624
- ind += 1
625
- self.ui.progress.setValue(ind)
626
- view.x = x*bin_x
627
- view.y = y*bin_y
628
- spectrum = view.get_spectrum()
629
-
630
- edges = eels.fit_edges2(spectrum, self.energy_scale, edges)
631
- for key, edge in edges.items():
632
- if key.isdigit():
633
- # element.append(edge['element'])
634
- results[x, y, int(key)] = edge['areal_density']
635
- edges['spectrum_image_quantification'] = results
636
- self.ui.progress.setValue(total_spec)
637
- view.x = start_x
638
- view.y = start_y
639
-
640
- def do_fit_button_click(self):
641
- if 'experiment' in self.dataset.metadata:
642
- exp = self.dataset.metadata['experiment']
643
- if 'convergence_angle' not in exp:
644
- raise ValueError('need a convergence_angle in experiment of metadata dictionary ')
645
- alpha = exp['convergence_angle']
646
- beta = exp['collection_angle']
647
- beam_kv = exp['acceleration_voltage']
648
-
649
- else:
650
- raise ValueError('need a experiment parameter in metadata dictionary')
651
- self.energy_scale = self.dataset._axes[self.spec_dim].values
652
- eff_beta = eels.effective_collection_angle(self.energy_scale, alpha, beta, beam_kv)
653
-
654
- if self.edges['use_low_loss']:
655
- low_loss = self.spectrum_ll / self.spectrum_ll.sum()
656
- else:
657
- low_loss = None
658
- edges = eels.make_cross_sections(self.edges, np.array(self.energy_scale), beam_kv, eff_beta, low_loss)
28
+ """
29
+ def __init__(self, dset, spectrum_number=None, axis=None, leg=None, **kwargs):
30
+ if not isinstance(dset, sidpy.Dataset):
31
+ raise TypeError('dset should be a sidpy.Dataset object')
32
+ if axis is None:
33
+ self.fig = plt.figure()
34
+ self.axis = self.fig.add_subplot(1, 1, 1)
35
+ else:
36
+ self.axis = axis
37
+ self.fig = axis.figure
659
38
 
660
- if self.dataset.data_type == sidpy.DataType.SPECTRAL_IMAGE:
661
- spectrum = self.dataset.view.get_spectrum()
662
- else:
663
- spectrum = self.dataset
664
- self.edges = eels.fit_edges2(spectrum, self.energy_scale, edges)
665
- areal_density = []
666
- elements = []
667
- for key in edges:
668
- if key.isdigit(): # only edges have numbers in that dictionary
669
- elements.append(edges[key]['element'])
670
- areal_density.append(edges[key]['areal_density'])
671
- areal_density = np.array(areal_density)
672
- out_string = '\nRelative composition: \n'
673
- for i, element in enumerate(elements):
674
- out_string += f'{element}: {areal_density[i] / areal_density.sum() * 100:.1f}% '
675
-
676
- self.model = self.edges['model']['spectrum']
677
- self.update()
678
- self.plot()
679
-
680
- def do_auto_id_button_click(self):
681
- # self.ui.dialog.setWindowTitle(f"auto id ")
682
- self.ui.do_fit_button.setFocus()
683
-
684
- if '0' not in self.edges:
685
- self.edges['0'] ={}
686
- found_edges = eels.auto_id_edges(self.dataset)
687
-
688
- to_delete = []
689
- if len(found_edges) >0:
690
- for key in self.edges:
691
- if key.isdigit():
692
- to_delete.append(key)
693
- for key in to_delete:
694
- del self.edges[key]
695
- if len(to_delete) == 0:
696
- self.edges['0'] = {}
697
-
698
- selected_elements = []
699
- for key in found_edges:
700
- selected_elements.append(key)
701
- self.set_elements(selected_elements)
702
-
703
- for button in self.pt_dialog.button:
704
- if button.text() in selected_elements:
705
- button.setChecked(True)
706
- else:
707
- button.setChecked(False)
708
- self.update()
709
-
710
- def do_select_button_click(self):
711
- self.pt_dialog.energy_scale = self.energy_scale
712
- self.pt_dialog.show()
713
- self.update()
714
-
715
- def set_action(self):
716
- self.ui.edit1.editingFinished.connect(self.on_enter)
717
- self.ui.edit2.editingFinished.connect(self.on_enter)
718
- self.ui.list3.activated[str].connect(self.on_list_enter)
719
- self.ui.check3.clicked.connect(self.on_check)
720
- self.ui.edit4.editingFinished.connect(self.on_enter)
721
- self.ui.list5.activated[str].connect(self.on_list_enter)
722
- self.ui.select5.activated[str].connect(self.on_list_enter)
723
-
724
- self.ui.edit6.editingFinished.connect(self.on_enter)
725
- self.ui.edit7.editingFinished.connect(self.on_enter)
726
- self.ui.edit8.editingFinished.connect(self.on_enter)
727
- self.ui.edit9.editingFinished.connect(self.on_enter)
728
-
729
- self.ui.check10.clicked.connect(self.on_check)
730
- self.ui.select10.clicked.connect(self.on_check)
731
- self.ui.show_edges.clicked.connect(self.on_check)
732
- self.ui.check_probability.clicked.connect(self.on_check)
733
-
734
- self.ui.do_all_button.clicked.connect(self.do_all_button_click)
735
- self.ui.do_fit_button.clicked.connect(self.do_fit_button_click)
736
- self.ui.auto_id_button.clicked.connect(self.do_auto_id_button_click)
737
- self.ui.select_button.clicked.connect(self.do_select_button_click)
738
-
739
-
740
- class CurveVisualizer(object):
741
- """Plots a sidpy.Dataset with spectral dimension-type
742
-
743
- """
744
- def __init__(self, dset, spectrum_number=None, axis=None, leg=None, **kwargs):
745
- if not isinstance(dset, sidpy.Dataset):
746
- raise TypeError('dset should be a sidpy.Dataset object')
747
- if axis is None:
748
- self.fig = plt.figure()
749
- self.axis = self.fig.add_subplot(1, 1, 1)
750
- else:
751
- self.axis = axis
752
- self.fig = axis.figure
39
+ self.dset = dset
40
+ self.selection = []
41
+ [self.spec_dim, self.energy_scale] = ft.get_dimensions_by_type('spectral', self.dset)[0]
753
42
 
754
- self.dset = dset
755
- self.selection = []
756
- [self.spec_dim, self.energy_scale] = ft.get_dimensions_by_type('spectral', self.dset)[0]
43
+ self.lined = dict()
44
+ self.plot(**kwargs)
757
45
 
758
- self.lined = dict()
759
- self.plot(**kwargs)
46
+ def plot(self, **kwargs):
47
+ if self.dset.data_type.name == 'IMAGE_STACK':
48
+ line1, = self.axis.plot(self.energy_scale.values, self.dset[0, 0], label='spectrum', **kwargs)
49
+ else:
50
+ line1, = self.axis.plot(self.energy_scale.values, self.dset, label='spectrum', **kwargs)
51
+ lines = [line1]
52
+ if 'add2plot' in self.dset.metadata:
53
+ data = self.dset.metadata['add2plot']
54
+ for key, line in data.items():
55
+ line_add, = self.axis.plot(self.energy_scale.values, line['data'], label=line['legend'])
56
+ lines.append(line_add)
57
+
58
+ legend = self.axis.legend(loc='upper right', fancybox=True, shadow=True)
59
+ legend.get_frame().set_alpha(0.4)
60
+
61
+ for legline, origline in zip(legend.get_lines(), lines):
62
+ legline.set_picker(True)
63
+ legline.set_pickradius(5) # 5 pts tolerance
64
+ self.lined[legline] = origline
65
+ self.fig.canvas.mpl_connect('pick_event', self.onpick)
66
+
67
+ self.axis.axhline(0, color='gray', alpha=0.6)
68
+ self.axis.set_xlabel(self.dset.labels[0])
69
+ self.axis.set_ylabel(self.dset.data_descriptor)
70
+ self.axis.ticklabel_format(style='sci', scilimits=(-2, 3))
71
+ self.fig.canvas.draw_idle()
760
72
 
761
- def plot(self, **kwargs):
762
- if self.dset.data_type.name == 'IMAGE_STACK':
763
- line1, = self.axis.plot(self.energy_scale.values, self.dset[0, 0], label='spectrum', **kwargs)
764
- else:
765
- line1, = self.axis.plot(self.energy_scale.values, self.dset, label='spectrum', **kwargs)
766
- lines = [line1]
767
- if 'add2plot' in self.dset.metadata:
768
- data = self.dset.metadata['add2plot']
769
- for key, line in data.items():
770
- line_add, = self.axis.plot(self.energy_scale.values, line['data'], label=line['legend'])
771
- lines.append(line_add)
772
-
773
- legend = self.axis.legend(loc='upper right', fancybox=True, shadow=True)
774
- legend.get_frame().set_alpha(0.4)
775
-
776
- for legline, origline in zip(legend.get_lines(), lines):
777
- legline.set_picker(True)
778
- legline.set_pickradius(5) # 5 pts tolerance
779
- self.lined[legline] = origline
780
- self.fig.canvas.mpl_connect('pick_event', self.onpick)
781
-
782
- self.axis.axhline(0, color='gray', alpha=0.6)
783
- self.axis.set_xlabel(self.dset.labels[0])
784
- self.axis.set_ylabel(self.dset.data_descriptor)
785
- self.axis.ticklabel_format(style='sci', scilimits=(-2, 3))
786
- self.fig.canvas.draw_idle()
787
-
788
- def update(self, **kwargs):
789
- x_limit = self.axis.get_xlim()
790
- y_limit = self.axis.get_ylim()
791
- self.axis.clear()
792
- self.plot(**kwargs)
793
- self.axis.set_xlim(x_limit)
794
- self.axis.set_ylim(y_limit)
795
-
796
- def onpick(self, event):
797
- # on the pick event, find the orig line corresponding to the
798
- # legend proxy line, and toggle the visibility
799
- legline = event.artist
800
- origline = self.lined[legline]
801
- vis = not origline.get_visible()
802
- origline.set_visible(vis)
803
- # Change the alpha on the line in the legend, so we can see what lines
804
- # have been toggled
805
- if vis:
806
- legline.set_alpha(1.0)
807
- else:
808
- legline.set_alpha(0.2)
809
- self.fig.canvas.draw()
73
+ def update(self, **kwargs):
74
+ x_limit = self.axis.get_xlim()
75
+ y_limit = self.axis.get_ylim()
76
+ self.axis.clear()
77
+ self.plot(**kwargs)
78
+ self.axis.set_xlim(x_limit)
79
+ self.axis.set_ylim(y_limit)
80
+
81
+ def onpick(self, event):
82
+ # on the pick event, find the orig line corresponding to the
83
+ # legend proxy line, and toggle the visibility
84
+ legline = event.artist
85
+ origline = self.lined[legline]
86
+ vis = not origline.get_visible()
87
+ origline.set_visible(vis)
88
+ # Change the alpha on the line in the legend, so we can see what lines
89
+ # have been toggled
90
+ if vis:
91
+ legline.set_alpha(1.0)
92
+ else:
93
+ legline.set_alpha(0.2)
94
+ self.fig.canvas.draw()
810
95
 
811
96
  def get_sidebar():
812
- side_bar = ipywidgets.GridspecLayout(13, 3,width='auto', grid_gap="0px")
97
+ side_bar = ipywidgets.GridspecLayout(14, 3,width='auto', grid_gap="0px")
813
98
 
814
99
 
815
100
  row = 0
@@ -894,111 +179,88 @@ def get_sidebar():
894
179
  tooltip='Changes y-axis to probability of flux is given',
895
180
  layout=ipywidgets.Layout(width='100px')
896
181
  )
182
+
183
+ row += 1
184
+ side_bar[row,0] = ipywidgets.ToggleButton(
185
+ description='Do All',
186
+ disabled=False,
187
+ button_style='', # 'success', 'info', 'warning', 'danger' or ''
188
+ tooltip='Fits all spectra of spectrum image',
189
+ layout=ipywidgets.Layout(width='100px')
190
+ )
191
+
192
+ side_bar[row,1] = ipywidgets.IntProgress(value=0, min=0, max=10, description=' ', bar_style='', # 'success', 'info', 'warning', 'danger' or ''
193
+ style={'bar_color': 'maroon'}, orientation='horizontal')
897
194
  return side_bar
898
195
 
899
196
 
900
197
  class CompositionWidget(object):
901
- def __init__(self, datasets=None):
902
- self.datasets = datasets
198
+ def __init__(self, datasets=None, key=None):
199
+
903
200
  if not isinstance(datasets, dict):
904
- raise TypeError('dataset or first item inhas to be a sidpy dataset')
905
-
201
+ raise TypeError('dataset or first item has to be a sidpy dataset')
202
+ self.datasets = datasets
203
+
204
+
205
+ self.model = []
906
206
  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
207
 
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])
208
+ self.set_dataset(key)
209
+
210
+ self.periodic_table = eels_dialog_utilities.PeriodicTableWidget(self.energy_scale)
211
+ self.elements_cancel_button = ipywidgets.Button(description='Cancel')
212
+ self.elements_select_button = ipywidgets.Button(description='Select')
213
+ self.elements_auto_button = ipywidgets.Button(description='Auto ID')
214
+
215
+ self.periodic_table_panel = ipywidgets.VBox([self.periodic_table.periodic_table,
216
+ ipywidgets.HBox([self.elements_cancel_button, self.elements_auto_button, self.elements_select_button])])
217
+
947
218
 
948
219
  self.app_layout = ipywidgets.AppLayout(
949
220
  left_sidebar=self.sidebar,
950
- center=self.panel,
221
+ center=self.view.panel,
951
222
  footer=None,#message_bar,
952
223
  pane_heights=[0, 10, 0],
953
224
  pane_widths=[4, 10, 0],
954
225
  )
226
+ self.set_action()
955
227
  IPython.display.display(self.app_layout)
228
+
956
229
 
957
230
  def line_select_callback(self, x_min, x_max):
958
231
  self.start_cursor.value = np.round(x_min,3)
959
232
  self.end_cursor.value = np.round(x_max, 3)
233
+
960
234
  self.start_channel = np.searchsorted(self.datasets[self.key].energy_loss, self.start_cursor.value)
961
235
  self.end_channel = np.searchsorted(self.datasets[self.key].energy_loss, self.end_cursor.value)
236
+
962
237
 
963
238
  def plot(self, scale=True):
239
+ self.view.change_y_scale = self.change_y_scale
240
+ self.view.y_scale = self.y_scale
241
+ self.energy_scale = self.dataset.energy_loss.values
964
242
 
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
-
243
+ if self.dataset.data_type == sidpy.DataType.SPECTRAL_IMAGE:
244
+ spectrum = self.view.get_spectrum()
245
+ else:
246
+ spectrum = self.dataset
984
247
  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
-
248
+ additional_spectra = {'model': self.model,
249
+ 'difference': spectrum-self.model}
250
+ else:
251
+ additional_spectra = None
252
+ self.view.plot(scale=True, additional_spectra=additional_spectra )
253
+ self.change_y_scale = 1.
254
+
993
255
  if self.sidebar[12, 2].value:
994
- self.show_edges()
256
+ self.show_edges()
995
257
  if self.sidebar[0, 0].value:
996
258
  self.plot_regions()
997
- self.fig.canvas.draw_idle()
259
+ self.view.figure.canvas.draw_idle()
998
260
 
999
261
 
1000
262
  def plot_regions(self):
1001
- axis = self.fig.gca()
263
+ axis = self.view.figure.gca()
1002
264
  y_min, y_max = axis.get_ylim()
1003
265
  height = y_max - y_min
1004
266
 
@@ -1025,7 +287,7 @@ class CompositionWidget(object):
1025
287
  axis.text(x_min, y_max, f"exclude\n edge {int(key)+1}", verticalalignment='top')
1026
288
 
1027
289
  def show_edges(self):
1028
- axis = self.fig.gca()
290
+ axis = self.view.figure.gca()
1029
291
  x_min, x_max = axis.get_xlim()
1030
292
  y_min, y_max = axis.get_ylim()
1031
293
 
@@ -1044,7 +306,30 @@ class CompositionWidget(object):
1044
306
 
1045
307
 
1046
308
 
1047
- def set_dataset(self, index=0):
309
+ def set_dataset(self, set_key):
310
+ spectrum_list = []
311
+ self.spectrum_keys_list = []
312
+ reference_list =[('None', -1)]
313
+
314
+ for index, key in enumerate(self.datasets.keys()):
315
+ if 'Reference' not in key:
316
+ if 'SPECTR' in self.datasets[key].data_type.name:
317
+ spectrum_list.append((f'{key}: {self.datasets[key].title}', index))
318
+ self.spectrum_keys_list.append(key)
319
+ reference_list.append((f'{key}: {self.datasets[key].title}', index))
320
+
321
+ if set_key in self.spectrum_keys_list:
322
+ self.key = set_key
323
+ else:
324
+ self.key = self.spectrum_keys_list[-1]
325
+ self.dataset = self.datasets[self.key]
326
+
327
+ spec_dim = self.dataset.get_dimensions_by_type(sidpy.DimensionType.SPECTRAL)
328
+ self.spec_dim = self.dataset._axes[spec_dim[0]]
329
+
330
+ self.energy_scale = self.spec_dim.values
331
+ self.dataset.metadata['experiment']['offset'] = self.energy_scale[0]
332
+ self.dataset.metadata['experiment']['dispersion'] = self.energy_scale[1] - self.energy_scale[0]
1048
333
  if 'edges' not in self.dataset.metadata or self.dataset.metadata['edges'] == {}:
1049
334
  self.dataset.metadata['edges'] = {'0': {}, 'model': {}, 'use_low_loss': False}
1050
335
 
@@ -1073,6 +358,13 @@ class CompositionWidget(object):
1073
358
  bin_x = self.dataset.metadata['experiment']['SI_bin_x']
1074
359
  bin_y = self.dataset.metadata['experiment']['SI_bin_y']
1075
360
  # self.dataset.view.set_bin([bin_x, bin_y])
361
+ if self.dataset.data_type.name =='SPECTRAL_IMAGE':
362
+ self.view = eels_dialog_utilities.SIPlot(self.dataset)
363
+ else:
364
+ self.view = eels_dialog_utilities.SpectrumPlot(self.dataset)
365
+ self.y_scale = 1.0
366
+ self.change_y_scale = 1.0
367
+
1076
368
  self.update()
1077
369
 
1078
370
  def update_element(self, z=0, index=-1):
@@ -1131,8 +423,6 @@ class CompositionWidget(object):
1131
423
  self.edges[str(index)]['areal_density'] = 0.0
1132
424
  self.edges[str(index)]['original_onset'] = self.edges[str(index)]['onset']
1133
425
  return True
1134
-
1135
-
1136
426
 
1137
427
  def sort_elements(self):
1138
428
  onsets = []
@@ -1159,24 +449,36 @@ class CompositionWidget(object):
1159
449
  if edge['end_exclude'] > self.energy_scale[-3]:
1160
450
  edge['end_exclude'] = self.energy_scale[-3]
1161
451
 
1162
- def set_elements(self, selected_elements):
452
+ def set_elements(self, value=0):
453
+ selected_elements = self.periodic_table.get_output()
454
+ edges = self.edges.copy()
455
+ to_delete = []
456
+ old_elements = []
457
+ if len(selected_elements) > 0:
458
+ for key in self.edges:
459
+ if key.isdigit():
460
+ to_delete.append(key)
461
+ old_elements.append(self.edges[key]['element'])
1163
462
 
463
+ for key in to_delete:
464
+ edges[key] = self.edges[key]
465
+ del self.edges[key]
466
+
1164
467
  for index, elem in enumerate(selected_elements):
1165
- self.sidebar[4, 0].value =index
1166
- self.update_element(elem)
1167
-
1168
- # self.sort_elements()
468
+ if elem in old_elements:
469
+ self.edges[str(index)] = edges[str(old_elements.index(elem))]
470
+ else:
471
+ self.update_element(elem, index=index)
472
+ self.sort_elements()
1169
473
  self.update()
1170
-
474
+ self.set_figure_pane()
1171
475
 
1172
-
1173
476
  def set_element(self, elem):
1174
477
  self.update_element(self.sidebar[5, 0].value)
1175
478
  # self.sort_elements()
1176
479
  self.update()
1177
480
 
1178
481
  def cursor2energy_scale(self, value):
1179
-
1180
482
  dispersion = (self.end_cursor.value - self.start_cursor.value) / (self.end_channel - self.start_channel)
1181
483
  self.datasets[self.key].energy_loss *= (self.sidebar[3, 0].value/dispersion)
1182
484
  self.sidebar[3, 0].value = dispersion
@@ -1199,38 +501,43 @@ class CompositionWidget(object):
1199
501
 
1200
502
  def set_y_scale(self, value):
1201
503
  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
504
+ self.y_scale = 1.0
505
+ if self.dataset.metadata['experiment']['flux_ppm'] > 0:
506
+ if self.sidebar[12, 0].value:
507
+ dispersion = self.energy_scale[1] - self.energy_scale[0]
508
+ self.y_scale = 1/self.dataset.metadata['experiment']['flux_ppm'] * dispersion
1207
509
 
1208
510
  self.change_y_scale *= self.y_scale
1209
511
  self.update()
1210
512
  self.plot()
513
+
514
+ def auto_id(self, value=0):
515
+ found_edges = eels.auto_id_edges(self.dataset)
516
+ if len(found_edges) > 0:
517
+ self.periodic_table.elements_selected = found_edges
518
+ self.periodic_table.update()
1211
519
 
1212
520
  def find_elements(self, value=0):
1213
521
 
1214
522
  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
523
  self.edges['0'] = {}
524
+ # found_edges = eels.auto_id_edges(self.dataset)
525
+ found_edges = {}
1227
526
 
1228
527
  selected_elements = []
1229
- for key in found_edges:
1230
- selected_elements.append(key)
1231
- self.set_elements(selected_elements)
528
+ elements = self.edges.copy()
1232
529
 
1233
- self.update()
530
+ for key in self.edges:
531
+ if key.isdigit():
532
+ if 'element' in self.edges[key]:
533
+ selected_elements.append(self.edges[key]['element'])
534
+ self.periodic_table.elements_selected = selected_elements
535
+ self.periodic_table.update()
536
+ self.app_layout.center = self.periodic_table_panel # self.periodic_table.periodic_table
537
+
538
+ def set_figure_pane(self, value=0):
539
+
540
+ self.app_layout.center = self.view.panel
1234
541
 
1235
542
  def update(self, index=0):
1236
543
 
@@ -1242,10 +549,10 @@ class CompositionWidget(object):
1242
549
  self.sidebar[4,0].value = len(self.sidebar[4,0].options)-2
1243
550
  if str(index) not in self.edges:
1244
551
  self.edges[str(index)] = {'z': 0, 'element': 'x', 'symmetry': 'K1', 'onset': 0, 'start_exclude': 0, 'end_exclude':0,
1245
- 'areal_density': 0}
552
+ 'areal_density': 0, 'chemical_shift':0}
1246
553
  if 'z' not in self.edges[str(index)]:
1247
554
  self.edges[str(index)] = {'z': 0, 'element': 'x', 'symmetry': 'K1', 'onset': 0, 'start_exclude': 0, 'end_exclude':0,
1248
- 'areal_density': 0}
555
+ 'areal_density': 0, 'chemical_shift':0}
1249
556
  edge = self.edges[str(index)]
1250
557
 
1251
558
  self.sidebar[5,0].value = edge['z']
@@ -1289,7 +596,7 @@ class CompositionWidget(object):
1289
596
  edges = eels.make_cross_sections(self.edges, np.array(self.energy_scale), beam_kv, eff_beta, self.low_loss)
1290
597
 
1291
598
  if self.dataset.data_type == sidpy.DataType.SPECTRAL_IMAGE:
1292
- spectrum = self.dataset.view.get_spectrum()
599
+ spectrum = self.view.get_spectrum()
1293
600
  else:
1294
601
  spectrum = self.dataset
1295
602
  self.edges = eels.fit_edges2(spectrum, self.energy_scale, edges)
@@ -1307,11 +614,83 @@ class CompositionWidget(object):
1307
614
  self.model = self.edges['model']['spectrum']
1308
615
  self.update()
1309
616
  self.plot()
617
+
618
+ def do_all_button_click(self, value=0):
619
+ if self.sidebar[13,0].value==False:
620
+ return
621
+
622
+ if self.dataset.data_type.name != 'SPECTRAL_IMAGE':
623
+ self.do_fit()
624
+ return
625
+
626
+ if 'experiment' in self.dataset.metadata:
627
+ exp = self.dataset.metadata['experiment']
628
+ if 'convergence_angle' not in exp:
629
+ raise ValueError('need a convergence_angle in experiment of metadata dictionary ')
630
+ alpha = exp['convergence_angle']
631
+ beta = exp['collection_angle']
632
+ beam_kv = exp['acceleration_voltage']
633
+ else:
634
+ raise ValueError('need a experiment parameter in metadata dictionary')
635
+
636
+ eff_beta = eels.effective_collection_angle(self.energy_scale, alpha, beta, beam_kv)
637
+
638
+ self.low_loss = None
639
+ if self.sidebar[12, 1].value:
640
+ for key in self.datasets.keys():
641
+ if key != self.key:
642
+ if isinstance(self.datasets[key], sidpy.Dataset):
643
+ if 'SPECTR' in self.datasets[key].data_type.name:
644
+ if self.datasets[key].energy_loss[0] < 0:
645
+ self.low_loss = self.datasets[key]/self.datasets[key].sum()
646
+
647
+ edges = eels.make_cross_sections(self.edges, np.array(self.energy_scale), beam_kv, eff_beta, self.low_loss)
648
+
649
+ view = self.view
650
+ bin_x = view.bin_x
651
+ bin_y = view.bin_y
652
+
653
+ start_x = view.x
654
+ start_y = view.y
655
+
656
+ number_of_edges = 0
657
+ for key in self.edges:
658
+ if key.isdigit():
659
+ number_of_edges += 1
660
+
661
+ results = np.zeros([int(self.dataset.shape[0]/bin_x), int(self.dataset.shape[1]/bin_y), number_of_edges])
662
+ total_spec = int(self.dataset.shape[0]/bin_x)*int(self.dataset.shape[1]/bin_y)
663
+ self.sidebar[13,1].max = total_spec
664
+ #self.ui.progress.setMaximum(total_spec)
665
+ #self.ui.progress.setValue(0)
666
+ ind = 0
667
+ for x in range(int(self.dataset.shape[0]/bin_x)):
668
+ for y in range(int(self.dataset.shape[1]/bin_y)):
669
+ ind += 1
670
+ self.sidebar[13,1].value = ind
671
+ view.x = x*bin_x
672
+ view.y = y*bin_y
673
+ spectrum = view.get_spectrum()
674
+ with warnings.catch_warnings():
675
+ warnings.simplefilter("ignore")
676
+ edges = eels.fit_edges2(spectrum, self.energy_scale, edges)
677
+ for key, edge in edges.items():
678
+ if key.isdigit():
679
+ # element.append(edge['element'])
680
+ results[x, y, int(key)] = edge['areal_density']
681
+ edges['spectrum_image_quantification'] = results
682
+ self.sidebar[13,1].value = total_spec
683
+ view.x = start_x
684
+ view.y = start_y
685
+ self.sidebar[13,0].value = False
686
+
1310
687
 
1311
688
  def modify_onset(self, value=-1):
1312
689
  edge_index = self.sidebar[4, 0].value
1313
690
  edge = self.edges[str(edge_index)]
1314
691
  edge['onset'] = self.sidebar[7,0].value
692
+ if 'original_onset' not in edge:
693
+ edge['original_onset'] = edge['onset']
1315
694
  edge['chemical_shift'] = edge['onset'] - edge['original_onset']
1316
695
  self.update()
1317
696
 
@@ -1340,7 +719,9 @@ class CompositionWidget(object):
1340
719
  self.model = self.edges['model']['background']
1341
720
  for key in self.edges:
1342
721
  if key.isdigit():
1343
- self.model = self.model + self.edges[key]['areal_density'] * self.edges[key]['data']
722
+ if 'data' in self.edges[key]:
723
+
724
+ self.model = self.model + self.edges[key]['areal_density'] * self.edges[key]['data']
1344
725
  self.plot()
1345
726
 
1346
727
  def set_action(self):
@@ -1348,7 +729,7 @@ class CompositionWidget(object):
1348
729
  self.sidebar[2, 0].observe(self.set_fit_area, names='value')
1349
730
 
1350
731
  self.sidebar[3, 0].on_click(self.find_elements)
1351
- self.sidebar[4, 0].observe(self.update)
732
+ self.sidebar[4, 0].observe(self.update, names='value')
1352
733
  self.sidebar[5, 0].observe(self.set_element, names='value')
1353
734
 
1354
735
  self.sidebar[7, 0].observe(self.modify_onset, names='value')
@@ -1357,7 +738,11 @@ class CompositionWidget(object):
1357
738
  self.sidebar[10, 0].observe(self.modify_areal_density, names='value')
1358
739
 
1359
740
  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)
741
+ self.sidebar[12, 2].observe(self.plot, names='value')
742
+ self.sidebar[0, 0].observe(self.plot, names='value')
743
+ self.sidebar[12,0].observe(self.set_y_scale, names='value')
744
+ self.sidebar[13,0].observe(self.do_all_button_click, names='value')
745
+
746
+ self.elements_cancel_button.on_click(self.set_figure_pane)
747
+ self.elements_auto_button.on_click(self.auto_id)
748
+ self.elements_select_button.on_click(self.set_elements)