tomwer 1.3.0.dev2__py3-none-any.whl → 1.3.0rc10__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.
Files changed (156) hide show
  1. orangecontrib/tomwer/widgets/__init__.py +11 -12
  2. orangecontrib/tomwer/widgets/control/DataListenerOW.py +6 -6
  3. orangecontrib/tomwer/widgets/control/DataValidatorOW.py +6 -6
  4. orangecontrib/tomwer/widgets/control/NXTomomillMixIn.py +3 -3
  5. orangecontrib/tomwer/widgets/control/NXTomomillOW.py +10 -8
  6. orangecontrib/tomwer/widgets/control/SingleTomoObjOW.py +6 -6
  7. orangecontrib/tomwer/widgets/debugtools/DatasetGeneratorOW.py +1 -1
  8. orangecontrib/tomwer/widgets/icat/RawDataScreenshotCreatorOW.py +98 -98
  9. orangecontrib/tomwer/widgets/icat/SaveToGalleryAndPublishOW.py +129 -129
  10. orangecontrib/tomwer/widgets/reconstruction/AxisOW.py +13 -12
  11. orangecontrib/tomwer/widgets/reconstruction/SAAxisOW.py +11 -9
  12. orangecontrib/tomwer/widgets/reconstruction/SADeltaBetaOW.py +11 -9
  13. orangecontrib/tomwer/widgets/reconstruction/SinoNormOW.py +12 -15
  14. orangecontrib/tomwer/widgets/visualization/DataViewerOW.py +9 -9
  15. orangecontrib/tomwer/widgets/visualization/DiffViewerOW.py +1 -1
  16. orangecontrib/tomwer/widgets/visualization/SinogramViewerOW.py +0 -1
  17. tomwer/__main__.py +0 -10
  18. tomwer/app/canvas_launcher/config.py +3 -3
  19. tomwer/app/canvas_launcher/environ.py +1 -0
  20. tomwer/app/intensitynormalization.py +12 -11
  21. tomwer/app/nabuapp.py +0 -11
  22. tomwer/app/zstitching.py +11 -1
  23. tomwer/core/process/control/datalistener/datalistener.py +15 -10
  24. tomwer/core/process/control/nxtomomill.py +1 -1
  25. tomwer/core/process/control/scantransfer.py +8 -32
  26. tomwer/core/process/edit/darkflatpatch.py +8 -9
  27. tomwer/core/process/edit/imagekeyeditor.py +20 -22
  28. tomwer/core/process/icat/screenshots.py +1 -0
  29. tomwer/core/process/reconstruction/axis/axis.py +263 -59
  30. tomwer/core/process/reconstruction/axis/mode.py +161 -50
  31. tomwer/core/process/reconstruction/axis/params.py +23 -20
  32. tomwer/core/process/reconstruction/darkref/darkrefs.py +12 -13
  33. tomwer/core/process/reconstruction/nabu/castvolume.py +3 -3
  34. tomwer/core/process/reconstruction/nabu/nabucommon.py +43 -19
  35. tomwer/core/process/reconstruction/nabu/nabuscores.py +34 -7
  36. tomwer/core/process/reconstruction/nabu/nabuslices.py +81 -26
  37. tomwer/core/process/reconstruction/nabu/nabuvolume.py +31 -26
  38. tomwer/core/process/reconstruction/nabu/plane.py +9 -0
  39. tomwer/core/process/reconstruction/nabu/utils.py +32 -9
  40. tomwer/core/process/reconstruction/saaxis/saaxis.py +4 -1
  41. tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +9 -1
  42. tomwer/core/process/reconstruction/scores/params.py +3 -3
  43. tomwer/core/process/reconstruction/test/test_darkref_copy.py +4 -4
  44. tomwer/core/process/stitching/nabustitcher.py +11 -10
  45. tomwer/core/process/task.py +33 -27
  46. tomwer/core/process/test/test_axis.py +7 -6
  47. tomwer/core/process/test/test_data_transfer.py +3 -3
  48. tomwer/core/process/test/test_nabu.py +10 -2
  49. tomwer/core/process/test/test_normalization.py +2 -2
  50. tomwer/core/scan/blissscan.py +3 -3
  51. tomwer/core/scan/edfscan.py +9 -9
  52. tomwer/core/scan/nxtomoscan.py +11 -11
  53. tomwer/core/scan/scanbase.py +31 -24
  54. tomwer/core/scan/test/test_future_scan.py +1 -1
  55. tomwer/core/scan/test/test_h5.py +4 -4
  56. tomwer/core/scan/test/test_process_registration.py +2 -2
  57. tomwer/core/scan/test/test_scan.py +1 -75
  58. tomwer/core/settings.py +3 -3
  59. tomwer/core/test/test_utils.py +2 -2
  60. tomwer/core/volume/edfvolume.py +6 -6
  61. tomwer/core/volume/hdf5volume.py +6 -6
  62. tomwer/core/volume/jp2kvolume.py +6 -6
  63. tomwer/core/volume/rawvolume.py +6 -6
  64. tomwer/core/volume/tiffvolume.py +12 -12
  65. tomwer/gui/cluster/slurm.py +14 -9
  66. tomwer/gui/cluster/supervisor.py +12 -0
  67. tomwer/gui/cluster/test/test_cluster.py +1 -2
  68. tomwer/gui/cluster/test/test_supervisor.py +1 -1
  69. tomwer/gui/control/datalist.py +5 -0
  70. tomwer/gui/control/datawatcher/controlwidget.py +2 -4
  71. tomwer/gui/control/reducedarkflatselector.py +8 -8
  72. tomwer/gui/control/test/test_single_tomo_obj.py +1 -1
  73. tomwer/gui/edit/dkrfpatch.py +4 -4
  74. tomwer/gui/edit/nxtomowarmer.py +2 -2
  75. tomwer/gui/edit/test/test_dkrf_patch.py +6 -6
  76. tomwer/gui/imagefromfile.py +2 -2
  77. tomwer/gui/qfolderdialog.py +5 -0
  78. tomwer/gui/reconstruction/axis/CompareImages.py +94 -168
  79. tomwer/gui/reconstruction/axis/radioaxis.py +58 -182
  80. tomwer/gui/reconstruction/darkref/darkrefwidget.py +2 -1
  81. tomwer/gui/reconstruction/nabu/castvolume.py +8 -1
  82. tomwer/gui/reconstruction/nabu/nabuconfig/reconstruction.py +54 -21
  83. tomwer/gui/reconstruction/normalization/intensity.py +3 -25
  84. tomwer/gui/reconstruction/saaxis/corrangeselector.py +1 -1
  85. tomwer/gui/reconstruction/saaxis/saaxis.py +1 -11
  86. tomwer/gui/reconstruction/sadeltabeta/saadeltabeta.py +0 -10
  87. tomwer/gui/reconstruction/scores/scoreplot.py +1 -6
  88. tomwer/gui/reconstruction/test/test_axis.py +18 -4
  89. tomwer/gui/reconstruction/test/test_nabu.py +3 -0
  90. tomwer/gui/stitching/stitching.py +2 -2
  91. tomwer/gui/stitching/stitching_preview.py +7 -53
  92. tomwer/gui/stitching/stitching_raw.py +3 -3
  93. tomwer/gui/utils/inputwidget.py +12 -2
  94. tomwer/gui/utils/lineselector/lineselector.py +1 -1
  95. tomwer/gui/visualization/dataviewer.py +47 -17
  96. tomwer/gui/visualization/sinogramviewer.py +19 -26
  97. tomwer/gui/visualization/test/test_volumeviewer.py +64 -66
  98. tomwer/gui/visualization/volumeviewer.py +105 -105
  99. tomwer/io/utils/h5pyutils.py +7 -3
  100. tomwer/io/utils/utils.py +3 -3
  101. tomwer/resources/gui/icons/parameters.svg +1 -1
  102. tomwer/resources/gui/illustrations/no_rot.svg +1 -1
  103. tomwer/synctools/stacks/edit/darkflatpatch.py +17 -12
  104. tomwer/tests/test_scripts.py +0 -3
  105. tomwer/third_part/WaitingOverlay.py +110 -0
  106. tomwer/third_part/__init__.py +0 -0
  107. tomwer/version.py +2 -2
  108. {tomwer-1.3.0.dev2.dist-info → tomwer-1.3.0rc10.dist-info}/METADATA +32 -31
  109. {tomwer-1.3.0.dev2.dist-info → tomwer-1.3.0rc10.dist-info}/RECORD +115 -153
  110. {tomwer-1.3.0.dev2.dist-info → tomwer-1.3.0rc10.dist-info}/WHEEL +1 -1
  111. orangecontrib/tomwer/widgets/reconstruction/TofuOW.py +0 -197
  112. orangecontrib/tomwer/widgets/reconstruction/icons/XY_lamino.svg +0 -168
  113. orangecontrib/tomwer/widgets/reconstruction/icons/XZ_lamino.svg +0 -275
  114. orangecontrib/tomwer/widgets/reconstruction/icons/YZ_lamino.svg +0 -182
  115. tomwer/app/lamino.py +0 -143
  116. tomwer/core/process/reconstruction/lamino/__init__.py +0 -1
  117. tomwer/core/process/reconstruction/lamino/tofu.py +0 -1000
  118. tomwer/core/process/test/test_lamino.py +0 -76
  119. tomwer/core/test/test_lamino.py +0 -92
  120. tomwer/gui/reconstruction/lamino/__init__.py +0 -31
  121. tomwer/gui/reconstruction/lamino/tofu/TofuOptionLoader.py +0 -107
  122. tomwer/gui/reconstruction/lamino/tofu/__init__.py +0 -1
  123. tomwer/gui/reconstruction/lamino/tofu/misc.py +0 -148
  124. tomwer/gui/reconstruction/lamino/tofu/projections.py +0 -896
  125. tomwer/gui/reconstruction/lamino/tofu/settings.py +0 -75
  126. tomwer/gui/reconstruction/lamino/tofu/tofu.py +0 -432
  127. tomwer/gui/reconstruction/lamino/tofu/tofuexpert.py +0 -567
  128. tomwer/gui/reconstruction/lamino/tofu/tofuoutput.py +0 -757
  129. tomwer/gui/reconstruction/test/test_lamino.py +0 -194
  130. tomwer/resources/gui/icons/lamino_parameters.svg +0 -70
  131. tomwer/resources/gui/illustrations/lamino_angle.png +0 -0
  132. tomwer/resources/gui/illustrations/lamino_angle.svg +0 -509
  133. tomwer/resources/gui/illustrations/lamino_beta_angle.png +0 -0
  134. tomwer/resources/gui/illustrations/lamino_beta_angle.svg +0 -97
  135. tomwer/resources/gui/illustrations/lamino_theta_angle.png +0 -0
  136. tomwer/resources/gui/illustrations/lamino_theta_angle.svg +0 -368
  137. tomwer/resources/gui/illustrations/manual_slice.png +0 -0
  138. tomwer/resources/gui/illustrations/manual_slice.svg +0 -221
  139. tomwer/resources/gui/illustrations/psi_angle.png +0 -0
  140. tomwer/resources/gui/illustrations/psi_angle.svg +0 -479
  141. tomwer/resources/gui/illustrations/rotation_center.png +0 -0
  142. tomwer/resources/gui/illustrations/rotation_center.svg +0 -276
  143. tomwer/resources/gui/illustrations/slice_stack.png +0 -0
  144. tomwer/resources/gui/illustrations/slice_stack.svg +0 -266
  145. tomwer/resources/gui/illustrations/xy_slice.png +0 -0
  146. tomwer/resources/gui/illustrations/xy_slice.svg +0 -269
  147. tomwer/resources/gui/illustrations/xz_slice.png +0 -0
  148. tomwer/resources/gui/illustrations/xz_slice.svg +0 -270
  149. tomwer/resources/gui/illustrations/yz_slice.png +0 -0
  150. tomwer/resources/gui/illustrations/yz_slice.svg +0 -270
  151. tomwer/synctools/stacks/reconstruction/lamino.py +0 -233
  152. /tomwer-1.3.0.dev2-py3.11-nspkg.pth → /tomwer-1.3.0rc10-py3.11-nspkg.pth +0 -0
  153. {tomwer-1.3.0.dev2.dist-info → tomwer-1.3.0rc10.dist-info}/LICENSE +0 -0
  154. {tomwer-1.3.0.dev2.dist-info → tomwer-1.3.0rc10.dist-info}/entry_points.txt +0 -0
  155. {tomwer-1.3.0.dev2.dist-info → tomwer-1.3.0rc10.dist-info}/namespace_packages.txt +0 -0
  156. {tomwer-1.3.0.dev2.dist-info → tomwer-1.3.0rc10.dist-info}/top_level.txt +0 -0
