tomwer 1.2.9__py3-none-any.whl → 1.3.0a0__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 (253) hide show
  1. orangecontrib/tomwer/tutorials/icat_publication.ows +58 -0
  2. orangecontrib/tomwer/widgets/__init__.py +1 -0
  3. orangecontrib/tomwer/widgets/control/DataDiscoveryOW.py +2 -2
  4. orangecontrib/tomwer/widgets/control/DataListOW.py +9 -7
  5. orangecontrib/tomwer/widgets/control/DataSelectorOW.py +21 -10
  6. orangecontrib/tomwer/widgets/control/EDF2NXTomomillOW.py +11 -5
  7. orangecontrib/tomwer/widgets/control/EmailOW.py +4 -4
  8. orangecontrib/tomwer/widgets/control/NXTomomillOW.py +31 -18
  9. orangecontrib/tomwer/widgets/control/NXtomoConcatenate.py +14 -7
  10. orangecontrib/tomwer/widgets/control/NotifierOW.py +1 -0
  11. orangecontrib/tomwer/widgets/control/VolumeSelector.py +7 -4
  12. orangecontrib/tomwer/widgets/control/VolumeSymLinkOW.py +182 -182
  13. orangecontrib/tomwer/widgets/debugtools/DatasetGeneratorOW.py +4 -4
  14. orangecontrib/tomwer/widgets/edit/DarkFlatPatchOW.py +4 -4
  15. orangecontrib/tomwer/widgets/edit/ImageKeyEditorOW.py +3 -3
  16. orangecontrib/tomwer/widgets/edit/ImageKeyUpgraderOW.py +2 -0
  17. orangecontrib/tomwer/widgets/edit/NXtomoEditorOW.py +3 -3
  18. orangecontrib/tomwer/widgets/edit/test/test_nxtomo_editor.py +3 -3
  19. orangecontrib/tomwer/widgets/icat/PublishProcessedDataOW.py +115 -0
  20. orangecontrib/tomwer/widgets/icat/RawDataScreenshotCreatorOW.py +98 -0
  21. orangecontrib/tomwer/widgets/icat/SaveToGalleryAndPublishOW.py +129 -0
  22. orangecontrib/tomwer/widgets/icat/__init__.py +13 -0
  23. orangecontrib/tomwer/widgets/icat/icons/add_gallery.png +0 -0
  24. orangecontrib/tomwer/widgets/icat/icons/add_gallery.svg +82 -0
  25. orangecontrib/tomwer/widgets/icat/icons/publish_processed_data.png +0 -0
  26. orangecontrib/tomwer/widgets/icat/icons/publish_processed_data.svg +95 -0
  27. orangecontrib/tomwer/widgets/icat/icons/raw_screenshots.png +0 -0
  28. orangecontrib/tomwer/widgets/icat/icons/raw_screenshots.svg +143 -0
  29. orangecontrib/tomwer/widgets/icons/tomwer_data_portal.png +0 -0
  30. orangecontrib/tomwer/widgets/icons/tomwer_data_portal.svg +76 -0
  31. orangecontrib/tomwer/widgets/reconstruction/AxisOW.py +9 -8
  32. orangecontrib/tomwer/widgets/reconstruction/CastNabuVolumeOW.py +3 -3
  33. orangecontrib/tomwer/widgets/reconstruction/NabuHelicalPrepareWeightsDoubleOW.py +179 -169
  34. orangecontrib/tomwer/widgets/reconstruction/NabuOW.py +23 -0
  35. orangecontrib/tomwer/widgets/reconstruction/NabuVolumeOW.py +39 -5
  36. orangecontrib/tomwer/widgets/reconstruction/SAAxisOW.py +7 -13
  37. orangecontrib/tomwer/widgets/reconstruction/SADeltaBetaOW.py +7 -17
  38. orangecontrib/tomwer/widgets/reconstruction/SinoNormOW.py +3 -4
  39. orangecontrib/tomwer/widgets/visualization/LivesliceOW.py +1 -1
  40. orangecontrib/tomwer/widgets/visualization/NXtomoMetadataViewerOW.py +3 -3
  41. orangecontrib/tomwer/widgets/visualization/VolumeViewerOW.py +3 -29
  42. tomwer/__main__.py +11 -58
  43. tomwer/app/canvas.py +8 -0
  44. tomwer/app/canvas_launcher/config.py +13 -11
  45. tomwer/app/darkref.py +1 -1
  46. tomwer/app/darkrefpatch.py +1 -1
  47. tomwer/app/imagekeyeditor.py +5 -5
  48. tomwer/app/imagekeyupgrader.py +5 -5
  49. tomwer/app/intensitynormalization.py +2 -2
  50. tomwer/app/radiostack.py +2 -2
  51. tomwer/app/zstitching.py +74 -3
  52. tomwer/core/cluster/cluster.py +26 -0
  53. tomwer/core/log/logger.py +7 -5
  54. tomwer/core/process/conditions/filters.py +1 -1
  55. tomwer/core/process/control/datalistener/datalistener.py +3 -3
  56. tomwer/core/process/control/nxtomoconcatenate.py +13 -13
  57. tomwer/core/process/control/nxtomomill.py +83 -25
  58. tomwer/core/process/control/scantransfer.py +11 -10
  59. tomwer/core/process/control/scanvalidator.py +3 -2
  60. tomwer/core/process/control/test/test_concatenate_nxtomos.py +9 -9
  61. tomwer/core/process/control/test/test_email.py +4 -4
  62. tomwer/core/process/control/test/test_h52nx_process.py +59 -7
  63. tomwer/core/process/control/test/test_volume_link.py +64 -64
  64. tomwer/core/process/control/timer.py +1 -1
  65. tomwer/core/process/control/volumesymlink.py +200 -200
  66. tomwer/core/process/edit/darkflatpatch.py +6 -6
  67. tomwer/core/process/edit/imagekeyeditor.py +17 -18
  68. tomwer/core/process/icat/__init__.py +0 -0
  69. tomwer/core/process/icat/createscreenshots.py +100 -0
  70. tomwer/core/process/icat/gallery.py +377 -0
  71. tomwer/core/process/icat/icatbase.py +36 -0
  72. tomwer/core/process/icat/publish.py +228 -0
  73. tomwer/core/process/icat/screenshots.py +26 -0
  74. tomwer/core/process/output.py +52 -0
  75. tomwer/core/process/reconstruction/axis/axis.py +17 -10
  76. tomwer/core/process/reconstruction/axis/mode.py +4 -0
  77. tomwer/core/process/reconstruction/axis/params.py +9 -4
  78. tomwer/core/process/reconstruction/darkref/darkrefs.py +8 -6
  79. tomwer/core/process/reconstruction/darkref/darkrefscopy.py +1 -1
  80. tomwer/core/process/reconstruction/darkref/params.py +1 -1
  81. tomwer/core/process/reconstruction/lamino/tofu.py +4 -4
  82. tomwer/core/process/reconstruction/nabu/castvolume.py +1 -1
  83. tomwer/core/process/reconstruction/nabu/helical.py +9 -5
  84. tomwer/core/process/reconstruction/nabu/nabucommon.py +32 -62
  85. tomwer/core/process/reconstruction/nabu/nabuscores.py +387 -61
  86. tomwer/core/process/reconstruction/nabu/nabuslices.py +33 -21
  87. tomwer/core/process/reconstruction/nabu/nabuvolume.py +37 -14
  88. tomwer/core/process/reconstruction/nabu/settings.py +2 -2
  89. tomwer/core/process/reconstruction/nabu/utils.py +129 -24
  90. tomwer/core/process/reconstruction/output.py +108 -0
  91. tomwer/core/process/reconstruction/saaxis/saaxis.py +233 -263
  92. tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +140 -86
  93. tomwer/core/process/reconstruction/scores/params.py +4 -1
  94. tomwer/core/process/reconstruction/scores/scores.py +13 -0
  95. tomwer/core/process/reconstruction/test/test_axis_params.py +2 -2
  96. tomwer/core/process/reconstruction/test/test_darkref.py +3 -3
  97. tomwer/core/process/reconstruction/test/test_darkref_copy.py +3 -3
  98. tomwer/core/process/reconstruction/test/test_saaxis.py +3 -4
  99. tomwer/core/process/reconstruction/test/test_sadeltabeta.py +2 -2
  100. tomwer/core/process/stitching/nabustitcher.py +2 -2
  101. tomwer/core/process/test/test_axis.py +6 -6
  102. tomwer/core/process/test/test_dark_and_flat.py +10 -7
  103. tomwer/core/process/test/test_data_transfer.py +7 -6
  104. tomwer/core/process/test/test_nabu.py +4 -4
  105. tomwer/core/process/test/test_normalization.py +2 -2
  106. tomwer/core/scan/edfscan.py +4 -1
  107. tomwer/core/scan/hdf5scan.py +19 -500
  108. tomwer/core/scan/nxtomoscan.py +532 -0
  109. tomwer/core/scan/scanbase.py +42 -20
  110. tomwer/core/scan/scanfactory.py +13 -13
  111. tomwer/core/scan/test/test_future_scan.py +2 -2
  112. tomwer/core/scan/test/test_h5.py +12 -10
  113. tomwer/core/scan/test/test_process_registration.py +2 -2
  114. tomwer/core/scan/test/test_scan.py +4 -3
  115. tomwer/core/settings.py +20 -0
  116. tomwer/core/test/test_scanutils.py +8 -7
  117. tomwer/core/test/test_utils.py +33 -26
  118. tomwer/core/utils/__init__.py +0 -466
  119. tomwer/core/utils/deprecation.py +1 -1
  120. tomwer/core/utils/dictutils.py +14 -0
  121. tomwer/core/utils/lbsram.py +35 -0
  122. tomwer/core/utils/nxtomoutils.py +1 -1
  123. tomwer/core/utils/scanutils.py +6 -6
  124. tomwer/core/utils/spec.py +263 -0
  125. tomwer/core/volume/volumefactory.py +2 -2
  126. tomwer/gui/cluster/slurm.py +260 -60
  127. tomwer/gui/cluster/test/test_cluster.py +13 -0
  128. tomwer/gui/cluster/test/test_supervisor.py +2 -2
  129. tomwer/gui/configuration/__init__.py +0 -0
  130. tomwer/gui/{reconstruction/nabu → configuration}/action.py +1 -32
  131. tomwer/gui/configuration/level.py +22 -0
  132. tomwer/gui/control/actions.py +54 -0
  133. tomwer/gui/control/datalist.py +78 -16
  134. tomwer/gui/control/datalistener.py +4 -16
  135. tomwer/gui/control/{email.py → emailnotifier.py} +9 -18
  136. tomwer/gui/control/history.py +2 -2
  137. tomwer/gui/control/observations.py +2 -2
  138. tomwer/gui/control/reducedarkflatselector.py +1 -1
  139. tomwer/gui/control/selectorwidgetbase.py +36 -9
  140. tomwer/gui/control/serie/seriecreator.py +5 -22
  141. tomwer/gui/control/test/test_email.py +1 -1
  142. tomwer/gui/control/test/test_scanvalidator.py +6 -5
  143. tomwer/gui/control/test/test_single_tomo_obj.py +2 -2
  144. tomwer/gui/control/tomoobjdisplaymode.py +8 -0
  145. tomwer/gui/debugtools/datasetgenerator.py +3 -3
  146. tomwer/gui/edit/dkrfpatch.py +16 -22
  147. tomwer/gui/edit/imagekeyeditor.py +8 -11
  148. tomwer/gui/edit/nxtomoeditor.py +111 -44
  149. tomwer/gui/edit/nxtomowarmer.py +4 -4
  150. tomwer/gui/edit/test/test_dkrf_patch.py +7 -7
  151. tomwer/gui/edit/test/test_image_key_editor.py +3 -3
  152. tomwer/gui/edit/test/test_nx_editor.py +40 -16
  153. tomwer/gui/icat/__init__.py +0 -0
  154. tomwer/gui/icat/createscreenshots.py +80 -0
  155. tomwer/gui/icat/gallery.py +214 -0
  156. tomwer/gui/icat/publish.py +187 -0
  157. tomwer/gui/reconstruction/axis/axis.py +171 -57
  158. tomwer/gui/reconstruction/axis/radioaxis.py +80 -95
  159. tomwer/gui/reconstruction/darkref/darkrefcopywidget.py +3 -2
  160. tomwer/gui/reconstruction/lamino/tofu/projections.py +1 -1
  161. tomwer/gui/reconstruction/lamino/tofu/tofuoutput.py +3 -6
  162. tomwer/gui/reconstruction/nabu/castvolume.py +1 -1
  163. tomwer/gui/reconstruction/nabu/check.py +9 -9
  164. tomwer/gui/reconstruction/nabu/helical.py +29 -12
  165. tomwer/gui/reconstruction/nabu/nabuconfig/base.py +2 -4
  166. tomwer/gui/reconstruction/nabu/nabuconfig/output.py +110 -33
  167. tomwer/gui/reconstruction/nabu/nabuconfig/phase.py +9 -12
  168. tomwer/gui/reconstruction/nabu/nabuconfig/preprocessing.py +219 -29
  169. tomwer/gui/reconstruction/nabu/nabuconfig/reconstruction.py +3 -6
  170. tomwer/gui/reconstruction/nabu/nabuflow.py +12 -20
  171. tomwer/gui/reconstruction/nabu/slices.py +6 -7
  172. tomwer/gui/reconstruction/nabu/volume.py +22 -10
  173. tomwer/gui/reconstruction/normalization/intensity.py +15 -23
  174. tomwer/gui/reconstruction/saaxis/corrangeselector.py +7 -23
  175. tomwer/gui/reconstruction/saaxis/dimensionwidget.py +1 -1
  176. tomwer/gui/reconstruction/saaxis/saaxis.py +7 -9
  177. tomwer/gui/reconstruction/sadeltabeta/saadeltabeta.py +2 -1
  178. tomwer/gui/reconstruction/scores/control.py +2 -9
  179. tomwer/gui/reconstruction/scores/scoreplot.py +11 -5
  180. tomwer/gui/reconstruction/test/test_axis.py +23 -12
  181. tomwer/gui/reconstruction/test/test_lamino.py +8 -3
  182. tomwer/gui/reconstruction/test/test_nabu.py +28 -9
  183. tomwer/gui/reconstruction/test/test_saaxis.py +3 -3
  184. tomwer/gui/reconstruction/test/test_sadeltabeta.py +2 -2
  185. tomwer/gui/settings.py +5 -28
  186. tomwer/gui/stackplot.py +2 -5
  187. tomwer/gui/stitching/action.py +49 -0
  188. tomwer/gui/stitching/config/axisparams.py +7 -24
  189. tomwer/gui/stitching/config/output.py +10 -8
  190. tomwer/gui/stitching/config/positionoveraxis.py +22 -23
  191. tomwer/gui/stitching/normalization.py +117 -0
  192. tomwer/gui/stitching/stitchandbackground.py +4 -6
  193. tomwer/gui/stitching/stitching.py +265 -43
  194. tomwer/gui/stitching/stitching_preview.py +62 -5
  195. tomwer/gui/stitching/stitching_raw.py +2 -5
  196. tomwer/gui/stitching/z_stitching/fineestimation.py +0 -60
  197. tomwer/gui/utils/buttons.py +112 -29
  198. tomwer/gui/utils/inputwidget.py +33 -25
  199. tomwer/gui/utils/scandescription.py +4 -0
  200. tomwer/gui/utils/step.py +144 -0
  201. tomwer/gui/utils/unitsystem.py +2 -5
  202. tomwer/gui/utils/vignettes.py +176 -15
  203. tomwer/gui/visualization/dataviewer.py +1 -4
  204. tomwer/gui/visualization/diffviewer/diffviewer.py +7 -16
  205. tomwer/gui/visualization/diffviewer/shiftwidget.py +2 -5
  206. tomwer/gui/visualization/scanoverview.py +1 -1
  207. tomwer/gui/visualization/sinogramviewer.py +1 -10
  208. tomwer/gui/visualization/test/test_diffviewer.py +3 -3
  209. tomwer/gui/visualization/test/test_nx_tomo_metadata_viewer.py +4 -4
  210. tomwer/gui/visualization/test/test_sinogramviewer.py +2 -2
  211. tomwer/gui/visualization/test/test_stacks.py +3 -3
  212. tomwer/gui/visualization/test/test_volumeviewer.py +2 -2
  213. tomwer/io/utils/raw_and_processed_data.py +84 -0
  214. tomwer/io/utils/tomoobj.py +4 -6
  215. tomwer/resources/gui/icons/ruler.png +0 -0
  216. tomwer/resources/gui/icons/ruler.svg +273 -0
  217. tomwer/resources/gui/icons/short_description.png +0 -0
  218. tomwer/resources/gui/icons/short_description.svg +58 -0
  219. tomwer/resources/gui/icons/url.png +0 -0
  220. tomwer/resources/gui/icons/url.svg +58 -0
  221. tomwer/synctools/stacks/edit/darkflatpatch.py +2 -2
  222. tomwer/synctools/stacks/edit/imagekeyeditor.py +2 -2
  223. tomwer/synctools/stacks/reconstruction/axis.py +4 -4
  224. tomwer/synctools/stacks/reconstruction/castvolume.py +2 -2
  225. tomwer/synctools/stacks/reconstruction/dkrefcopy.py +4 -10
  226. tomwer/synctools/stacks/reconstruction/nabu.py +2 -2
  227. tomwer/synctools/stacks/reconstruction/normalization.py +2 -2
  228. tomwer/synctools/stacks/reconstruction/saaxis.py +2 -2
  229. tomwer/synctools/stacks/reconstruction/sadeltabeta.py +2 -2
  230. tomwer/synctools/test/test_darkRefs.py +7 -58
  231. tomwer/synctools/test/test_foldertransfer.py +6 -6
  232. tomwer/synctools/utils/scanstages.py +6 -6
  233. tomwer/tests/conftest.py +34 -0
  234. tomwer/tests/datasets.py +13 -0
  235. tomwer/tests/test_scripts.py +92 -39
  236. tomwer/tests/utils.py +5 -0
  237. tomwer/version.py +3 -3
  238. {tomwer-1.2.9.dist-info → tomwer-1.3.0a0.dist-info}/METADATA +39 -39
  239. {tomwer-1.2.9.dist-info → tomwer-1.3.0a0.dist-info}/RECORD +248 -209
  240. tomwer/resources/gui/icons/esrf_1.svg +0 -307
  241. tomwer/resources/gui/icons/triangle.svg +0 -80
  242. tomwer/synctools/test/test_scanstages.py +0 -162
  243. tomwer/tests/utils/__init__.py +0 -247
  244. tomwer/tests/utils/utilstest.py +0 -220
  245. /tomwer/app/{saaxis.py → multicor.py} +0 -0
  246. /tomwer/app/{sadeltabeta.py → multipag.py} +0 -0
  247. /tomwer/core/process/control/{email.py → emailnotifier.py} +0 -0
  248. /tomwer-1.2.9-py3.11-nspkg.pth → /tomwer-1.3.0a0-py3.11-nspkg.pth +0 -0
  249. {tomwer-1.2.9.dist-info → tomwer-1.3.0a0.dist-info}/LICENSE +0 -0
  250. {tomwer-1.2.9.dist-info → tomwer-1.3.0a0.dist-info}/WHEEL +0 -0
  251. {tomwer-1.2.9.dist-info → tomwer-1.3.0a0.dist-info}/entry_points.txt +0 -0
  252. {tomwer-1.2.9.dist-info → tomwer-1.3.0a0.dist-info}/namespace_packages.txt +0 -0
  253. {tomwer-1.2.9.dist-info → tomwer-1.3.0a0.dist-info}/top_level.txt +0 -0
