pyTEMlib 0.2023.3.0__py2.py3-none-any.whl → 0.2023.8.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pyTEMlib might be problematic. Click here for more details.

pyTEMlib/image_dialog.py CHANGED
@@ -14,7 +14,7 @@ try:
14
14
  from PyQt5 import QtCore, QtWidgets
15
15
  except:
16
16
  Qt_available = False
17
- print('Qt dialogs are not available')
17
+ # print('Qt dialogs are not available')
18
18
 
19
19
  from matplotlib.widgets import SpanSelector
20
20
  from skimage import exposure
pyTEMlib/image_dlg.py CHANGED
@@ -10,7 +10,7 @@ try:
10
10
  from PyQt5 import QtCore, QtGui, QtWidgets
11
11
  except:
12
12
  Qt_available = False
13
- print('Qt dialogs are not available')
13
+ # print('Qt dialogs are not available')
14
14
 
15
15
  from matplotlib.figure import Figure
16
16
 
pyTEMlib/image_tools.py CHANGED
@@ -446,9 +446,9 @@ def demon_registration(dataset, verbose=False):
446
446
 
447
447
  def rigid_registration(dataset):
448
448
  """
449
- Rigid registration of image stack with sub-pixel accuracy
449
+ Rigid registration of image stack with pixel accuracy
450
450
 
451
- Uses phase_cross_correlation from 'skimage.registration'
451
+ Uses simple cross_correlation
452
452
  (we determine drift from one image to next)
453
453
 
454
454
  Parameters
@@ -461,56 +461,71 @@ def rigid_registration(dataset):
461
461
  rigid_registered: sidpy.Dataset
462
462
  Registered Stack and drift (with respect to center image)
463
463
  """
464
-
464
+
465
465
  if not isinstance(dataset, sidpy.Dataset):
466
466
  raise TypeError('We need a sidpy.Dataset')
467
467
  if dataset.data_type.name != 'IMAGE_STACK':
468
468
  raise TypeError('Registration makes only sense for an image stack')
469
-
470
- frame_dim = dataset.get_dimensions_by_type(['temporal'])
471
- image_dims = dataset.get_dimensions_by_type(['spatial'])
472
-
473
- nopix = dataset.shape[image_dims[0]]
474
- nopiy = dataset.shape[image_dims[1]]
469
+
470
+ frame_dim = []
471
+ spatial_dim = []
472
+ selection = []
473
+
474
+ for i, axis in dataset._axes.items():
475
+ if axis.dimension_type.name == 'SPATIAL':
476
+ spatial_dim.append(i)
477
+ selection.append(slice(None))
478
+ else:
479
+ frame_dim.append(i)
480
+ selection.append(slice(0, 1))
481
+
482
+ if len(spatial_dim) != 2:
483
+ print('need two spatial dimensions')
484
+ if len(frame_dim) != 1:
485
+ print('need one frame dimensions')
486
+
487
+ nopix = dataset.shape[spatial_dim[0]]
488
+ nopiy = dataset.shape[spatial_dim[1]]
475
489
  nimages = dataset.shape[frame_dim[0]]
476
-
490
+
477
491
  print('Stack contains ', nimages, ' images, each with', nopix, ' pixels in x-direction and ', nopiy,
478
492
  ' pixels in y-direction')
479
-
480
- data_array = np.moveaxis(np.array(dataset), frame_dim[0], 0)
481
-
482
- fixed = np.array(data_array[0])
483
- fft_fixed = np.fft.fft2(fixed)
484
-
493
+
494
+ fixed = dataset[tuple(selection)].squeeze().compute()
495
+ fft_fixed = np.fft.fft2(fixed)
496
+
485
497
  relative_drift = [[0., 0.]]
486
-
498
+
487
499
  for i in trange(nimages):
488
- moving = np.array(data_array[i])
500
+ selection[frame_dim[0]] = slice(i, i+1)
501
+ moving = dataset[tuple(selection)].squeeze().compute()
489
502
  fft_moving = np.fft.fft2(moving)
490
- if skimage.__version__[:4] == '0.16':
491
- raise DeprecationWarning('Old scikit image version does not work')
492
- else:
493
- shift = registration.phase_cross_correlation(fft_fixed, fft_moving, upsample_factor=1000, space='fourier')
503
+ image_product = fft_fixed * fft_moving.conj()
504
+ cc_image = np.fft.fftshift(np.fft.ifft2(image_product))
505
+ shift =np.array(ndimage.maximum_position(cc_image.real))-cc_image.shape[0]/2
494
506
  fft_fixed = fft_moving