@@ -35,6 +35,7 @@ from silx.gui import qt
35
35
  from silx.gui.dialog.DataFileDialog import DataFileDialog
36
36
  from silx.utils.enum import Enum as _Enum
37
37
 
38
+ from tomwer.core.process.reconstruction.nabu.plane import NabuPlane
38
39
  from tomwer.core.process.reconstruction.nabu.nabuslices import NabuSliceMode
39
40
  from tomwer.core.process.reconstruction.nabu.utils import (
40
41
  _NabuFBPFilterType,
@@ -300,55 +301,74 @@ class _NabuReconstructionConfig(qt.QWidget, _NabuStageConfigBase):
300
301
  # come with an issue as we are on a scroll area
301
302
  self._slicesWidget.setFocusPolicy(qt.Qt.FocusPolicy.NoFocus)
302
303
 
304
+ # axis
305
+ self._axisLabel = qt.QLabel("reconstruction plane", self)
306
+ self._axisLabel.setToolTip("Over which axis the slice must be picked")
307
+ self.layout().addWidget(self._axisLabel)
308
+ self._axisQCB = qt.QComboBox(self)
309
+ axis_tooltips = {
310
+ NabuPlane.YZ.value: "along axis x (aka axis 2 - expected to be slow)",
311
+ NabuPlane.XZ.value: "along axis y (aka axis 1 - expected to be slow)",
312
+ NabuPlane.XY.value: "along axis Z (aka axis 0 - fastest)",
313
+ }
314
+ for item, tooltip in axis_tooltips.items():
315
+ self._axisQCB.addItem(item)
316
+ self._axisQCB.setItemData(
317
+ self._axisQCB.findText(item),
318
+ tooltip,
319
+ qt.Qt.ToolTipRole,
320
+ )
321
+ self.layout().addWidget(self._axisQCB, 1, 1, 1, 1)
322
+
303
323
  # method
304
324
  self._methodLabel = qt.QLabel("method", self)
305
- self.layout().addWidget(self._methodLabel, 1, 0, 1, 1)
325
+ self.layout().addWidget(self._methodLabel, 2, 0, 1, 1)
306
326
  self._methodQCB = QComboBoxIgnoreWheel(parent=self, scrollArea=scrollArea)
307
327
  for method in _NabuReconstructionMethods:
308
328
  self._methodQCB.addItem(method.value)
309
- self.layout().addWidget(self._methodQCB, 1, 1, 1, 1)
329
+ self.layout().addWidget(self._methodQCB, 2, 1, 1, 1)
310
330
  self.registerWidget(self._methodLabel, "required")
311
331
  self.registerWidget(self._methodQCB, "required")
312
332
 
313
333
  # angle_offset
314
334
  self._labelOffsetLabel = qt.QLabel("angle offset (in degree)", self)
315
- self.layout().addWidget(self._labelOffsetLabel, 2, 0, 1, 1)
335
+ self.layout().addWidget(self._labelOffsetLabel, 3, 0, 1, 1)
316
336
  self._angleOffsetQDSB = QDoubleSpinBoxIgnoreWheel(self, scrollArea)
317
337
  self._angleOffsetQDSB.setMaximum(-180)
318
338
  self._angleOffsetQDSB.setMaximum(180)
319
- self.layout().addWidget(self._angleOffsetQDSB, 2, 1, 1, 1)
339
+ self.layout().addWidget(self._angleOffsetQDSB, 3, 1, 1, 1)
320
340
  self.registerWidget(self._labelOffsetLabel, "advanced")
321
341
  self.registerWidget(self._angleOffsetQDSB, "advanced")
322
342
 
323
343
  # fbp filter type
324
344
  self._fbpFilterCB = qt.QCheckBox("fbp filter", self)
325
- self.layout().addWidget(self._fbpFilterCB, 3, 0, 1, 1)
345
+ self.layout().addWidget(self._fbpFilterCB, 4, 0, 1, 1)
326
346
  self._fbpFilterType = QComboBoxIgnoreWheel(self, scrollArea)
327
347
  for filter_type in _NabuFBPFilterType:
328
348
  self._fbpFilterType.addItem(filter_type.value)
329
- self.layout().addWidget(self._fbpFilterType, 3, 1, 1, 1)
349
+ self.layout().addWidget(self._fbpFilterType, 4, 1, 1, 1)
330
350
  self.registerWidget(self._fbpFilterCB, "advanced")
331
351
  self.registerWidget(self._fbpFilterType, "advanced")
332
352
 
333
353
  # padding type
334
354
  self._paddingTypeLabel = qt.QLabel("padding type", self)
335
- self.layout().addWidget(self._paddingTypeLabel, 4, 0, 1, 1)
355
+ self.layout().addWidget(self._paddingTypeLabel, 5, 0, 1, 1)
336
356
  self._paddingType = QComboBoxIgnoreWheel(self, scrollArea)
337
357
  for fbp_padding_type in _NabuPaddingType:
338
358
  self._paddingType.addItem(fbp_padding_type.value)
339
- self.layout().addWidget(self._paddingType, 4, 1, 1, 1)
359
+ self.layout().addWidget(self._paddingType, 5, 1, 1, 1)
340
360
  self.registerWidget(self._paddingTypeLabel, "optional")
341
361
  self.registerWidget(self._paddingType, "optional")
342
362
 
343
363
  # sub region
344
364
  self._subRegionSelector = _NabuReconstructionSubRegion(parent=self)
345
- self.layout().addWidget(self._subRegionSelector, 6, 0, 1, 2)
365
+ self.layout().addWidget(self._subRegionSelector, 7, 0, 1, 2)
346
366
 
347
367
  # iterations
348
368
  self._iterationsLabel = qt.QLabel("iterations", self)
349
- self.layout().addWidget(self._iterationsLabel, 7, 0, 1, 1)
369
+ self.layout().addWidget(self._iterationsLabel, 8, 0, 1, 1)
350
370
  self._iterationSB = qt.QSpinBox(parent=self)
351
- self.layout().addWidget(self._iterationSB, 7, 1, 1, 1)
371
+ self.layout().addWidget(self._iterationSB, 8, 1, 1, 1)
352
372
  self._iterationSB.setMinimum(1)
353
373
  self._iterationSB.setMaximum(9999)
354
374
  # not supported for now so hidden
@@ -359,14 +379,14 @@ class _NabuReconstructionConfig(qt.QWidget, _NabuStageConfigBase):
359
379
  self._binSubSamplingGB = _BinSubSampling(
360
380
  "binning and subsampling", parent=self, scrollArea=scrollArea
361
381
  )
362
- self.layout().addWidget(self._binSubSamplingGB, 8, 0, 1, 2)
382
+ self.layout().addWidget(self._binSubSamplingGB, 9, 0, 1, 2)
363
383
 
364
384
  # optimization algorithm:
365
385
  # set has default value for now, because has only one at the moment
366
386
 
367
387
  # weight total variation
368
388
  self._tvLabel = qt.QLabel("total variation weight", self)
369
- self.layout().addWidget(self._tvLabel, 9, 0, 1, 1)
389
+ self.layout().addWidget(self._tvLabel, 10, 0, 1, 1)
370
390
  self._totalVariationWeight = qt.QDoubleSpinBox(self)
371
391
  self._totalVariationWeight.setMinimum(0.0)
372
392
  self._totalVariationWeight.setMaximum(1.0)
@@ -382,7 +402,7 @@ class _NabuReconstructionConfig(qt.QWidget, _NabuStageConfigBase):
382
402
  self._preconditioningFilter.setToolTip(
383
403
  'Whether to enable "filter ' 'preconditioning" for iterative' " methods"
384
404
  )
385
- self.layout().addWidget(self._preconditioningFilter, 9, 0, 1, 2)
405
+ self.layout().addWidget(self._preconditioningFilter, 10, 0, 1, 2)
386
406
  # not supported for now so hidden
387
407
  self._preconditioningFilter.hide()
388
408
 
@@ -391,7 +411,7 @@ class _NabuReconstructionConfig(qt.QWidget, _NabuStageConfigBase):
391
411
  self._positivityConstraintCB.setToolTip(
392
412
  "Whether to enforce a " "positivity constraint in the " "reconstruction."
393
413
  )
394
- self.layout().addWidget(self._positivityConstraintCB, 10, 0, 1, 2)
414
+ self.layout().addWidget(self._positivityConstraintCB, 11, 0, 1, 2)
395
415
  # not supported for now so hidden
396
416
  self._positivityConstraintCB.hide()
397
417
 
@@ -400,28 +420,28 @@ class _NabuReconstructionConfig(qt.QWidget, _NabuStageConfigBase):
400
420
  self._clipOuterCircleCB.setToolTip(
401
421
  "Whether to set to zero voxels falling outside of the reconstruction region"
402
422
  )
403
- self.layout().addWidget(self._clipOuterCircleCB, 11, 0, 1, 2)
423
+ self.layout().addWidget(self._clipOuterCircleCB, 12, 0, 1, 2)
404
424
  self.registerWidget(self._clipOuterCircleCB, "optional")
405
425
 
406
426
  # centered axis option
407
427
  self._centeredAxisCB = qt.QCheckBox("centered axis", self)
408
428
  self._centeredAxisCB.setToolTip("")
409
- self.layout().addWidget(self._centeredAxisCB, 12, 0, 1, 2)
429
+ self.layout().addWidget(self._centeredAxisCB, 13, 0, 1, 2)
410
430
  self.registerWidget(self._centeredAxisCB, "optional")
411
431
 
412
432
  # translation movement file
413
433
  self._transMvtFileLabel = qt.QLabel("translation movement file", self)
414
- self.layout().addWidget(self._transMvtFileLabel, 21, 0, 1, 1)
434
+ self.layout().addWidget(self._transMvtFileLabel, 22, 0, 1, 1)
415
435
  self._transMvtFileWidget = TranslationMvtFileWidget(self)
416
- self.layout().addWidget(self._transMvtFileWidget, 21, 1, 1, 1)
436
+ self.layout().addWidget(self._transMvtFileWidget, 22, 1, 1, 1)
417
437
  self.registerWidget(self._transMvtFileLabel, "advanced")
418
438
  self.registerWidget(self._transMvtFileWidget, "advanced")
419
439
 
420
440
  # angle files (if the user want's to overwrite rotation angles)
421
441
  self._angleFileLabel = qt.QLabel("angles file", self)
422
- self.layout().addWidget(self._angleFileLabel, 22, 0, 1, 1)
442
+ self.layout().addWidget(self._angleFileLabel, 23, 0, 1, 1)
423
443
  self._anglesFileWidget = AnglesFileWidget(self)
424
- self.layout().addWidget(self._anglesFileWidget, 22, 1, 1, 1)
444
+ self.layout().addWidget(self._anglesFileWidget, 23, 1, 1, 1)
425
445
  self.registerWidget(self._angleFileLabel, "advanced")
426
446
  self.registerWidget(self._anglesFileWidget, "advanced")
427
447
 
@@ -431,6 +451,7 @@ class _NabuReconstructionConfig(qt.QWidget, _NabuStageConfigBase):
431
451
  self.layout().addWidget(spacer, 200, 1, 1, 1)
432
452
 
433
453
  # set up
454
+ self.setNabuPlane("XY")
434
455
  self._fbpFilterCB.setChecked(True)
435
456
  fbp_item = self._methodQCB.findText(_NabuReconstructionMethods.FBP.value)
436
457
  self._methodQCB.setCurrentIndex(fbp_item)
@@ -447,6 +468,7 @@ class _NabuReconstructionConfig(qt.QWidget, _NabuStageConfigBase):
447
468
  self._centeredAxisCB.setChecked(False)
448
469
 
449
470
  # connect signal / slot
471
+ self._axisQCB.currentIndexChanged.connect(self._slicesChanged)
450
472
  self._methodQCB.currentIndexChanged.connect(self._methodChanged)
451
473
  self._angleOffsetQDSB.editingFinished.connect(self._angleOffsetChanged)
452
474
  self._fbpFilterCB.toggled.connect(self._FBPFilterTypeChanged)
@@ -628,6 +650,14 @@ class _NabuReconstructionConfig(qt.QWidget, _NabuStageConfigBase):
628
650
  def setCenteredAxis(self, checked: bool):
629
651
  self._centeredAxisCB.setChecked(checked)
630
652
 
653
+ def getNabuPlane(self) -> NabuPlane:
654
+ """return over which axis we expect to do the reconstruction"""
655
+ return NabuPlane.from_value(self._axisQCB.currentText())
656
+
657
+ def setNabuPlane(self, axis: typing.Union[str, NabuPlane]):
658
+ axis = NabuPlane.from_value(axis)
659
+ self._axisQCB.setCurrentText(axis.value)
660
+
631
661
  @docstring(_NabuStageConfigBase)
632
662
  def getConfiguration(self) -> dict:
633
663
  fbp_filter_type = self.getFBPFilterType()
@@ -637,6 +667,7 @@ class _NabuReconstructionConfig(qt.QWidget, _NabuStageConfigBase):
637
667
  fbp_filter_type = fbp_filter_type.value
638
668
  config = {
639
669
  "method": self.getMethod().value,
670
+ "slice_plane": self.getNabuPlane().value,
640
671
  "angles_file": self.getAnglesFile(),
641
672
  "axis_correction_file": "", # not managed for now
642
673
  "angle_offset": self.getAngleOffset(),
@@ -689,6 +720,8 @@ class _NabuReconstructionConfig(qt.QWidget, _NabuStageConfigBase):
689
720
  self.setClipOuterCircle(bool(config["clip_outer_circle"]))
690
721
  if "centered_axis" in config:
691
722
  self.setCenteredAxis(bool(config["centered_axis"]))
723
+ if "slice_plane" in config:
724
+ self.setNabuPlane(config["slice_plane"])
692
725
  self._subRegionSelector.setConfiguration(config=config)
693
726
 
694
727
  def _signalConfChanged(self, param):
@@ -96,11 +96,6 @@ class SinoNormWindow(qt.QMainWindow):
96
96
  self._centralWidget._updateSinogramROI()
97
97
  self._modeChanged()
98
98
 
99
- def close(self):
100
- self._centralWidget.stop()
101
- self._centralWidget = None
102
- super().close()
103
-
104
99
  def _hideLockButton(self):
105
100
  self._optsWidget._hideLockButton()
106
101
 
@@ -165,11 +160,6 @@ class SinoNormWindow(qt.QMainWindow):
165
160
  self._centralWidget.setScan(scan=scan)
166
161
  self._optsWidget.setScan(scan=scan)
167
162
 
168
- def stop(self):
169
- if self._centralWidget is not None:
170
- self._centralWidget.stop()
171
- self._centralWidget = None
172
-
173
163
  def getExtraArgs(self) -> dict:
174
164
  return self._optsWidget.getExtraInfos()
175
165
 
@@ -246,12 +236,6 @@ class _Viewer(qt.QTabWidget):
246
236
  self._projView.setManualROIVisible(visible=visible)
247
237
  self._sinoView.setROIVisible(visible=visible)
248
238
 
249
- def stop(self):
250
- self._projView.stop()
251
- self._projView = None
252
- self._sinoView.stop()
253
- self._sinoView = None
254
-
255
239
  def getROI(self):
256
240
  return self._projView.getROI()
257
241
 
@@ -341,9 +325,6 @@ class _ProjPlotWithROI(DataViewer):
341
325
  super().clear()
342
326
  self.getPlotWidget().removeMarker("sinogram_line")
343
327
 
344
- def stop(self):
345
- self._viewer._plot.stopUpdateThread()
346
-
347
328
 
348
329
  class SinogramViewer(_SinogramViewer):
349
330
  """ "Sinogram viewer but adapated for Intensity normalization"""
@@ -397,14 +378,11 @@ class SinogramViewer(_SinogramViewer):
397
378
  self.getPlotWidget().addItem(item)
398
379
 
399
380
  def getPlotWidget(self):
400
- return self._plot.getPlotWidget()
381
+ return self._plot
401
382
 
402
383
  def _updatePlot(self, sinogram):
403
- self._plot.getPlotWidget().addImage(data=sinogram)
404
- self._plot.getPlotWidget().replot()
405
-
406
- def stop(self):
407
- self._plot.stopUpdateThread()
384
+ self.getPlotWidget().addImage(data=sinogram)
385
+ self.getPlotWidget().replot()
408
386
 
409
387
 
410
388
  class _NormIntensityOptions(qt.QWidget):
@@ -148,7 +148,7 @@ class SinogramViewer(_SinogramViewer):
148
148
  self._estimated_cor = estimated_cor
149
149
  self._other_cors = other_cors if other_cors is not None else tuple()
150
150
 
151
- plot = self._plot.getPlotWidget()
151
+ plot = self._plot
152
152
 
153
153
  if self._corMarker is not None:
154
154
  self._corMarker.sigDragFinished.disconnect(self._middleMarkerMoved)
@@ -303,10 +303,6 @@ class _SAAxisTabWidget(qt.QTabWidget):
303
303
  self._nabuSettings = None
304
304
  super().close()
305
305
 
306
- def _stopAnimationThread(self):
307
- self._resultsViewer._stopAnimationThread()
308
- self._sliceAndCorWidget._sinogramViewer._stopAnimationThread()
309
-
310
306
 
311
307
  class SAAxisWindow(qt.QMainWindow):
312
308
  """
@@ -381,9 +377,6 @@ class SAAxisWindow(qt.QMainWindow):
381
377
  self._saaxisControl.sigComputationRequest.connect(self._launchReconstructions)
382
378
  self._saaxisControl.sigValidateRequest.connect(self._validate)
383
379
 
384
- def stop(self):
385
- self._stopAnimationThread()
386
-
387
380
  def showResults(self):
388
381
  self._tabWidget.showResults()
389
382
 
@@ -451,7 +444,7 @@ class SAAxisWindow(qt.QMainWindow):
451
444
  def _updateSinogramLine(self):
452
445
  r_slice = self.getReconstructionSlices()
453
446
  if r_slice == "middle":
454
- line = slice_index_to_int(slice_index="middle", scan=self._scan)
447
+ line = slice_index_to_int(slice_index="middle", scan=self._scan, axis="XY")
455
448
  else:
456
449
  line = list(r_slice.values())[0]
457
450
  self._tabWidget.getSinogramViewer().setLine(line)
@@ -507,9 +500,6 @@ class SAAxisWindow(qt.QMainWindow):
507
500
  if idx >= 0:
508
501
  self._tabWidget.setCurrentIndex(idx)
509
502
 
510
- def _stopAnimationThread(self):
511
- self._tabWidget._stopAnimationThread()
512
-
513
503
  def close(self):
514
504
  self._tabWidget.close()
515
505
  self._tabWidget = None
@@ -239,7 +239,6 @@ class _SADeltaBetaTabWidget(qt.QTabWidget):
239
239
  self._resultsViewer.setScoreMethod(method)
240
240
 
241
241
  def close(self):
242
- self._stopAnimationThread()
243
242
  self._resultsViewer.close()
244
243
  self._resultsViewer = None
245
244
  self._deltaBetaSelectionWidget.close()
@@ -248,9 +247,6 @@ class _SADeltaBetaTabWidget(qt.QTabWidget):
248
247
  self._nabuSettings = None
249
248
  super().close()
250
249
 
251
- def _stopAnimationThread(self):
252
- self._resultsViewer._stopAnimationThread()
253
-
254
250
  def setSliceRange(self, min_, max_):
255
251
  self._deltaBetaSelectionWidget.setSliceRange(min_, max_)
256
252
 
@@ -357,12 +353,6 @@ class SADeltaBetaWindow(qt.QMainWindow):
357
353
  self._tabWidget = None
358
354
  super().close()
359
355
 
360
- def stop(self):
361
- self._stopAnimationThread()
362
-
363
- def _stopAnimationThread(self):
364
- self._tabWidget._stopAnimationThread()
365
-
366
356
  def setDBScores(
367
357
  self,
368
358
  scores: dict,
@@ -612,12 +612,7 @@ class ScorePlot(qt.QWidget):
612
612
  self.sigConfigurationChanged.emit()
613
613
 
614
614
  def getPlotWidget(self):
615
- return self._plot.getPlotWidget()
616
-
617
- def _stopAnimationThread(self):
618
- self._plot._freeLoadingThreads()
619
- if self._plot._plot.updateThread.is_alive():
620
- self._plot._plot.updateThread.stop()
615
+ return self._plot
621
616
 
622
617
  def close(self):
623
618
  self._plot.close()
@@ -74,19 +74,33 @@ class TestWindowAxis(TestCaseQt):
74
74
  def testSetImagesNumpyArray(self):
75
75
  """Test the setImages function"""
76
76
  radio_axis = self._window._axisWidget._radioAxis
77
- self.assertEqual(radio_axis.getPlot().getPlot().getActiveImage(), None)
77
+ radio_axis_plot = self._window._axisWidget._radioAxis.getPlot()
78
+ numpy.testing.assert_array_equal(
79
+ radio_axis_plot.getPlot().getActiveImage().getData(), numpy.empty((0, 0, 4))
80
+ )
78
81
  imgA = numpy.random.random((100, 100))
79
82
  imgB = numpy.random.random((100, 100))
80
83
  radio_axis.setImages(imgA=imgA, imgB=imgB, flipB=True)
81
84
  self.qapp.processEvents()
82
- self.assertNotEqual(radio_axis.getPlot().getPlot().getActiveImage(), None)
85
+ # make sur the image has been set
86
+ assert radio_axis_plot.getPlot().getImage(legend="image1").getData().shape == (
87
+ 100,
88
+ 100,
89
+ )
83
90
 
84
91
  def testSetScan(self):
85
92
  """Test the setScan function"""
86
93
  radio_axis_plot = self._window._axisWidget._radioAxis.getPlot()
87
- self.assertEqual(radio_axis_plot.getPlot().getActiveImage(), None)
94
+ numpy.testing.assert_array_equal(
95
+ radio_axis_plot.getPlot().getActiveImage().getData(), numpy.empty((0, 0, 4))
96
+ )
88
97
  self._window.setScan(self.scan)
89
- self.assertNotEqual(radio_axis_plot.getPlot().getActiveImage(), None)
98
+ self.qapp.processEvents()
99
+ # make sur the image has been set
100
+ assert radio_axis_plot.getPlot().getImage(legend="image1").getData().shape == (
101
+ 20,
102
+ 20,
103
+ )
90
104
 
91
105
  def testShiftButtons(self):
92
106
  """Test that the 'left', 'right', ... buttons and the shift steps are
@@ -219,6 +219,7 @@ class TestNabuReconstructionConfig(TestCaseQt):
219
219
  """Test that the get configuration is working"""
220
220
  ini_conf = {
221
221
  "method": "FBP",
222
+ "slice_plane": "XY",
222
223
  "angles_file": "",
223
224
  "axis_correction_file": "",
224
225
  "angle_offset": 0.0,
@@ -246,6 +247,7 @@ class TestNabuReconstructionConfig(TestCaseQt):
246
247
  """Test that the set configuration is working"""
247
248
  ini_conf = {
248
249
  "method": "FBP",
250
+ "slice_plane": "XZ",
249
251
  "angles_file": "",
250
252
  "axis_correction_file": "",
251
253
  "angle_offset": 12.5,
@@ -284,6 +286,7 @@ class TestNabuReconstructionConfig(TestCaseQt):
284
286
  self.assertFalse(self.nabuWidget._preconditioningFilter.isChecked())
285
287
  self.assertTrue(self.nabuWidget._clipOuterCircleCB.isChecked())
286
288
  self.assertTrue(self.nabuWidget._centeredAxisCB.isChecked())
289
+ assert self.nabuWidget._axisQCB.currentText() == ini_conf["slice_plane"]
287
290
 
288
291
  # check the generated configuration
289
292
  self.assertEqual(self.nabuWidget.getConfiguration(), ini_conf)
@@ -727,7 +727,7 @@ class ZStitchingWindow(qt.QMainWindow):
727
727
 
728
728
  # clean current preview to notify some calculation is going on
729
729
  preview_plot = self._widget._mainWidget._previewPlot
730
- preview_plot.setWaiting(True)
730
+ preview_plot._waitingOverlay.show()
731
731
 
732
732
  # start sitching on a thread
733
733
  self._previewThread = PreviewThread(stitching_config=config)
@@ -749,7 +749,7 @@ class ZStitchingWindow(qt.QMainWindow):
749
749
  output_obj_identifier = sender.output_identifier
750
750
 
751
751
  preview_plot = self._widget._mainWidget._previewPlot
752
- preview_plot.setWaiting(False)
752
+ preview_plot._waitingOverlay.hide()
753
753
 
754
754
  self._previewThread.finished.disconnect(self._previewCalculationFinished)
755
755
  self._previewThread = None
@@ -14,14 +14,9 @@ from tomwer.core.volume.volumefactory import VolumeFactory
14
14
  from tomwer.gui import icons as tomwer_icons
15
15
  from tomwer.gui import settings
16
16
  from tomwer.gui.stitching.stitchandbackground import StitchAndBackgroundAlphaMixIn
17
- from silx.gui.plot import Plot2D, items
18
17
 
19
- try:
20
- from silx.gui.plot.ImageStack import ( # noqa F401
21
- PlotWithWaitingLabel as _PlotWithWaitingLabel,
22
- )
23
- except ImportError:
24
- from silx.gui.plot.ImageStack import _PlotWithWaitingLabel # noqa F401
18
+ from silx.gui.plot import Plot2D, items
19
+ from silx.gui.widgets.WaitingOverlay import WaitingOverlay
25
20
 
26
21
  _logger = logging.getLogger(__name__)
27
22
 
@@ -62,22 +57,23 @@ class _PreviewPlot2D(Plot2D):
62
57
  return "-" # No image picked
63
58
 
64
59
 
65
- class PreviewStitchingPlot(_PlotWithWaitingLabel, StitchAndBackgroundAlphaMixIn):
60
+ class PreviewStitchingPlot(Plot2D, StitchAndBackgroundAlphaMixIn):
66
61
  DEFAULT_STITCHED_IMG_ALPHA = 0.95
67
62
  DEFAULT_BACKGROUND_IMG_ALPHA = 0.20
68
63
 
69
64
  def __init__(self, parent=None) -> None:
70
65
  super().__init__(parent=parent) # pylint: disable=E1123
66
+ self._waitingOverlay = WaitingOverlay(self)
67
+ self._waitingOverlay.setIconSize(qt.QSize(30, 30))
71
68
  self._stitched_image = None
72
69
  self._composition_background = None
73
70
 
74
71
  # replace the simple Plot2D by a `_PreviewPlot2D` (to filter overlay image value to be displayed)
75
- self.layout().removeWidget(self._plot)
76
72
  self._plot = _PreviewPlot2D(parent=self)
77
73
  self.layout().addWidget(self._plot)
78
74
 
79
75
  # tune plot
80
- self.getPlotWidget().setYAxisInverted(settings.Y_AXIS_DOWNWARD)
76
+ self.setYAxisInverted(settings.Y_AXIS_DOWNWARD)
81
77
  # by default we want to have a full screen display
82
78
  self.setAxesDisplayed(False)
83
79
 
@@ -110,7 +106,7 @@ class PreviewStitchingPlot(_PlotWithWaitingLabel, StitchAndBackgroundAlphaMixIn)
110
106
  # set up
111
107
  self.setAlphaBackgroundImg(value=self.DEFAULT_BACKGROUND_IMG_ALPHA)
112
108
  self.setAlphaStitchedImg(value=self.DEFAULT_STITCHED_IMG_ALPHA)
113
- self.setWaiting(False)
109
+ self._waitingOverlay.hide()
114
110
 
115
111
  # connect signal / slot
116
112
  self._backGroundAction.toggled.connect(self._update)
@@ -249,48 +245,6 @@ class PreviewStitchingPlot(_PlotWithWaitingLabel, StitchAndBackgroundAlphaMixIn)
249
245
  def stitched_image(self):
250
246
  return self._stitched_image
251
247
 
252
- # expose API
253
- def getImage(self, *args, **kwargs):
254
- return self.getPlotWidget().getImage(*args, **kwargs)
255
-
256
- def addImage(self, *args, **kwargs):
257
- self.getPlotWidget().addImage(*args, **kwargs)
258
-
259
- def removeImage(self, *args, **kwargs):
260
- self.getPlotWidget().removeImage(*args, **kwargs)
261
-
262
- def toolBar(self, *args, **kwargs):
263
- return self.getPlotWidget().toolBar(*args, **kwargs)
264
-
265
- def setKeepDataAspectRatio(self, *args, **kwargs):
266
- return self.getPlotWidget().setKeepDataAspectRatio(*args, **kwargs)
267
-
268
- def getColorBarWidget(self, *args, **kwargs):
269
- return self.getPlotWidget().getColorBarWidget(*args, **kwargs)
270
-
271
- def getMaskAction(self, *args, **kwargs):
272
- return self.getPlotWidget().getMaskAction(*args, **kwargs)
273
-
274
- def getCopyAction(self, *args, **kwargs):
275
- return self.getPlotWidget().getCopyAction(*args, **kwargs)
276
-
277
- def addToolBar(self, *args, **kwargs):
278
- return self.getPlotWidget().addToolBar(*args, **kwargs)
279
-
280
- def setActiveImage(self, *args, **kwargs):
281
- return self.getPlotWidget().setActiveImage(*args, **kwargs)
282
-
283
- def setAxesDisplayed(self, *args, **kwargs):
284
- plotWidget = self.getPlotWidget()
285
- if hasattr(plotWidget, "setAxesDisplayed"):
286
- plotWidget.setAxesDisplayed(*args, **kwargs)
287
-
288
- def getDefaultColormap(self, *args, **kwargs):
289
- return self.getPlotWidget().getDefaultColormap()
290
-
291
- def setDefaultColormap(self, *args, **kwargs):
292
- return self.getPlotWidget().setDefaultColormap(*args, **kwargs)
293
-
294
248
  def setPixelSize(self, pixel_size: Union[tuple, float]):
295
249
  """set the pixel size to be used by the ruler"""
296
250
  self._tapeMeasureButton.setPixelSize(pixel_size_m=pixel_size)
@@ -189,9 +189,9 @@ class RawStitchingPlot(PlotWindow):
189
189
 
190
190
  self._alphaValuesWidget.addTomoObj(tomo_obj)
191
191
  if isinstance(tomo_obj, TomwerScanBase):
192
- self._scan_reading_order[
193
- tomo_obj.get_identifier().to_str()
194
- ] = self.getRotationAngleDirection(tomo_obj)
192
+ self._scan_reading_order[tomo_obj.get_identifier().to_str()] = (
193
+ self.getRotationAngleDirection(tomo_obj)
194
+ )
195
195
  if first_tomo_obj_id != tuple(self._tomo_objs.keys())[0]:
196
196
  # if the order of scans might have change we need to update the full stack (to handle reading order)
197
197
  self._updateImages()
@@ -360,9 +360,9 @@ class NXTomomillOutputDirSelector(qt.QWidget):
360
360
  self._manualRB.setChecked(True)
361
361
  else:
362
362
  if default_output is ProcessDataOutputDirMode.IN_SCAN_FOLDER:
363
- self._processedDataFolderRB.setChecked(True)
364
- elif default_output is ProcessDataOutputDirMode.PROCESSED_DATA_FOLDER:
365
363
  self._inScanFolder.setChecked(True)
364
+ elif default_output is ProcessDataOutputDirMode.PROCESSED_DATA_FOLDER:
365
+ self._processedDataFolderRB.setChecked(True)
366
366
  elif default_output is ProcessDataOutputDirMode.RAW_DATA_FOLDER:
367
367
  self._rawDataFolderRB.setChecked(True)
368
368
  else:
@@ -524,6 +524,11 @@ class OutputVolumeDefinition(qt.QWidget):
524
524
  os.environ["TOMWER_DEFAULT_INPUT_DIR"]
525
525
  ):
526
526
  dialog.setDirectory(os.environ["TOMWER_DEFAULT_INPUT_DIR"])
527
+ elif dialog.directory() != os.getcwd() or str(dialog.directory()).startswith(
528
+ "/data"
529
+ ):
530
+ # if the directory as already been set by the user. Avoid redefining it
531
+ pass
527
532
  elif os.path.isdir("/data"):
528
533
  dialog.setDirectory("/data")
529
534
 
@@ -540,6 +545,11 @@ class OutputVolumeDefinition(qt.QWidget):
540
545
  os.environ["TOMWER_DEFAULT_INPUT_DIR"]
541
546
  ):
542
547
  dialog.setDirectory(os.environ["TOMWER_DEFAULT_INPUT_DIR"])
548
+ elif dialog.directory() != os.getcwd() or str(dialog.directory()).startswith(
549
+ "/data"
550
+ ):
551
+ # if the directory as already been set by the user. Avoid redefining it
552
+ pass
543
553
  elif os.path.isdir("/data"):
544
554
  dialog.setDirectory("/data")
545
555
 
@@ -219,7 +219,7 @@ class QLineSelector(qt.QWidget):
219
219
  """
220
220
  legend = self._getLegend(row_n=row)
221
221
  if legend in self.__selection:
222
- self._plot.removeItem(legend)
222
+ self._plot.remove(legend=legend, kind="item")
223
223
  del self.__selection[legend]
224
224
 
225
225
  def _plotDrawEvent(self, event):