@@ -37,7 +37,8 @@ from silx.gui import qt
37
37
 
38
38
  from tomwer.core import settings
39
39
  from tomwer.gui.reconstruction.lamino.tofu import TofuWindow
40
- from tomwer.tests.utils import UtilsTest, skip_gui_test
40
+ from tomwer.tests.datasets import TomwerCIDatasets
41
+ from tomwer.tests.utils import skip_gui_test
41
42
 
42
43
 
43
44
  @pytest.mark.skipif(skip_gui_test(), reason="skip gui test")
@@ -59,7 +60,9 @@ class TestLamino(unittest.TestCase):
59
60
 
60
61
  def testSetup(self):
61
62
  """Make sure the widget is correctly setting parameters from a scan"""
62
- dataset = UtilsTest.getEDFDataset("test01")
63
+ dataset = TomwerCIDatasets.get_dataset(
64
+ "edf_datasets/test01",
65
+ )
63
66
  self._window.loadFromScan(dataset)
64
67
  reconsParams = self._widget.getParameters()
65
68
  # check general information
@@ -101,7 +104,9 @@ class TestLamino(unittest.TestCase):
101
104
  outputWidget.setOutput("toto")
102
105
  outputWidget.lockOutput()
103
106
 
104
- dataset = UtilsTest.getEDFDataset("test01")
107
+ dataset = TomwerCIDatasets.get_dataset(
108
+ "edf_datasets/test01",
109
+ )
105
110
  self._window.loadFromScan(dataset)