495
- relative_drift.append(shift[0])
496
-
497
- rig_reg, drift = rig_reg_drift(data_array, relative_drift)
507
+ relative_drift.append(shift)
508
+ rig_reg, drift = rig_reg_drift(dataset, relative_drift)
498
509
 
510
+
499
511
  crop_reg, input_crop = crop_image_stack(rig_reg, drift)
500
-
501
- rigid_registered = sidpy.Dataset.from_array(crop_reg)
502
- rigid_registered.set_dimension(0, dataset._axes[frame_dim[0]])
503
- rigid_registered.set_dimension(1, dataset._axes[image_dims[0]][input_crop[0]:input_crop[1]])
504
- rigid_registered.set_dimension(2, dataset._axes[image_dims[1]][input_crop[2]:input_crop[3]])
505
- rigid_registered.data_type = 'Image_stack'
506
-
512
+
513
+ rigid_registered = dataset.like_data(crop_reg)
507
514
  rigid_registered.title = 'Rigid Registration'
508
515
  rigid_registered.source = dataset.title
509
516
  rigid_registered.metadata = {'analysis': 'rigid sub-pixel registration', 'drift': drift,
510
- 'input_crop': input_crop, 'input_shape': np.array(dataset.shape)[image_dims]}
511
-
512
- return rigid_registered
513
-
517
+ 'input_crop': input_crop, 'input_shape': dataset.shape[1:]}
518
+ if hasattr(rigid_registered, 'z'):
519
+ del rigid_registered.z
520
+ if hasattr(rigid_registered, 'x'):
521
+ del rigid_registered.x
522
+ if hasattr(rigid_registered, 'y'):
523
+ del rigid_registered.y
524
+ # rigid_registered._axes = {}
525
+ rigid_registered.set_dimension(0, dataset._axes[frame_dim[0]])
526
+ rigid_registered.set_dimension(1, dataset._axes[spatial_dim[0]][input_crop[0]:input_crop[1]])
527
+ rigid_registered.set_dimension(2, dataset._axes[spatial_dim[1]][input_crop[2]:input_crop[3]])
528
+ return rigid_registered.rechunk({0: 'auto', 1: -1, 2: -1})
514
529
 
515
530
  def rig_reg_drift(dset, rel_drift):