106
111
 
107
112
  self.assertTrue(inputWidget.rotationAngle._overallAngle.getAngle() == 12.0)
@@ -37,7 +37,7 @@ from tomwer.gui.reconstruction.nabu.nabuconfig.output import _NabuOutputConfig
37
37
  from tomwer.gui.reconstruction.nabu.nabuconfig.phase import _NabuPhaseConfig
38
38
  from tomwer.gui.reconstruction.nabu.nabuconfig.preprocessing import (
39
39
  _NabuPreProcessingConfig,
40
- _RingCorrectionMethod,
40
+ RingCorrectionMethod,
41
41
  )
42
42
  from tomwer.gui.reconstruction.nabu.nabuconfig.reconstruction import (
43
43
  _NabuReconstructionConfig,
@@ -45,6 +45,7 @@ from tomwer.gui.reconstruction.nabu.nabuconfig.reconstruction import (
45
45
  from tomwer.gui.reconstruction.nabu.nabuflow import NabuFlowControl
46
46
  from tomwer.gui.reconstruction.nabu.volume import NabuVolumeWidget
47
47
  from tomwer.tests.utils import skip_gui_test
48
+ from tomwer.core.process.output import ProcessDataOutputDirMode
48
49
 
49
50
 
50
51
  class ProcessClass:
@@ -119,8 +120,8 @@ class TestNabuPreProcConfig(TestCaseQt):
119
120
  "log_max_clip": 10.0,
120
121
  "take_logarithm": True,
121
122
  "normalize_srcurrent": 0,
122
- "sino_rings_correction": _RingCorrectionMethod.NONE.value,
123
- "sino_rings_options": "sigma=1.0 ; levels=10",
123
+ "sino_rings_correction": RingCorrectionMethod.NONE.value,
124
+ "sino_rings_options": "sigma=1.0 ; levels=10 ; padding=False",
124
125
  "tilt_correction": "",
125
126
  "autotilt_options": "",
126
127
  }
@@ -138,8 +139,8 @@ class TestNabuPreProcConfig(TestCaseQt):
138
139
  "log_max_clip": 250.0,
139
140
  "take_logarithm": False,
140
141
  "normalize_srcurrent": 1,
141
- "sino_rings_correction": _RingCorrectionMethod.MUNCH.value,
142
- "sino_rings_options": "sigma=1.4 ; levels=11",
142
+ "sino_rings_correction": RingCorrectionMethod.MUNCH.value,
143
+ "sino_rings_options": "sigma=1.4 ; levels=11 ; padding=True",
143
144
  "tilt_correction": "1d-correlation",
144
145
  "autotilt_options": "low_pass=1; high_pass=20",
145
146
  }