516
531
  """ Shifting images on top of each other
@@ -564,7 +579,7 @@ def rig_reg_drift(dset, rel_drift):
564
579
  for i in range(rig_reg.shape[0]):
565
580
  selection[frame_dim[0]] = slice(i, i+1)
566
581
  # Now we shift
567
- rig_reg[i, :, :] = ndimage.shift(dset[tuple(selection)].squeeze(), [drift[i, 0], drift[i, 1]], order=3)
582
+ rig_reg[i, :, :] = ndimage.shift(dset[tuple(selection)].squeeze().compute(), [drift[i, 0], drift[i, 1]], order=3)
568
583
  return rig_reg, drift
569
584
 
570
585
 
@@ -590,7 +605,6 @@ def crop_image_stack(rig_reg, drift):
590
605
 
591
606
  return rig_reg[:, xpmin:xpmax, ypmin:ypmax], [xpmin, xpmax, ypmin, ypmax]
592
607
 
593
-
594
608
  class ImageWithLineProfile:
595
609
  """Image with line profile"""
596
610
 
@@ -795,6 +809,7 @@ def cart2pol(points):
795
809
 
796
810
  rho = np.linalg.norm(points[:, 0:2], axis=1)
797
811
  phi = np.arctan2(points[:, 1], points[:, 0])
812
+
798
813
  return rho, phi
799
814
 
800
815
 
@@ -839,7 +854,7 @@ def xy2polar(points, rounding=1e-3):
839
854
 
840
855
  r, phi = cart2pol(points)
841
856
 
842
- phi = phi-phi.min() # only positive angles
857
+ phi = phi # %np.pi # only positive angles
843
858
  r = (np.floor(r/rounding))*rounding # Remove rounding error differences
844
859
 
845
860
  sorted_indices = np.lexsort((phi, r)) # sort first by r and then by phi
@@ -926,6 +941,33 @@ def calculate_scherzer(wavelength, cs):
926
941
  return scherzer
927
942
 
928
943
 
944
+ def get_rotation(experiment_spots, crystal_spots):
945
+ """Get rotation by comparing spots in diffractogram to diffraction Bragg spots
946
+
947
+ Parameter
948
+ ---------
949
+ experiment_spots: numpy array (nx2)
950
+ positions (in 1/nm) of spots in diffractogram
951
+ crystal_spots: numpy array (nx2)
952
+ positions (in 1/nm) of Bragg spots according to kinematic scattering theory
953
+
954
+ """
955
+
956
+ r_experiment, phi_experiment = cart2pol(experiment_spots)
957
+
958
+ # get crystal spots of same length and sort them by angle as well
959
+ r_crystal, phi_crystal, crystal_indices = xy2polar(crystal_spots)
960
+ angle_index = np.argmin(np.abs(r_experiment-r_crystal[1]) )
961
+ rotation_angle = phi_experiment[angle_index]%(2*np.pi) - phi_crystal[1]
962
+ print(phi_experiment[angle_index])
963
+ st = np.sin(rotation_angle)
964
+ ct = np.cos(rotation_angle)
965
+ rotation_matrix = np.array([[ct, -st], [st, ct]])
966
+
967
+ return rotation_matrix, rotation_angle
968
+
969
+
970
+
929
971
  def calibrate_image_scale(fft_tags, spots_reference, spots_experiment):
930
972
  """depreciated get change of scale from comparison of spots to Bragg angles """
931
973
  gx = fft_tags['spatial_scale_x']
@@ -947,6 +989,7 @@ def calibrate_image_scale(fft_tags, spots_reference, spots_experiment):
947
989
  return dg
948
990
 
949
991
 
992
+
950
993
  def align_crystal_reflections(spots, crystals):
951
994
  """ Depreciated - use diffraction spots"""
952
995
 
pyTEMlib/info_dialog.py CHANGED
@@ -12,17 +12,21 @@ try:
12
12
  from PyQt5 import QtCore, QtWidgets
13
13
  except:
14
14
  Qt_available = False
15
- print('Qt dialogs are not available')
15
+ # print('Qt dialogs are not available')
16
+
16
17
 
17
- from pyTEMlib import info_dlg
18
18
  import pyTEMlib.eels_dialog_utilities as ieels
19
19
  from pyTEMlib.microscope import microscope
20
-
20
+ import ipywidgets
21
+ import matplotlib.pylab as plt
22
+ import matplotlib
23
+ from IPython.display import display
21
24
  from pyTEMlib import file_tools as ft
22
25
  _version = 000
23
26
 
24
27
 
25
28
  if Qt_available:
29
+ from pyTEMlib import info_dlg
26
30
  class InfoDialog(QtWidgets.QDialog):
27
31
  """
28
32
  Input Dialog for EELS Analysis
@@ -40,7 +44,6 @@ if Qt_available:
40
44
  self.set_action()
41
45
  self.datasets = datasets
42
46
 
43
-
44
47
  self.spec_dim = []
45
48
  self.energy_scale = np.array([])
46
49
  self.experiment = {}
@@ -55,6 +58,8 @@ if Qt_available:
55
58
  # make a dummy dataset for testing
56
59
  key = 'Channel_000'
57
60
  self.datasets={key: ft.make_dummy_dataset(sidpy.DataType.SPECTRUM)}
61
+ if key is None:
62
+ key = list(self.datasets.keys())[0]
58
63
  self.dataset = self.datasets[key]
59
64
  self.key = key
60
65
  if not isinstance(self.dataset, sidpy.Dataset):
@@ -244,21 +249,24 @@ if Qt_available:
244
249
  flux_dataset = self.datasets[key]
245
250
  if flux_dataset.data_type.name == 'IMAGE' or 'SPECTRUM' in flux_dataset.data_type.name:
246
251
  if 'exposure_time' in flux_dataset.metadata['experiment']:
247
- exposure_time = flux_dataset.metadata['experiment']['exposure_time']
252
+ if 'number_of_frames' in flux_dataset.metadata['experiment']:
253
+ exposure_time = flux_dataset.metadata['experiment']['single_exposure_time'] * flux_dataset.metadata['experiment']['number_of_frames']
254
+ else:
255
+ exposure_time = flux_dataset.metadata['experiment']['exposure_time']
248
256
  else:
249
- exposure_time = 1.0
257
+ exposure_time = -1.0
250
258
  flux_dataset.metadata['experiment']['exposure_time'] = -1
251
259
  print('Did not find exposure time assume 1s')
252
260
  if exposure_time > 0:
253
- new_flux = np.sum(np.array(flux_dataset*1e-6))/exposure_time*exposure_time
261
+ new_flux = np.sum(np.array(flux_dataset*1e-6))/exposure_time*self.dataset.metadata['experiment']['exposure_time']
254
262
  title = flux_dataset.title
255
263
  metadata = flux_dataset.metadata
256
- self.experiment['flux_ppm'] = new_flux
257
- self.experiment['flux_units'] = 'counts'
258
- self.experiment['flux_source'] = title
259
- self.experiment['flux_metadata'] = metadata
264
+ self.experiment['flux_ppm'] = new_flux
265
+ self.experiment['flux_units'] = 'Mcounts '
266
+ self.experiment['flux_source'] = title
267
+ self.experiment['flux_metadata'] = metadata
260
268
 
261
- self.update()
269
+ self.update()
262
270
 
263
271
  def on_check(self):
264
272
  sender = self.sender()
@@ -290,15 +298,13 @@ if Qt_available:
290
298
  index = self.ui.select_flux.currentIndex()
291
299
  self.ui.statusBar.showMessage('list'+str(index))
292
300
  if index == 1:
293
- ft.add_dataset_from_file(self.datasets, keyname='Reference')
301
+ ft.add_dataset_from_file(self.datasets, key_name='Reference')
294
302
  self.set_flux_list()
295
303
  else:
296
304
  key = str(self.ui.select_flux.currentText()).split(':')[0]
297
305
  self.set_flux(key)
298
306
 
299
307
  self.update()
300
-
301
-
302
308
 
303
309
  def set_action(self):
304
310
  self.ui.statusBar.showMessage('action')
@@ -322,3 +328,338 @@ if Qt_available:
322
328
 
323
329
  self.ui.binXEdit.editingFinished.connect(self.on_enter)
324
330
  self.ui.binYEdit.editingFinished.connect(self.on_enter)