@@ -303,17 +304,25 @@ class TestNabuOutputConfig(TestCaseQt):
303
304
  self.qapp.processEvents()
304
305
 
305
306
  def testGetConfiguration(self):
306
- ini_conf = {"file_format": "hdf5", "location": ""}
307
+ ini_conf = {
308
+ "file_format": "hdf5",
309
+ "location": "",
310
+ "output_dir_mode": "same folder as scan",
311
+ }
307
312
  self.assertEqual(self.nabuWidget.getConfiguration(), ini_conf)
308
313
 
309
314
  def testSetConfiguration(self):
310
- conf = {"file_format": "tiff", "location": os.sep.join(("tmp", "my_output"))}
315
+ conf = {
316
+ "file_format": "tiff",
317
+ "location": os.sep.join(("tmp", "my_output")),
318
+ "output_dir_mode": "other",
319
+ }
311
320
  self.nabuWidget.setConfiguration(conf)
312
321
  self.nabuWidget.show()
313
322
  self.qapp.processEvents()
314
323
  # check some widget visibility
315
324
  self.assertTrue(self.nabuWidget._output_dir_widget._outputDirQLE.isVisible())
316
- self.assertFalse(self.nabuWidget._output_dir_widget._defaultOutput.isChecked())
325
+ self.assertTrue(self.nabuWidget._output_dir_widget._otherDirRB.isChecked())
317
326
 
318
327
  self.assertEqual(self.nabuWidget.getConfiguration(), conf)
319
328
 
@@ -323,6 +332,7 @@ class TestNabuVolumeWidget(TestCaseQt):
323
332
  def setUp(self):
324
333
  TestCaseQt.setUp(self)
325
334
  self.nabuWidget = NabuVolumeWidget(parent=None)
335
+ self.nabuWidget.setConfigurationLevel("advanced")
326
336
 
327
337
  def tearDown(self):
328
338
  self.nabuWidget.setAttribute(qt.Qt.WA_DeleteOnClose)
@@ -334,6 +344,8 @@ class TestNabuVolumeWidget(TestCaseQt):
334
344
  "start_z": 0,
335
345
  "end_z": -1,
336
346
  "gpu_mem_fraction": 0.9,
347
+ "output_dir_mode": ProcessDataOutputDirMode.IN_SCAN_FOLDER.value,
348
+ "overwrite_output_location": False,
337
349
  "postproc": {"output_histogram": 1},
338
350
  "cpu_mem_fraction": 0.9,
339
351
  "use_phase_margin": True,
@@ -354,6 +366,13 @@ class TestNabuVolumeWidget(TestCaseQt):
354
366
  "new_output_location": "/new/location",
355
367
  }
356
368
  self.nabuWidget.setConfiguration(conf)
357
- self.nabuWidget.show()
358
369
  self.qapp.processEvents()
370
+
371
+ # update the config dict has setting an other custom output directory update some items
372
+ conf.update(
373
+ {
374
+ "overwrite_output_location": True,
375
+ "output_dir_mode": ProcessDataOutputDirMode.OTHER.value,
376
+ }
377
+ )
359
378
  self.assertEqual(self.nabuWidget.getConfiguration(), conf)
@@ -37,7 +37,7 @@ import pytest
37
37
  from silx.gui import qt
38
38
  from silx.gui.utils.testutils import TestCaseQt
39
39
  from silx.io.url import DataUrl
40
- from tomoscan.unitsystem import metricsystem
40
+ from pyunitsystem import metricsystem
41
41
 
42
42
  from tomwer.core.process.reconstruction.saaxis.params import (
43
43
  ReconstructionMode,
@@ -45,7 +45,7 @@ from tomwer.core.process.reconstruction.saaxis.params import (
45
45
  )
46
46
  from tomwer.core.process.reconstruction.scores import ComputedScore
47
47
  from tomwer.core.process.reconstruction.scores.params import ScoreMethod
48
- from tomwer.core.utils.scanutils import MockHDF5
48
+ from tomwer.core.utils.scanutils import MockNXtomo
49
49
  from tomwer.gui.reconstruction.saaxis.dimensionwidget import DimensionWidget
50
50
  from tomwer.gui.reconstruction.saaxis.saaxis import SAAxisWindow
51
51
  from tomwer.tests.utils import skip_gui_test
@@ -144,7 +144,7 @@ class TestSAAxisWindow(TestCaseQt):
144
144
  # create a scan
145
145
  self.folder = tempfile.mkdtemp()
146
146
  dim = 10
147
- mock = MockHDF5(
147
+ mock = MockNXtomo(
148
148
  scan_path=self.folder, n_proj=10, n_ini_proj=10, scan_range=180, dim=dim
149
149
  )
150
150
  mock.add_alignment_radio(index=10, angle=90)
@@ -41,7 +41,7 @@ from silx.io.url import DataUrl
41
41
  from tomwer.core.process.reconstruction.sadeltabeta.params import SADeltaBetaParams
42
42
  from tomwer.core.process.reconstruction.scores import ComputedScore
43
43
  from tomwer.core.process.reconstruction.scores.params import ScoreMethod
44
- from tomwer.core.utils.scanutils import MockHDF5
44
+ from tomwer.core.utils.scanutils import MockNXtomo
45
45
  from tomwer.gui.reconstruction.sadeltabeta import SADeltaBetaWindow
46
46
  from tomwer.tests.utils import skip_gui_test
47
47
 
@@ -75,7 +75,7 @@ class TestSADeltaBetaWindow(TestCaseQt):
75
75
  # create a scan
76
76
  self.folder = tempfile.mkdtemp()
77
77
  dim = 10
78
- mock = MockHDF5(
78
+ mock = MockNXtomo(
79
79
  scan_path=self.folder, n_proj=10, n_ini_proj=10, scan_range=180, dim=dim
80
80
  )
81
81
  mock.add_alignment_radio(index=10, angle=90)
tomwer/gui/settings.py CHANGED
@@ -1,31 +1,8 @@
1
- # coding: utf-8
2
- # /*##########################################################################
3
- #
4
- # Copyright (c) 2016-2017 European Synchrotron Radiation Facility
5
- #
6
- # Permission is hereby granted, free of charge, to any person obtaining a copy
7
- # of this software and associated documentation files (the "Software"), to deal
8
- # in the Software without restriction, including without limitation the rights
9
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
- # copies of the Software, and to permit persons to whom the Software is
11
- # furnished to do so, subject to the following conditions:
12
- #
13
- # The above copyright notice and this permission notice shall be included in
14
- # all copies or substantial portions of the Software.
15
- #
16
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
- # THE SOFTWARE.
23
- #
24
- # ###########################################################################*/
25
-
26
- __authors__ = ["H. Payno"]
27
- __license__ = "MIT"
28
- __date__ = "05/11/2018"
1
+ from silx.gui import qt
29
2
 
30
3
 
31
4
  Y_AXIS_DOWNWARD = True
5
+ """Default axis direction Y"""
6
+
7
+ EDITING_BACKGROUND_COLOR = qt.QColor("#c3d0d6")
8
+ """Background color used to notify the user that application waits end of edition before taking it into account"""
tomwer/gui/stackplot.py CHANGED
@@ -555,7 +555,7 @@ class _StackImageToLoad(_StackImage, qt.QObject):
555
555
 
556
556
  def clear(self):
557
557
  for img in self._images.values():
558
- img.sigLoaded.disconnect(self._loaded)
558
+ img.sigLoaded.disconnect(self.sigImageLoaded)
559
559
  _StackImage.clear(self)
560
560
  self._url_to_index.clear()
561
561
 
@@ -568,7 +568,7 @@ class _StackImageToLoad(_StackImage, qt.QObject):
568
568
  raise TypeError(f"Unmanaged type: {type(image)}")
569
569
  self._url_to_index[image_.url.path()] = self.nextIndex
570
570
  _StackImage.addImage(self, image_)
571
- image_.sigLoaded.connect(self._loaded)
571
+ image_.sigLoaded.connect(self.sigImageLoaded)
572
572
  if self._mode == ASAP_LOADING:
573
573
  image_.load(self._force_sync)
574
574
 
@@ -615,9 +615,6 @@ class _StackImageToLoad(_StackImage, qt.QObject):
615
615
  except Exception as e:
616
616
  logger.error(e)
617
617
 
618
- def _loaded(self, url_path):
619
- self.sigImageLoaded.emit(url_path)
620
-
621
618
  def setForceSync(self, value):
622
619
  self._force_sync = value
623
620
 
@@ -0,0 +1,49 @@
1
+ from silx.gui import qt
2
+ from silx.gui import icons as silx_icons
3
+ from tomwer.gui import icons as tomwer_icons
4
+
5
+
6
+ class LoadConfigurationAction(qt.QAction):
7
+ """Action to trigger load of a stitching configuration"""
8
+
9
+ def __init__(self, parent=None, text=None):
10
+ super().__init__(parent)
11
+ if text is not None:
12
+ self.setText(text)
13
+ self.setToolTip("load nabu-stitching configuration")
14
+ load_icon = silx_icons.getQIcon("document-open")
15
+ self.setIcon(load_icon)
16
+
17
+
18
+ class SaveConfigurationAction(qt.QAction):
19
+ """Action to trigger save of a stitching configuration"""
20
+
21
+ def __init__(self, parent=None, text=None):
22
+ super().__init__(parent)
23
+ if text is not None:
24
+ self.setText(text)
25
+ self.setToolTip("save nabu-stitching configuration")
26
+ save_icon = silx_icons.getQIcon("document-save")
27
+ self.setIcon(save_icon)
28
+
29
+
30
+ class AddTomoObjectAction(qt.QAction):
31
+ """Action to trigger add a volume to a stitching configuration"""
32
+
33
+ def __init__(self, parent=None, text=None):
34
+ super().__init__(parent)
35
+ if text is not None:
36
+ self.setText(text)
37
+ self.setToolTip(
38
+ "Add a NXtomo or a (nabu) reconstructed volume to the stitching"
39
+ )
40
+ add_icon = tomwer_icons.getQIcon("add")
41
+ self.setIcon(add_icon)
42
+
43
+
44
+ class PreviewAction(qt.QAction):
45
+ def __init__(self, parent=None):
46
+ super().__init__(parent)
47
+ self.setToolTip("Compute preview with current settings (shortcut: F5)")
48
+ update_preview_icon = tomwer_icons.getQIcon("update_stitching_preview")
49
+ self.setIcon(update_preview_icon)
@@ -2,11 +2,11 @@ import logging
2
2
  from typing import Union
3
3
 
4
4
  from nabu.stitching import config as stitching_config
5
- from nabu.stitching.utils import ScoreMethod
6
5
  from nabu.stitching.utils import ShiftAlgorithm as StitchShiftAlgorithm
7
6
  from silx.gui import qt
8
7
 
9
8
  from tomwer.gui.utils.qt_utils import block_signals
9
+ from tomwer.gui.configuration.level import ConfigurationLevel
10
10
 
11
11
  _logger = logging.getLogger(__name__)
12
12
 
@@ -34,7 +34,6 @@ class StitcherAxisParams(qt.QWidget):
34
34
  axis_0_shift_search_method = [
35
35
  StitchShiftAlgorithm.NABU_FFT,
36
36
  StitchShiftAlgorithm.SKIMAGE,
37
- StitchShiftAlgorithm.SHIFT_GRID,
38
37
  StitchShiftAlgorithm.ITK_IMG_REG_V4,
39
38
  StitchShiftAlgorithm.NONE,
40
39
  ]
@@ -54,13 +53,6 @@ class StitcherAxisParams(qt.QWidget):
54
53
  tooltip = "size of the window to try to refine shift"
55
54
  self._windowSizeLabel.setToolTip(tooltip)
56
55
  self._windowSizeSB.setToolTip(tooltip)
57
- # score method
58
- self._scoreMethodLabel = qt.QLabel("score method", self)
59
- self.layout().addWidget(self._scoreMethodLabel, 2, 0, 1, 1)
60
- self._scoreMethodCB = qt.QComboBox(self)
61
- for method in ScoreMethod:
62
- self._scoreMethodCB.addItem(method.value)
63
- self.layout().addWidget(self._scoreMethodCB, 2, 1, 1, 1)
64
56
 
65
57
  # filter options
66
58
  self._filteringGroup = _FilteringGroupBox("filter for shift search", self)
@@ -68,7 +60,7 @@ class StitcherAxisParams(qt.QWidget):
68
60
  self._filteringGroup.setChecked(False)
69
61
  self._filteringGroup.setLowPassValue(1)
70
62
  self._filteringGroup.setHighPassValue(20)
71
- self.layout().addWidget(self._filteringGroup, 3, 0, 2, 3)
63
+ self.layout().addWidget(self._filteringGroup, 2, 0, 2, 3)
72
64
 
73
65
  # set up
74
66
  self._methodChanged()
@@ -76,7 +68,6 @@ class StitcherAxisParams(qt.QWidget):
76
68
  # connect signal / slot
77
69
  self._shiftSearchMethodCB.currentIndexChanged.connect(self._methodChanged)
78
70
  self._windowSizeSB.valueChanged.connect(self._notifyConfigChanged)
79
- self._scoreMethodCB.currentIndexChanged.connect(self._notifyConfigChanged)
80
71
  self._filteringGroup.sigValueChanged.connect(self._notifyConfigChanged)
81
72
 
82
73
  @property
@@ -91,21 +82,12 @@ class StitcherAxisParams(qt.QWidget):
91
82
  idx = self._shiftSearchMethodCB.findText(method.value)
92
83
  self._shiftSearchMethodCB.setCurrentIndex(idx)
93
84
 
94
- def setScoreMethod(self, method: Union[ScoreMethod, str]) -> None:
95
- method = ScoreMethod.from_value(method)
96
- idx = self._scoreMethodCB.findText(method.value)
97
- self._scoreMethodCB.setCurrentIndex(idx)
98
-
99
85
  def getConfiguration(self) -> dict:
100
86
  method = self.getShiftSearchMethod()
101
87
  param_opts = [
102
88
  f"{stitching_config.KEY_IMG_REG_METHOD}={method.value}",
103
89
  f"{stitching_config.KEY_WINDOW_SIZE}={self._windowSizeSB.value()}",
104
90
  ]
105
- if method is StitchShiftAlgorithm.SHIFT_GRID:
106
- param_opts.append(
107
- f"{stitching_config.KEY_SCORE_METHOD}='{self._scoreMethodCB.currentText()}'"
108
- )
109
91
  if self._filteringGroup.isChecked():
110
92
  param_opts.append(
111
93
  f"{stitching_config.KEY_LOW_PASS_FILTER}='{self._filteringGroup.getLowPassValue()}'"
@@ -136,8 +118,6 @@ class StitcherAxisParams(qt.QWidget):
136
118
  self.setShiftSearchMethod(opt_value)
137
119
  elif opt_name == stitching_config.KEY_WINDOW_SIZE:
138
120
  self._windowSizeSB.setValue(int(opt_value))
139
- elif opt_name == stitching_config.KEY_SCORE_METHOD:
140
- self.setScoreMethod(opt_value)
141
121
  elif opt_name == stitching_config.KEY_LOW_PASS_FILTER:
142
122
  self._filteringGroup.setLowPassValue(int(opt_value))
143
123
  self._filteringGroup.setEnabled(True)
@@ -153,8 +133,6 @@ class StitcherAxisParams(qt.QWidget):
153
133
  def _methodChanged(self) -> None:
154
134
  method = self.getShiftSearchMethod()
155
135
  with block_signals(self):
156
- self._scoreMethodCB.setVisible(method is StitchShiftAlgorithm.SHIFT_GRID)
157
- self._scoreMethodLabel.setVisible(method is StitchShiftAlgorithm.SHIFT_GRID)
158
136
  self._windowSizeSB.setVisible(method is not StitchShiftAlgorithm.NONE)
159
137
  self._windowSizeLabel.setVisible(method is not StitchShiftAlgorithm.NONE)
160
138
  self._notifyConfigChanged()
@@ -162,6 +140,11 @@ class StitcherAxisParams(qt.QWidget):
162
140
  def _notifyConfigChanged(self, *args, **kwargs) -> None:
163
141
  self.sigConfigChanged.emit()
164
142
 
143
+ def setConfigurationLevel(self, level: ConfigurationLevel):
144
+ self._windowSizeLabel.setVisible(level >= ConfigurationLevel.OPTIONAL)
145
+ self._windowSizeSB.setVisible(level >= ConfigurationLevel.OPTIONAL)
146
+ self._filteringGroup.setVisible(level >= ConfigurationLevel.ADVANCED)
147
+
165
148
 
166
149
  class _FilteringGroupBox(qt.QGroupBox):
167
150
  sigValueChanged = qt.Signal()
@@ -5,9 +5,10 @@ from nabu.stitching.config import StitchingType
5
5
  from nxtomomill.io.utils import convert_str_to_bool
6
6
  from silx.gui import qt
7
7
 
8
- from tomwer.core.scan.hdf5scan import HDF5TomoScan, HDF5TomoScanIdentifier
8
+ from tomwer.core.scan.nxtomoscan import NXtomoScan, NXtomoScanIdentifier
9
9
  from tomwer.core.scan.scanfactory import ScanFactory
10
10
  from tomwer.gui.utils.inputwidget import OutputVolumeDefinition
11
+ from tomwer.gui.qlefilesystem import QLFileSystem
11
12
 
12
13
  _logger = logging.getLogger(__name__)
13
14
 
@@ -21,21 +22,21 @@ class _PreProcessingOutput(qt.QWidget):
21
22
  super().__init__(parent)
22
23
  self.setLayout(qt.QFormLayout())
23
24
  # TODO: check if the widget with output .nx file exists somewhere
24
- self._outputFile = qt.QLineEdit("stitching/stitched.nx", self)
25
+ self._outputFile = QLFileSystem("stitching/stitched.nx", self)
25
26
  self.layout().addRow("output nexus file", self._outputFile)
26
27
  self._outputDataPath = qt.QLineEdit("entry0000", self)
27
28
  self.layout().addRow("output data path", self._outputDataPath)
28
29
 
29
30
  def getUrl(self) -> str:
30
- return HDF5TomoScanIdentifier(
31
- object=HDF5TomoScan,
31
+ return NXtomoScanIdentifier(
32
+ object=NXtomoScan,
32
33
  hdf5_file=self._outputFile.text(),
33
34
  entry=self._outputDataPath.text(),
34
35
  )
35
36
 
36
37
  def setUrl(self, url: str):
37
38
  try:
38
- identifier = HDF5TomoScanIdentifier.from_str(url)
39
+ identifier = NXtomoScanIdentifier.from_str(url)
39
40
  except Exception as e:
40
41
  _logger.warning(f"Fail to create an identifier from {url}. Error is {e}")
41
42
  else:
@@ -71,6 +72,7 @@ class StitchingOutput(qt.QWidget):
71
72
  self._postProcOutput = _PostProcessingOutput(parent=self)
72
73
  self.layout().addWidget(self._postProcOutput)
73
74
  self._overwritePB = qt.QCheckBox("overwrite", self)
75
+ self._overwritePB.setChecked(True)
74
76
  self.layout().addWidget(self._overwritePB)
75
77
 
76
78
  # add a vertical spacer for display
@@ -110,7 +112,7 @@ class StitchingOutput(qt.QWidget):
110
112
  except Exception:
111
113
  scan = None
112
114
 
113
- if not isinstance(scan, HDF5TomoScan):
115
+ if not isinstance(scan, NXtomoScan):
114
116
  _logger.info("Failed to create an HDFTomoscan from url")
115
117
  return None
116
118
  else:
@@ -146,8 +148,8 @@ class StitchingOutput(qt.QWidget):
146
148
  stitching_config.DATA_PATH_FIELD, None
147
149
  )
148
150
  if location is not None:
149
- identifier = HDF5TomoScanIdentifier(
150
- object=HDF5TomoScan, hdf5_file=location, entry=data_path
151
+ identifier = NXtomoScanIdentifier(
152
+ object=NXtomoScan, hdf5_file=location, entry=data_path
151
153
  )
152
154
  self._preProcOutput.setUrl(identifier.to_str())
153
155
 
@@ -3,6 +3,7 @@ import numpy
3
3
  from silx.gui import qt
4
4
 
5
5
  from tomwer.gui.stitching.axisorderedlist import AxisOrderedTomoObjsModel
6
+ from tomwer.gui.utils.step import StepSizeSelectorWidget
6
7
 
7
8
 
8
9
  class PosEditorOverOneAxis(qt.QWidget):
@@ -15,7 +16,6 @@ class PosEditorOverOneAxis(qt.QWidget):
15
16
  ) -> None:
16
17
  assert axis_edited in (0, 1, 2)
17
18
  super().__init__(parent, *args, **kwargs)
18
- self._stepSize = 1
19
19
  self._axisEdited = axis_edited
20
20
  # the axis the spin boxes are editing
21
21
  self._axisOrder = axis_order if axis_order is not None else axis_edited
@@ -25,7 +25,13 @@ class PosEditorOverOneAxis(qt.QWidget):
25
25
  self.__spinBoxescallback = {}
26
26
  self.setLayout(qt.QVBoxLayout())
27
27
  # widget to define step size
28
- self._stepSizeWidget = StepSizeWidget(self)
28
+ self._stepSizeWidget = StepSizeSelectorWidget(
29
+ self,
30
+ fine_value=1,
31
+ medium_value=5,
32
+ rough_value=25,
33
+ dtype=int,
34
+ )
29
35
  self.layout().addWidget(self._stepSizeWidget)
30
36
 
31
37
  # table with the different Tomo objects
@@ -35,22 +41,28 @@ class PosEditorOverOneAxis(qt.QWidget):
35
41
 
36
42
  self.layout().addWidget(self._tomoObjsTableView)
37
43
 
44
+ # connect signal / slot
45
+ self._stepSizeWidget.valueChanged.connect(self._updateStepSize)
46
+
38
47
  # tune table view
39
48
  self._tomoObjsTableView.setColumnWidth(0, 15)
40
49
  self._tomoObjsTableView.setColumnWidth(2, 120)
41
50
  self._tomoObjsTableView.horizontalHeader().setSectionResizeMode(
42
51
  1, qt.QHeaderView.Stretch
43
52
  )
53
+ self.setStepSize(1)
44
54
 
45
- # connect signal / slot
46
- self._stepSizeWidget.stepSB.valueChanged.connect(self.setStepSize)
47
- self._stepSize = 1
55
+ def _updateStepSize(self):
56
+ step_size = self.getStepSize()
57
+ for sb in self._tomoObjtoSpinBoxes.values():
58
+ sb.setSingleStep(step_size)
48
59
 
49
60
  def setStepSize(self, step_size: int):
50
- self._stepSize = step_size
51
- # update SB step size
52
- for sb in self._tomoObjtoSpinBoxes.values():
53
- sb.setSingleStep(self._stepSize)
61
+ self._stepSizeWidget.setStepSize(step_size)
62
+ self._updateStepSize()
63
+
64
+ def getStepSize(self) -> int:
65
+ return self._stepSizeWidget.getStepSize()
54
66
 
55
67
  def addTomoObj(self, tomo_obj):
56
68
  if tomo_obj is None:
@@ -68,7 +80,7 @@ class PosEditorOverOneAxis(qt.QWidget):
68
80
  spinBox = qt.QSpinBox(parent=self)
69
81
  spinBox.setRange(numpy.iinfo(numpy.int32).min, numpy.iinfo(numpy.int32).max)
70
82
  spinBox.setSuffix("px")
71
- spinBox.setSingleStep(self._stepSize)
83
+ spinBox.setSingleStep(self.getStepSize())
72
84
  spinBox.setValue(
73
85
  tomo_obj.stitching_metadata.get_abs_position_px(axis=self._axisEdited)
74
86
  or self.DEFAULT_VALUE_WHEM_MISSING
@@ -154,16 +166,3 @@ class EditableAxisOrderedTomoObjsModel(AxisOrderedTomoObjsModel):
154
166
  def __init__(self, axis: int, parent=None) -> None:
155
167
  super().__init__(axis, parent)
156
168
  self._headers = ["index", "tomo obj", f"axis {axis} pos (px)"]
157
-
158
-
159
- class StepSizeWidget(qt.QWidget):
160
- def __init__(self, parent=None) -> None:
161
- super().__init__(parent)
162
- self.setLayout(qt.QFormLayout())
163
- self._stepSB = qt.QSpinBox(self)
164
- self._stepSB.setRange(1, 9999)
165
- self.layout().addRow("step size", self._stepSB)
166
-
167
- @property
168
- def stepSB(self):
169
- return self._stepSB
@@ -0,0 +1,117 @@
1
+ from __future__ import annotations
2
+ from silx.gui import qt
3
+ from nabu.stitching.sample_normalization import (
4
+ SampleSide as _SampleSide,
5
+ Method as _SampleNormalizationMethod,
6
+ )
7
+ from nabu.stitching import config as _config_stitching
8
+ from tomwer.gui.utils.qt_utils import block_signals
9
+
10
+
11
+ class NormalizationBySampleGroupBox(qt.QGroupBox):
12
+ """
13
+ Widget to define the normalization to apply to frames"""
14
+
15
+ sigConfigChanged = qt.Signal()
16
+ """Emit when the configuration is changed"""
17
+
18
+ def __init__(self, title: str = "normalization by sample", parent=None):
19
+ # FIXME: add a way to the user for requesting a view of the region picked ???
20
+ super().__init__(title, parent)
21
+ self.setCheckable(True)
22
+ self.setLayout(qt.QFormLayout())
23
+
24
+ # method
25
+ self._methodCB = qt.QComboBox(self)
26
+ self._methodCB.addItems(_SampleNormalizationMethod.values())
27
+ self._methodCB.setCurrentText(_SampleNormalizationMethod.MEDIAN.value)
28
+ self.layout().addRow("method", self._methodCB)
29
+
30
+ # side
31
+ self._sideCB = qt.QComboBox(self)
32
+ self._sideCB.addItems(_SampleSide.values())
33
+ self._sideCB.setCurrentText(_SampleSide.LEFT.value)
34
+ self.layout().addRow("sampling side", self._sideCB)
35
+
36
+ # width
37
+ self._widthSB = qt.QSpinBox(self)
38
+ self._widthSB.setRange(1, 9999999)
39
+ self._widthSB.setValue(30)
40
+ self._widthSB.setSingleStep(10)
41
+ self.layout().addRow("sampling width", self._widthSB)
42
+
43
+ # margin
44
+ self._marginSB = qt.QSpinBox(self)
45
+ self._marginSB.setRange(0, 999999)
46
+ self._marginSB.setValue(0)
47
+ self.layout().addRow("sampling margin", self._marginSB)
48
+
49
+ # connect signal / slot
50
+ self._methodCB.currentIndexChanged.connect(self._configChanged)
51
+ self._sideCB.currentIndexChanged.connect(self._configChanged)
52
+ self._widthSB.valueChanged.connect(self._configChanged)
53
+ self._marginSB.valueChanged.connect(self._configChanged)
54
+
55
+ def _configChanged(self, *args, **kwargs):
56
+ self.sigConfigChanged.emit()
57
+
58
+ def getMethod(self) -> _SampleNormalizationMethod:
59
+ return _SampleNormalizationMethod.from_value(self._methodCB.currentText())
60
+
61
+ def setMethod(self, method: _SampleNormalizationMethod | str):
62
+ method = _SampleNormalizationMethod.from_value(method)
63
+ self._methodCB.setCurrentText(method.value)
64
+
65
+ def getSide(self) -> _SampleSide:
66
+ return _SampleSide.from_value(self._sideCB.currentText())
67
+
68
+ def setSide(self, side: _SampleSide):
69
+ side = _SampleSide.from_value(side)
70
+ self._sideCB.setCurrentText(side.value)
71
+
72
+ def getMargin(self) -> int:
73
+ return self._marginSB.value()
74
+
75
+ def setMargin(self, margin: int):
76
+ self._marginSB.setValue(int(margin))
77
+
78
+ def getWidth(self) -> int:
79
+ return self._widthSB.value()
80
+
81
+ def setWidth(self, width: int):
82
+ self._widthSB.setValue(int(width))
83
+
84
+ def getConfiguration(self) -> dict:
85
+ return {
86
+ _config_stitching.NORMALIZATION_BY_SAMPLE_ACTIVE_FIELD: self.isChecked(),
87
+ _config_stitching.NORMALIZATION_BY_SAMPLE_METHOD: self.getMethod().value,
88
+ _config_stitching.NORMALIZATION_BY_SAMPLE_SIDE: self.getSide().value,
89
+ _config_stitching.NORMALIZATION_BY_SAMPLE_MARGIN: self.getMargin(),
90
+ _config_stitching.NORMALIZATION_BY_SAMPLE_WIDTH: self.getWidth(),
91
+ }
92
+
93
+ def setConfiguration(self, config: dict) -> None:
94
+ with block_signals(self):
95
+ method = config.get(_config_stitching.NORMALIZATION_BY_SAMPLE_METHOD, None)
96
+ if method is not None:
97
+ self.setMethod(method=method)
98
+
99
+ side = config.get(_config_stitching.NORMALIZATION_BY_SAMPLE_SIDE, None)
100
+ if side is not None:
101
+ self.setSide(side=side)
102
+
103
+ margin = config.get(_config_stitching.NORMALIZATION_BY_SAMPLE_MARGIN, None)
104
+ if margin is not None:
105
+ self.setMargin(margin=margin)
106
+
107
+ width = config.get(_config_stitching.NORMALIZATION_BY_SAMPLE_WIDTH, None)
108
+ if width is not None:
109
+ self.setWidth(width=width)
110
+
111
+ active = config.get(
112
+ _config_stitching.NORMALIZATION_BY_SAMPLE_ACTIVE_FIELD, None
113
+ )
114
+ if active is not None:
115
+ self.setChecked(active in (True, 1, "1", "True"))
116
+
117
+ self._configChanged()