331
+
332
+
333
+ def get_sidebar():
334
+ side_bar = ipywidgets.GridspecLayout(17, 3,width='auto', grid_gap="0px")
335
+
336
+ side_bar[0, :2] = ipywidgets.Dropdown(
337
+ options=[('None', 0)],
338
+ value=0,
339
+ description='Main Dataset:',
340
+ disabled=False)
341
+
342
+ row = 1
343
+ side_bar[row, :3] = ipywidgets.Button(description='Energy Scale',
344
+ layout=ipywidgets.Layout(width='auto', grid_area='header'),
345
+ style=ipywidgets.ButtonStyle(button_color='lightblue'))
346
+ row += 1
347
+ side_bar[row, :2] = ipywidgets.FloatText(value=7.5,description='Offset:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
348
+ side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='20px'))
349
+ row += 1
350
+ side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Dispersion:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
351
+ side_bar[row, 2] = ipywidgets.widgets.Label(value="eV", layout=ipywidgets.Layout(width='20px'))
352
+
353
+ row += 1
354
+ side_bar[row, :3] = ipywidgets.Button(description='Microscope',
355
+ layout=ipywidgets.Layout(width='auto', grid_area='header'),
356
+ style=ipywidgets.ButtonStyle(button_color='lightblue'))
357
+ row += 1
358
+ side_bar[row, :2] = ipywidgets.FloatText(value=7.5,description='Conv.Angle:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
359
+ side_bar[row, 2] = ipywidgets.widgets.Label(value="mrad", layout=ipywidgets.Layout(width='100px'))
360
+ row += 1
361
+ side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Coll.Angle:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
362
+ side_bar[row, 2] = ipywidgets.widgets.Label(value="mrad", layout=ipywidgets.Layout(width='100px'))
363
+ row += 1
364
+ side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Acc Voltage:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
365
+ side_bar[row, 2] = ipywidgets.widgets.Label(value="keV", layout=ipywidgets.Layout(width='100px'))
366
+ row += 1
367
+
368
+ side_bar[row, :3] = ipywidgets.Button(description='Quantification',
369
+ layout=ipywidgets.Layout(width='auto', grid_area='header'),
370
+ style=ipywidgets.ButtonStyle(button_color='lightblue'))
371
+ row+=1
372
+ side_bar[row, :2] = ipywidgets.Dropdown(
373
+ options=[('None', 0)],
374
+ value=0,
375
+ description='Reference:',
376
+ disabled=False)
377
+ side_bar[row,2] = ipywidgets.ToggleButton(
378
+ description='Probability',
379
+ disabled=False,
380
+ button_style='', # 'success', 'info', 'warning', 'danger' or ''
381
+ tooltip='Changes y-axis to probability if flux is given',
382
+ layout=ipywidgets.Layout(width='100px'))
383
+ row += 1
384
+ side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Exp_Time:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
385
+ side_bar[row, 2] = ipywidgets.widgets.Label(value="s", layout=ipywidgets.Layout(width='100px'))
386
+ row += 1
387
+ side_bar[row, :2] = ipywidgets.FloatText(value=7.5,description='Flux:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
388
+ side_bar[row, 2] = ipywidgets.widgets.Label(value="Mcounts", layout=ipywidgets.Layout(width='100px'))
389
+ row += 1
390
+ side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Conversion:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
391
+ side_bar[row, 2] = ipywidgets.widgets.Label(value=r"e$^-$/counts", layout=ipywidgets.Layout(width='100px'))
392
+ row += 1
393
+ side_bar[row, :2] = ipywidgets.FloatText(value=0.1, description='Current:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
394
+ side_bar[row, 2] = ipywidgets.widgets.Label(value="pA", layout=ipywidgets.Layout(width='100px') )
395
+
396
+ row += 1
397
+
398
+ side_bar[row, :3] = ipywidgets.Button(description='Spectrum Image',
399
+ layout=ipywidgets.Layout(width='auto', grid_area='header'),
400
+ style=ipywidgets.ButtonStyle(button_color='lightblue'))
401
+
402
+ row += 1
403
+ side_bar[row, :2] = ipywidgets.IntText(value=1, description='bin X:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
404
+ row += 1
405
+ side_bar[row, :2] = ipywidgets.IntText(value=1, description='bin X:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
406
+
407
+ for i in range(14, 17):
408
+ side_bar[i, 0].layout.display = "none"
409
+ return side_bar
410
+
411
+
412
+ class SpectrumPlot(sidpy.viz.dataset_viz.CurveVisualizer):
413
+ def __init__(self, dset, spectrum_number=0, figure=None, **kwargs):
414
+ with plt.ioff():
415
+ self.figure = plt.figure()
416
+ self.figure.canvas.toolbar_position = 'right'
417
+ self.figure.canvas.toolbar_visible = True
418
+
419
+ super().__init__(dset, spectrum_number=spectrum_number, figure=self.figure, **kwargs)
420
+
421
+ self.start_cursor = ipywidgets.FloatText(value=0, description='Start:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
422
+ self.end_cursor = ipywidgets.FloatText(value=0, description='End:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
423
+ self.panel = ipywidgets.VBox([ipywidgets.HBox([ipywidgets.Label('',layout=ipywidgets.Layout(width='100px')), ipywidgets.Label('Cursor:'),
424
+ self.start_cursor,ipywidgets.Label('eV'),
425
+ self.end_cursor, ipywidgets.Label('eV')]),
426
+ self.figure.canvas])
427
+
428
+ self.selector = matplotlib.widgets.SpanSelector(self.axis, self.line_select_callback,
429
+ direction="horizontal",
430
+ interactive=True,
431
+ props=dict(facecolor='blue', alpha=0.2))
432
+ #self.axis.legend()
433
+ display(self.panel)
434
+
435
+ def line_select_callback(self, x_min, x_max):
436
+ self.start_cursor.value = np.round(x_min, 3)
437
+ self.end_cursor.value = np.round(x_max, 3)
438
+ self.start_channel = np.searchsorted(self.datasets[self.key].energy_loss, self.start_cursor.value)
439
+ self.end_channel = np.searchsorted(self.datasets[self.key].energy_loss, self.end_cursor.value)
440
+
441
+
442
+ class SIPlot(sidpy.viz.dataset_viz.SpectralImageVisualizer):
443
+ def __init__(self, dset, figure=None, horizontal=True, **kwargs):
444
+ if figure is None:
445
+ with plt.ioff():
446
+ self.figure = plt.figure()
447
+ else:
448
+ self.figure = figure
449
+ self.figure.canvas.toolbar_position = 'right'
450
+ self.figure.canvas.toolbar_visible = True
451
+
452
+ super().__init__(dset, figure= self.figure, horizontal=horizontal, **kwargs)
453
+
454
+ self.start_cursor = ipywidgets.FloatText(value=0, description='Start:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
455
+ self.end_cursor = ipywidgets.FloatText(value=0, description='End:', disabled=False, color='black', layout=ipywidgets.Layout(width='200px'))
456
+ self.panel = ipywidgets.VBox([ipywidgets.HBox([ipywidgets.Label('',layout=ipywidgets.Layout(width='100px')), ipywidgets.Label('Cursor:'),
457
+ self.start_cursor,ipywidgets.Label('eV'),
458
+ self.end_cursor, ipywidgets.Label('eV')]),
459
+ self.figure.canvas])
460
+ self.axis = self.axes[-1]
461
+ self.selector = matplotlib.widgets.SpanSelector(self.axis, self.line_select_callback,
462
+ direction="horizontal",
463
+ interactive=True,
464
+ props=dict(facecolor='blue', alpha=0.2))
465
+
466
+ def line_select_callback(self, x_min, x_max):
467
+ self.start_cursor.value = np.round(x_min, 3)
468
+ self.end_cursor.value = np.round(x_max, 3)
469
+ self.start_channel = np.searchsorted(self.datasets[self.key].energy_loss, self.start_cursor.value)
470
+ self.end_channel = np.searchsorted(self.datasets[self.key].energy_loss, self.end_cursor.value)
471
+
472
+ def _update(self, ev=None):
473
+
474
+ xlim = self.axes[1].get_xlim()
475
+ ylim = self.axes[1].get_ylim()
476
+ self.axes[1].clear()
477
+ self.get_spectrum()
478
+ if len(self.energy_scale)!=self.spectrum.shape[0]:
479
+ self.spectrum = self.spectrum.T
480
+ self.axes[1].plot(self.energy_scale, self.spectrum.compute(), label='experiment')
481
+
482
+ if self.set_title:
483
+ self.axes[1].set_title('spectrum {}, {}'.format(self.x, self.y))
484
+ self.fig.tight_layout()
485
+ self.selector = matplotlib.widgets.SpanSelector(self.axes[1], self.line_select_callback,
486
+ direction="horizontal",
487
+ interactive=True,
488
+ props=dict(facecolor='blue', alpha=0.2))
489
+
490
+ self.axes[1].set_xlim(xlim)
491
+ self.axes[1].set_ylim(ylim)
492
+ self.axes[1].set_xlabel(self.xlabel)
493
+ self.axes[1].set_ylabel(self.ylabel)
494
+
495
+ self.fig.canvas.draw_idle()
496
+
497
+ class InfoWidget(object):
498
+ def __init__(self, datasets=None):
499
+ self.datasets = datasets
500
+ self.dataset = None
501
+
502
+ self.sidebar = get_sidebar()
503
+
504
+ self.set_dataset()
505
+ self.set_action()
506
+
507
+
508
+ self.app_layout = ipywidgets.AppLayout(
509
+ left_sidebar=self.sidebar,
510
+ center=self.view.panel,
511
+ footer=None,#message_bar,
512
+ pane_heights=[0, 10, 0],
513
+ pane_widths=[4, 10, 0],
514
+ )
515
+
516
+ display(self.app_layout)
517
+
518
+
519
+ def get_spectrum(self):
520
+ if self.dataset.data_type == sidpy.DataType.SPECTRAL_IMAGE:
521
+ spectrum = self.dataset.view.get_spectrum()
522
+ self.axis = self.dataset.view.axes[1]
523
+ else:
524
+ spectrum = np.array(self.dataset)
525
+ self.axis = self.dataset.view.axis
526
+
527
+ spectrum *= self.y_scale
528
+ return spectrum
529
+
530
+ def plot(self, scale=True):
531
+ spectrum = self.get_spectrum()
532
+ self.energy_scale = self.dataset.energy_loss.values
533
+ x_limit = self.axis.get_xlim()
534
+ y_limit = np.array(self.axis.get_ylim())
535
+ """
536
+ self.axis.clear()
537
+
538
+ self.axis.plot(self.energy_scale, spectrum, label='spectrum')
539
+
540
+
541
+ self.axis.set_xlabel(self.datasets[self.key].labels[0])
542
+ self.axis.set_ylabel(self.datasets[self.key].data_descriptor)
543
+ self.axis.ticklabel_format(style='sci', scilimits=(-2, 3))
544
+ if scale:
545
+ self.axis.set_ylim(np.array(y_limit)*self.change_y_scale)
546
+ self.change_y_scale = 1.0
547
+ if self.y_scale != 1.:
548
+ self.axis.set_ylabel('scattering probability (ppm/eV)')
549
+ self.selector = matplotlib.widgets.SpanSelector(self.axis, self.line_select_callback,
550
+ direction="horizontal",
551
+ interactive=True,
552
+ props=dict(facecolor='blue', alpha=0.2))
553
+ self.axis.legend()
554
+ self.figure.canvas.draw_idle()
555
+ """
556
+
557
+ def set_dataset(self, index=0):
558
+
559
+ spectrum_list = []
560
+ reference_list =[('None', -1)]
561
+ dataset_index = self.sidebar[0, 0].value
562
+ for index, key in enumerate(self.datasets.keys()):
563
+ if 'Reference' not in key:
564
+ if 'SPECTR' in self.datasets[key].data_type.name:
565
+ spectrum_list.append((f'{key}: {self.datasets[key].title}', index))
566
+ reference_list.append((f'{key}: {self.datasets[key].title}', index))
567
+
568
+ self.sidebar[0,0].options = spectrum_list
569
+ self.sidebar[9,0].options = reference_list
570
+ self.key = list(self.datasets)[dataset_index]
571
+ self.dataset = self.datasets[self.key]
572
+ if 'SPECTRUM' in self.dataset.data_type.name:
573
+ for i in range(14, 17):
574
+ self.sidebar[i, 0].layout.display = "none"
575
+ else:
576
+ for i in range(14, 17):
577
+ self.sidebar[i, 0].layout.display = "flex"
578
+ #self.sidebar[0,0].value = dataset_index #f'{self.key}: {self.datasets[self.key].title}'
579
+ self.sidebar[2,0].value = np.round(self.datasets[self.key].energy_loss[0], 3)
580
+ self.sidebar[3,0].value = np.round(self.datasets[self.key].energy_loss[1] - self.datasets[self.key].energy_loss[0], 4)
581
+ self.sidebar[5,0].value = np.round(self.datasets[self.key].metadata['experiment']['convergence_angle'], 1)
582
+ self.sidebar[6,0].value = np.round(self.datasets[self.key].metadata['experiment']['collection_angle'], 1)
583
+ self.sidebar[7,0].value = np.round(self.datasets[self.key].metadata['experiment']['acceleration_voltage']/1000, 1)
584
+ self.sidebar[10,0].value = np.round(self.datasets[self.key].metadata['experiment']['exposure_time'], 4)
585
+ if 'flux_ppm' not in self.datasets[self.key].metadata['experiment']:
586
+ self.datasets[self.key].metadata['experiment']['flux_ppm'] = 0
587
+ self.sidebar[11,0].value = self.datasets[self.key].metadata['experiment']['flux_ppm']
588
+ if 'count_conversion' not in self.datasets[self.key].metadata['experiment']:
589
+ self.datasets[self.key].metadata['experiment']['count_conversion'] = 1
590
+ self.sidebar[12,0].value = self.datasets[self.key].metadata['experiment']['count_conversion']
591
+ if 'beam_current' not in self.datasets[self.key].metadata['experiment']:
592
+ self.datasets[self.key].metadata['experiment']['beam_current'] = 0
593
+ self.sidebar[13,0].value = self.datasets[self.key].metadata['experiment']['beam_current']
594
+
595
+ self.view = SIPlot(self.dataset)
596
+
597
+ self.y_scale = 1.0
598
+ self.change_y_scale = 1.0
599
+
600
+
601
+ def cursor2energy_scale(self, value):
602
+
603
+ dispersion = (self.end_cursor.value - self.start_cursor.value) / (self.end_channel - self.start_channel)
604
+ self.datasets[self.key].energy_loss *= (self.sidebar[3, 0].value/dispersion)
605
+ self.sidebar[3, 0].value = dispersion
606
+ offset = self.start_cursor.value - self.start_channel * dispersion
607
+ self.datasets[self.key].energy_loss += (self.sidebar[2, 0].value-self.datasets[self.key].energy_loss[0])
608
+ self.sidebar[2, 0].value = offset
609
+ self.plot()
610
+
611
+ def set_energy_scale(self, value):
612
+ dispersion = self.datasets[self.key].energy_loss[1] - self.datasets[self.key].energy_loss[0]
613
+ self.datasets[self.key].energy_loss *= (self.sidebar[3, 0].value/dispersion)
614
+ self.datasets[self.key].energy_loss += (self.sidebar[2, 0].value-self.datasets[self.key].energy_loss[0])
615
+ self.plot()
616
+
617
+ def set_y_scale(self, value):
618
+ self.change_y_scale = 1/self.y_scale
619
+ if self.sidebar[9,2].value:
620
+ dispersion = self.datasets[self.key].energy_loss[1] - self.datasets[self.key].energy_loss[0]
621
+ self.y_scale = 1/self.datasets[self.key].metadata['experiment']['flux_ppm'] * dispersion
622
+ else:
623
+ self.y_scale = 1.0
624
+
625
+ self.change_y_scale *= self.y_scale
626
+ self.plot()
627
+
628
+
629
+ def set_flux(self, value):
630
+ self.datasets[self.key].metadata['experiment']['exposure_time'] = self.sidebar[10,0].value
631
+ if self.sidebar[9,0].value < 0:
632
+ self.datasets[self.key].metadata['experiment']['flux_ppm'] = 0.
633
+ else:
634
+ key = list(self.datasets.keys())[self.sidebar[9,0].value]
635
+ self.datasets[self.key].metadata['experiment']['flux_ppm'] = (np.array(self.datasets[key])*1e-6).sum() / self.datasets[key].metadata['experiment']['exposure_time']
636
+ self.datasets[self.key].metadata['experiment']['flux_ppm'] *= self.datasets[self.key].metadata['experiment']['exposure_time']
637
+ self.sidebar[11,0].value = np.round(self.datasets[self.key].metadata['experiment']['flux_ppm'], 2)
638
+
639
+ def set_microscope_parameter(self, value):
640
+ self.datasets[self.key].metadata['experiment']['convergence_angle'] = self.sidebar[5,0].value
641
+ self.datasets[self.key].metadata['experiment']['collection_angle'] = self.sidebar[6,0].value
642
+ self.datasets[self.key].metadata['experiment']['acceleration_voltage'] = self.sidebar[7,0].value*1000
643
+
644
+ def set_binning(self, value):
645
+ if 'SPECTRAL' in self.dataset.data_type.name:
646
+ bin_x = self.sidebar[15,0].value
647
+ bin_y = self.sidebar[16,0].value
648
+ self.dataset.view.set_bin([bin_x, bin_y])
649
+ self.datasets[self.key].metadata['experiment']['SI_bin_x'] = bin_x
650
+ self.datasets[self.key].metadata['experiment']['SI_bin_y'] = bin_y
651
+
652
+ def set_action(self):
653
+ self.sidebar[0,0].observe(self.set_dataset)
654
+ self.sidebar[1,0].on_click(self.cursor2energy_scale)
655
+ self.sidebar[2,0].observe(self.set_energy_scale, names='value')
656
+ self.sidebar[3,0].observe(self.set_energy_scale, names='value')
657
+ self.sidebar[5,0].observe(self.set_microscope_parameter)
658
+ self.sidebar[6,0].observe(self.set_microscope_parameter)
659
+ self.sidebar[7,0].observe(self.set_microscope_parameter)
660
+ self.sidebar[9,0].observe(self.set_flux)
661
+ self.sidebar[9,2].observe(self.set_y_scale)
662
+ self.sidebar[10,0].observe(self.set_flux)
663
+ self.sidebar[15,0].observe(self.set_binning)
664
+ self.sidebar[16,0].observe(self.set_binning)
665
+
pyTEMlib/info_dlg.py CHANGED
@@ -20,7 +20,7 @@ try:
20
20
 
21
21
  except:
22
22
  Qt_available = False
23
- print('Qt dialogs are not available')
23
+ # print('Qt dialogs are not available')
24
24
 
25
25
 
26
26
  if Qt_available: