tomwer 1.0.4__py3-none-any.whl → 1.1.0__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 (256) hide show
  1. orangecontrib/tomwer/tutorials/EBS_tomo_listener.ows +39 -0
  2. orangecontrib/tomwer/tutorials/cast_volume.ows +34 -0
  3. orangecontrib/tomwer/tutorials/simple_slice_reconstruction.ows +39 -0
  4. orangecontrib/tomwer/tutorials/simple_volume_local_reconstruction.ows +49 -0
  5. orangecontrib/tomwer/tutorials/simple_volume_to_slurm_reconstruction.ows +59 -0
  6. orangecontrib/tomwer/tutorials/using_saaxis_to_find_cor.ows +44 -0
  7. orangecontrib/tomwer/widgets/cluster/FutureSupervisorOW.py +1 -1
  8. orangecontrib/tomwer/widgets/cluster/SlurmClusterOW.py +14 -4
  9. orangecontrib/tomwer/widgets/cluster/__init__.py +1 -1
  10. orangecontrib/tomwer/widgets/control/DataListOW.py +12 -5
  11. orangecontrib/tomwer/widgets/control/DataListenerOW.py +18 -9
  12. orangecontrib/tomwer/widgets/control/DataSelectorOW.py +13 -6
  13. orangecontrib/tomwer/widgets/control/DataTransfertOW.py +4 -5
  14. orangecontrib/tomwer/widgets/control/DataValidatorOW.py +8 -4
  15. orangecontrib/tomwer/widgets/control/DataWatcherOW.py +4 -6
  16. orangecontrib/tomwer/widgets/control/EDF2NXTomomillOW.py +49 -62
  17. orangecontrib/tomwer/widgets/control/FilterOW.py +2 -4
  18. orangecontrib/tomwer/widgets/control/NXTomomillMixIn.py +93 -0
  19. orangecontrib/tomwer/widgets/control/NXTomomillOW.py +135 -128
  20. orangecontrib/tomwer/widgets/control/NotifierOW.py +31 -7
  21. orangecontrib/tomwer/widgets/control/SingleTomoObjOW.py +3 -5
  22. orangecontrib/tomwer/widgets/control/TomoObjSerieOW.py +85 -0
  23. orangecontrib/tomwer/widgets/control/VolumeSelector.py +12 -4
  24. orangecontrib/tomwer/widgets/control/VolumeSymLinkOW.py +11 -7
  25. orangecontrib/tomwer/widgets/control/icons/notification.svg +4 -4
  26. orangecontrib/tomwer/widgets/control/icons/nxtomomill.png +0 -0
  27. orangecontrib/tomwer/widgets/control/icons/nxtomomill.svg +8 -5
  28. orangecontrib/tomwer/widgets/control/icons/tomoobjserie.png +0 -0
  29. orangecontrib/tomwer/widgets/control/icons/tomoobjserie.svg +138 -0
  30. orangecontrib/tomwer/widgets/edit/DarkFlatPatchOW.py +16 -4
  31. orangecontrib/tomwer/widgets/edit/NXtomoEditorOW.py +100 -0
  32. orangecontrib/tomwer/widgets/edit/icons/image_key_editor.png +0 -0
  33. orangecontrib/tomwer/widgets/edit/icons/image_key_upgrader.png +0 -0
  34. orangecontrib/tomwer/widgets/edit/icons/nx_tomo_editor.png +0 -0
  35. orangecontrib/tomwer/widgets/edit/icons/nx_tomo_editor.svg +123 -0
  36. orangecontrib/tomwer/widgets/edit/test/test_dark_flat_patch.py +21 -1
  37. orangecontrib/tomwer/widgets/edit/test/test_image_key_editor.py +1 -1
  38. orangecontrib/tomwer/widgets/edit/test/test_image_key_upgrader.py +1 -1
  39. orangecontrib/tomwer/widgets/edit/test/test_nxtomo_editor.py +25 -0
  40. orangecontrib/tomwer/widgets/other/PythonScriptOW.py +19 -10
  41. orangecontrib/tomwer/widgets/reconstruction/AxisOW.py +20 -14
  42. orangecontrib/tomwer/widgets/reconstruction/CastNabuVolumeOW.py +24 -10
  43. orangecontrib/tomwer/widgets/reconstruction/DarkRefAndCopyOW.py +26 -21
  44. orangecontrib/tomwer/widgets/reconstruction/NabuOW.py +29 -12
  45. orangecontrib/tomwer/widgets/reconstruction/NabuVolumeOW.py +44 -17
  46. orangecontrib/tomwer/widgets/reconstruction/SAAxisOW.py +28 -18
  47. orangecontrib/tomwer/widgets/reconstruction/SADeltaBetaOW.py +24 -17
  48. orangecontrib/tomwer/widgets/reconstruction/SinoNormOW.py +6 -6
  49. orangecontrib/tomwer/widgets/reconstruction/TofuOW.py +4 -2
  50. orangecontrib/tomwer/widgets/reconstruction/icons/nabu_2d.png +0 -0
  51. orangecontrib/tomwer/widgets/reconstruction/icons/nabu_2d.svg +11 -8
  52. orangecontrib/tomwer/widgets/visualization/DataViewerOW.py +10 -4
  53. orangecontrib/tomwer/widgets/visualization/DiffViewerOW.py +1 -1
  54. orangecontrib/tomwer/widgets/visualization/NXtomoMetadataViewerOW.py +69 -0
  55. orangecontrib/tomwer/widgets/visualization/SampleMovedOW.py +2 -4
  56. orangecontrib/tomwer/widgets/visualization/icons/nx_tomo_metadata_viewer.png +0 -0
  57. orangecontrib/tomwer/widgets/visualization/icons/nx_tomo_metadata_viewer.svg +105 -0
  58. tomwer/__main__.py +10 -5
  59. tomwer/app/canvas_launcher/config.py +10 -10
  60. tomwer/app/canvas_launcher/mainwindow.py +68 -6
  61. tomwer/app/canvas_launcher/widgetsscheme.py +1 -3
  62. tomwer/app/darkref.py +16 -12
  63. tomwer/app/imagekeyeditor.py +2 -2
  64. tomwer/app/imagekeyupgrader.py +104 -0
  65. tomwer/app/nxtomoeditor.py +103 -0
  66. tomwer/app/rsync.py +1 -1
  67. tomwer/core/cluster/cluster.py +1 -1
  68. tomwer/core/futureobject.py +1 -0
  69. tomwer/core/process/control/datalistener/datalistener.py +7 -1
  70. tomwer/core/process/control/datalistener/rpcserver.py +3 -3
  71. tomwer/core/process/control/datawatcher/datawatcher.py +18 -18
  72. tomwer/core/process/control/datawatcher/datawatcherobserver.py +5 -8
  73. tomwer/core/process/control/datawatcher/datawatcherprocess.py +2 -3
  74. tomwer/core/process/control/datawatcher/edfdwprocess.py +2 -2
  75. tomwer/core/process/control/nxtomomill.py +33 -58
  76. tomwer/core/process/control/scanlist.py +2 -1
  77. tomwer/core/process/control/scanselector.py +7 -0
  78. tomwer/core/process/control/scantransfer.py +9 -18
  79. tomwer/core/process/control/scanvalidator.py +6 -5
  80. tomwer/core/process/control/singletomoobj.py +2 -1
  81. tomwer/core/process/control/timer.py +2 -1
  82. tomwer/core/process/control/tomoobjserie.py +8 -0
  83. tomwer/core/process/control/volumeselector.py +2 -1
  84. tomwer/core/process/control/volumesymlink.py +2 -1
  85. tomwer/core/process/edit/darkflatpatch.py +2 -1
  86. tomwer/core/process/edit/imagekeyeditor.py +4 -3
  87. tomwer/core/process/reconstruction/axis/axis.py +29 -32
  88. tomwer/core/process/reconstruction/axis/mode.py +3 -2
  89. tomwer/core/process/reconstruction/axis/params.py +35 -16
  90. tomwer/core/process/reconstruction/darkref/darkrefs.py +90 -707
  91. tomwer/core/process/reconstruction/darkref/darkrefscopy.py +44 -16
  92. tomwer/core/process/reconstruction/darkref/params.py +62 -67
  93. tomwer/core/process/reconstruction/lamino/tofu.py +1 -1
  94. tomwer/core/process/reconstruction/nabu/castvolume.py +21 -26
  95. tomwer/core/process/reconstruction/nabu/nabucommon.py +36 -38
  96. tomwer/core/process/reconstruction/nabu/nabuscores.py +28 -13
  97. tomwer/core/process/reconstruction/nabu/nabuslices.py +41 -14
  98. tomwer/core/process/reconstruction/nabu/nabuvolume.py +21 -12
  99. tomwer/core/process/reconstruction/nabu/utils.py +12 -1
  100. tomwer/core/process/reconstruction/normalization/normalization.py +9 -8
  101. tomwer/core/process/reconstruction/saaxis/saaxis.py +46 -20
  102. tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +38 -12
  103. tomwer/core/process/reconstruction/test/__init__.py +0 -39
  104. tomwer/core/process/reconstruction/test/test_axis_params.py +25 -3
  105. tomwer/core/process/reconstruction/test/test_darkref_copy.py +117 -1
  106. tomwer/core/process/script/python.py +16 -12
  107. tomwer/core/process/task.py +3 -7
  108. tomwer/core/process/test/test_axis.py +1 -1
  109. tomwer/core/process/test/test_dark_and_flat.py +41 -111
  110. tomwer/core/process/test/test_data_listener.py +0 -29
  111. tomwer/core/process/test/test_data_transfer.py +10 -14
  112. tomwer/core/process/test/test_nabu.py +1 -1
  113. tomwer/core/process/test/test_normalization.py +1 -1
  114. tomwer/core/process/visualization/liveslice.py +6 -0
  115. tomwer/core/scan/blissscan.py +37 -2
  116. tomwer/core/scan/edfscan.py +14 -4
  117. tomwer/core/scan/hdf5scan.py +10 -4
  118. tomwer/core/scan/scanbase.py +35 -29
  119. tomwer/core/scan/scanfactory.py +3 -17
  120. tomwer/core/scan/test/test_h5.py +1 -1
  121. tomwer/core/scan/test/test_process_registration.py +0 -11
  122. tomwer/core/scan/test/test_scan.py +32 -30
  123. tomwer/core/settings.py +2 -2
  124. tomwer/core/test/test_utils.py +1 -1
  125. tomwer/core/tomwer_object.py +19 -0
  126. tomwer/core/utils/__init__.py +0 -45
  127. tomwer/core/utils/char.py +2 -0
  128. tomwer/core/utils/gpu.py +5 -5
  129. tomwer/core/utils/nxtomoutils.py +2 -2
  130. tomwer/core/utils/scanutils.py +50 -0
  131. tomwer/core/utils/volumeutils.py +13 -0
  132. tomwer/core/volume/edfvolume.py +4 -0
  133. tomwer/core/volume/hdf5volume.py +4 -0
  134. tomwer/core/volume/jp2kvolume.py +4 -0
  135. tomwer/core/volume/rawvolume.py +4 -0
  136. tomwer/core/volume/tiffvolume.py +4 -0
  137. tomwer/core/volume/volumebase.py +19 -12
  138. tomwer/core/volume/volumefactory.py +20 -1
  139. tomwer/gui/cluster/slurm.py +1 -1
  140. tomwer/gui/cluster/test/test_cluster.py +2 -2
  141. tomwer/gui/control/datalist.py +109 -34
  142. tomwer/gui/control/datatransfert.py +1 -1
  143. tomwer/gui/control/datawatcher/datawatcher.py +23 -13
  144. tomwer/gui/control/datawatcher/datawatcherobserver.py +1 -1
  145. tomwer/gui/control/observations.py +0 -3
  146. tomwer/gui/control/selectorwidgetbase.py +42 -11
  147. tomwer/gui/control/serie/seriecreator.py +967 -0
  148. tomwer/{web/__init__.py → gui/control/serie/seriewaiter.py} +5 -7
  149. tomwer/gui/control/singletomoobj.py +15 -3
  150. tomwer/gui/control/test/test_datalist.py +1 -1
  151. tomwer/gui/control/test/test_datalistener.py +1 -1
  152. tomwer/gui/control/test/test_inputwidget.py +1 -1
  153. tomwer/gui/control/test/test_process_manager.py +1 -13
  154. tomwer/gui/control/test/test_scanselector.py +1 -1
  155. tomwer/gui/control/test/test_scanvalidator.py +1 -1
  156. tomwer/gui/control/test/test_single_tomo_obj.py +1 -1
  157. tomwer/gui/control/test/test_volume_dialog.py +19 -7
  158. tomwer/gui/control/test/test_volumeselector.py +4 -4
  159. tomwer/gui/debugtools/datasetgenerator.py +1 -8
  160. tomwer/gui/edit/dkrfpatch.py +2 -2
  161. tomwer/gui/edit/imagekeyeditor.py +12 -9
  162. tomwer/gui/edit/nxtomoeditor.py +475 -0
  163. tomwer/gui/edit/test/test_dkrf_patch.py +2 -14
  164. tomwer/gui/edit/test/test_image_key_editor.py +2 -2
  165. tomwer/gui/edit/test/test_nx_editor.py +155 -0
  166. tomwer/gui/qfolderdialog.py +11 -0
  167. tomwer/gui/reconstruction/axis/CompareImages.py +27 -29
  168. tomwer/gui/reconstruction/axis/axis.py +2 -0
  169. tomwer/gui/reconstruction/axis/radioaxis.py +67 -11
  170. tomwer/gui/reconstruction/darkref/darkrefcopywidget.py +7 -9
  171. tomwer/gui/reconstruction/darkref/darkrefwidget.py +22 -24
  172. tomwer/gui/reconstruction/lamino/tofu/projections.py +1 -1
  173. tomwer/gui/reconstruction/lamino/tofu/tofu.py +3 -3
  174. tomwer/gui/reconstruction/lamino/tofu/tofuexpert.py +4 -4
  175. tomwer/gui/reconstruction/lamino/tofu/tofuoutput.py +10 -4
  176. tomwer/gui/reconstruction/nabu/castvolume.py +80 -11
  177. tomwer/gui/reconstruction/nabu/check.py +1 -1
  178. tomwer/gui/reconstruction/nabu/nabuconfig/ctf.py +352 -0
  179. tomwer/gui/reconstruction/nabu/nabuconfig/nabuconfig.py +0 -9
  180. tomwer/gui/reconstruction/nabu/nabuconfig/output.py +1 -1
  181. tomwer/gui/reconstruction/nabu/nabuconfig/phase.py +18 -19
  182. tomwer/gui/reconstruction/nabu/nabuconfig/preprocessing.py +30 -7
  183. tomwer/gui/reconstruction/nabu/nabuconfig/reconstruction.py +26 -13
  184. tomwer/gui/reconstruction/nabu/slices.py +10 -2
  185. tomwer/gui/reconstruction/nabu/slurm.py +1 -1
  186. tomwer/gui/reconstruction/nabu/volume.py +13 -7
  187. tomwer/gui/reconstruction/normalization/intensity.py +1 -1
  188. tomwer/gui/reconstruction/saaxis/corrangeselector.py +10 -34
  189. tomwer/gui/reconstruction/saaxis/saaxis.py +11 -6
  190. tomwer/gui/reconstruction/saaxis/sliceselector.py +11 -26
  191. tomwer/gui/reconstruction/sadeltabeta/saadeltabeta.py +13 -8
  192. tomwer/gui/reconstruction/scores/scoreplot.py +67 -61
  193. tomwer/gui/reconstruction/test/test_axis.py +2 -2
  194. tomwer/gui/reconstruction/test/test_lamino.py +2 -2
  195. tomwer/gui/reconstruction/test/test_nabu.py +14 -1
  196. tomwer/gui/reconstruction/test/test_saaxis.py +8 -17
  197. tomwer/gui/reconstruction/test/test_sadeltabeta.py +7 -13
  198. tomwer/gui/stackplot.py +11 -28
  199. tomwer/gui/test/test_axis_gui.py +4 -4
  200. tomwer/gui/test/test_qfolder_dialog.py +12 -0
  201. tomwer/gui/utils/inputwidget.py +42 -21
  202. tomwer/gui/utils/lineselector/lineselector.py +13 -21
  203. tomwer/gui/utils/scandescription.py +2 -4
  204. tomwer/gui/utils/slider.py +1 -102
  205. tomwer/gui/utils/unitsystem.py +48 -11
  206. tomwer/gui/visualization/dataviewer.py +24 -17
  207. tomwer/gui/visualization/diffviewer/diffviewer.py +2 -11
  208. tomwer/gui/visualization/nxtomometadata.py +21 -0
  209. tomwer/gui/visualization/scanoverview.py +0 -1
  210. tomwer/gui/visualization/test/test_nx_tomo_metadata_viewer.py +72 -0
  211. tomwer/gui/visualization/test/test_stacks.py +1 -1
  212. tomwer/gui/visualization/tomoobjoverview.py +49 -0
  213. tomwer/gui/visualization/volumeoverview.py +64 -0
  214. tomwer/gui/visualization/volumeviewer.py +1 -1
  215. tomwer/resources/gui/icons/multi-document-save.png +0 -0
  216. tomwer/resources/gui/icons/multi-document-save.svg +101 -0
  217. tomwer/resources/gui/illustrations/ctf_z1.png +0 -0
  218. tomwer/resources/gui/illustrations/ctf_z1.svg +471 -0
  219. tomwer/synctools/datalistener.py +5 -1
  220. tomwer/synctools/imageloaderthread.py +2 -2
  221. tomwer/synctools/stacks/edit/imagekeyeditor.py +1 -1
  222. tomwer/synctools/stacks/processingstack.py +2 -2
  223. tomwer/synctools/stacks/reconstruction/castvolume.py +1 -0
  224. tomwer/synctools/stacks/reconstruction/lamino.py +1 -3
  225. tomwer/synctools/stacks/reconstruction/sadeltabeta.py +0 -2
  226. tomwer/synctools/test/test_darkRefs.py +32 -149
  227. tomwer/synctools/test/test_foldertransfer.py +1 -1
  228. tomwer/synctools/test/test_scanstages.py +2 -2
  229. tomwer/tests/__init__.py +0 -0
  230. tomwer/tests/conftest.py +51 -0
  231. tomwer/{test → tests}/test_scripts.py +1 -1
  232. tomwer/tests/test_utils.py +10 -0
  233. tomwer/{test → tests}/utils/utilstest.py +0 -11
  234. tomwer/version.py +3 -3
  235. {tomwer-1.0.4.dist-info → tomwer-1.1.0.dist-info}/METADATA +14 -16
  236. {tomwer-1.0.4.dist-info → tomwer-1.1.0.dist-info}/RECORD +245 -217
  237. {tomwer-1.0.4.dist-info → tomwer-1.1.0.dist-info}/WHEEL +1 -1
  238. {tomwer-1.0.4.dist-info → tomwer-1.1.0.dist-info}/entry_points.txt +6 -0
  239. orangecontrib/tomwer/setup.py +0 -45
  240. orangecontrib/tomwer/widgets/setup.py +0 -49
  241. tomwer/app/process.py +0 -153
  242. tomwer/core/process/reconstruction/nabu/slurm.py +0 -36
  243. tomwer/core/process/reconstruction/utils/nabu_slice_exec.py +0 -10
  244. tomwer/core/utils/laminoutils.py +0 -80
  245. tomwer/gui/utils/lineselector/lineselection.py +0 -76
  246. tomwer/setup.py +0 -52
  247. tomwer/web/client.py +0 -43
  248. tomwer/web/config.py +0 -36
  249. tomwer/web/test/test_graylog_connection.py +0 -59
  250. {tomwer/test → orangecontrib/tomwer/tutorials}/__init__.py +0 -0
  251. /tomwer/{web/test → gui/control/serie}/__init__.py +0 -0
  252. /tomwer/{test → tests}/utils/__init__.py +0 -0
  253. /tomwer-1.0.4-py3.8-nspkg.pth → /tomwer-1.1.0-py3.9-nspkg.pth +0 -0
  254. {tomwer-1.0.4.dist-info → tomwer-1.1.0.dist-info}/LICENSE +0 -0
  255. {tomwer-1.0.4.dist-info → tomwer-1.1.0.dist-info}/namespace_packages.txt +0 -0
  256. {tomwer-1.0.4.dist-info → tomwer-1.1.0.dist-info}/top_level.txt +0 -0
@@ -37,7 +37,9 @@ from tomwer.core.process.reconstruction.nabu.castvolume import (
37
37
  from tomwer.core.process.reconstruction.nabu.nabucommon import NabuOutputFileFormat
38
38
  from tomwer.gui.qlefilesystem import QLFileSystem
39
39
  from tomwer.gui.reconstruction.nabu.nabuconfig.output import QNabuFileFormatComboBox
40
+ from silx.gui.utils import blockSignals
40
41
  import logging
42
+ from typing import Optional
41
43
 
42
44
  _logger = logging.getLogger(__name__)
43
45
 
@@ -58,28 +60,53 @@ class CastVolumeWidget(qt.QWidget):
58
60
  self._outputDataTypeCB = qt.QComboBox(self)
59
61
  for data_type in ("uint8", "uint16", "float32", "float64"):
60
62
  self._outputDataTypeCB.addItem(data_type)
61
- self.layout().addWidget(self._outputDataTypeCB, 0, 2, 1, 2)
63
+ self.layout().addWidget(self._outputDataTypeCB, 0, 1, 1, 3)
62
64
  # output file format
63
65
  self._outputFileformatLabel = qt.QLabel("output file format", self)
64
66
  self.layout().addWidget(self._outputFileformatLabel, 1, 0, 1, 1)
65
67
  self._outputFileformatCB = QNabuFileFormatComboBox(self)
66
- self.layout().addWidget(self._outputFileformatCB, 1, 2, 1, 1)
67
- # rescale percentiles
68
+ self.layout().addWidget(self._outputFileformatCB, 1, 1, 1, 3)
69
+
70
+ # let the user provide min and max manually
71
+ self._minMaxLabel = qt.QLabel("min max values")
72
+ self.layout().addWidget(self._minMaxLabel, 2, 0, 1, 1)
73
+ self._minMaxAuto = qt.QCheckBox("auto with rescale from percentiles")
74
+ self._minMaxAuto.setChecked(True)
75
+ self._minMaxAuto.setToolTip(
76
+ "If set to auto will try to get min/max pixel values from nabu histogram else will compute it. Otherwise will values provided by the user"
77
+ )
78
+ self.layout().addWidget(self._minMaxAuto, 2, 1, 1, 1)
79
+
80
+ self._minPixValue = qt.QLineEdit("", self)
81
+ self._minPixValue.setPlaceholderText("min")
82
+ self._maxPixValue = qt.QLineEdit("", self)
83
+ self._maxPixValue.setPlaceholderText("max")
84
+ validator = qt.QDoubleValidator(self)
85
+ validator.setNotation(qt.QDoubleValidator.ScientificNotation)
86
+ self._minPixValue.setValidator(validator)
87
+ self._maxPixValue.setValidator(validator)
88
+ self.layout().addWidget(self._minPixValue, 4, 2, 1, 1)
89
+ self.layout().addWidget(self._maxPixValue, 4, 3, 1, 1)
90
+ self._minPixValue.setVisible(False)
91
+ self._maxPixValue.setVisible(False)
92
+ # or from percentiles
68
93
  self._percentilesLabel = qt.QLabel("rescale percentiles")
69
- self.layout().addWidget(self._percentilesLabel, 2, 0, 1, 1)
94
+ self.layout().addWidget(self._percentilesLabel, 3, 1, 1, 1)
70
95
  self._lowPercentileQSB = qt.QSpinBox(self)
71
96
  self._lowPercentileQSB.setRange(0, 100)
72
97
  self._lowPercentileQSB.setPrefix("min:")
98
+ self._lowPercentileQSB.setSuffix("%")
73
99
  self._lowPercentileQSB.setValue(RESCALE_MIN_PERCENTILE)
74
- self.layout().addWidget(self._lowPercentileQSB, 2, 1, 1, 1)
100
+ self.layout().addWidget(self._lowPercentileQSB, 3, 2, 1, 1)
75
101
  self._highPercentileQSB = qt.QSpinBox(self)
76
102
  self._highPercentileQSB.setRange(0, 100)
77
103
  self._highPercentileQSB.setPrefix("max:")
104
+ self._highPercentileQSB.setSuffix("%")
78
105
  self._highPercentileQSB.setValue(RESCALE_MAX_PERCENTILE)
79
- self.layout().addWidget(self._highPercentileQSB, 2, 2, 1, 1)
106
+ self.layout().addWidget(self._highPercentileQSB, 3, 3, 1, 1)
80
107
  # save dir
81
108
  self._saveDirLabel = qt.QLabel("output directory", self)
82
- self.layout().addWidget(self._saveDirLabel, 3, 0, 1, 1)
109
+ self.layout().addWidget(self._saveDirLabel, 5, 0, 1, 1)
83
110
  self._useDefaultSaveDirQCB = qt.QCheckBox("default", self)
84
111
  self._useDefaultSaveDirQCB.setToolTip(
85
112
  f"Default directory is: {DEFAULT_OUTPUT_DIR}"
@@ -88,7 +115,7 @@ class CastVolumeWidget(qt.QWidget):
88
115
  qt.QSizePolicy.Minimum, qt.QSizePolicy.Minimum
89
116
  )
90
117
  self._useDefaultSaveDirQCB.setChecked(True)
91
- self.layout().addWidget(self._useDefaultSaveDirQCB, 3, 1, 1, 1)
118
+ self.layout().addWidget(self._useDefaultSaveDirQCB, 5, 1, 1, 1)
92
119
  self._saveDirQLE = QLFileSystem(text=DEFAULT_OUTPUT_DIR, parent=self)
93
120
  # force text because this is not a valid path
94
121
  self._saveDirQLE.setText(DEFAULT_OUTPUT_DIR)
@@ -99,11 +126,11 @@ class CastVolumeWidget(qt.QWidget):
99
126
  """
100
127
  )
101
128
  self._saveDirQLE.setVisible(False)
102
- self.layout().addWidget(self._saveDirQLE, 3, 2, 1, 1)
129
+ self.layout().addWidget(self._saveDirQLE, 5, 2, 1, 2)
103
130
  # overwrite
104
131
  self._overwriteCB = qt.QCheckBox("overwrite", self)
105
132
  self._overwriteCB.setChecked(True)
106
- self.layout().addWidget(self._overwriteCB, 4, 0, 1, 1)
133
+ self.layout().addWidget(self._overwriteCB, 6, 0, 1, 1)
107
134
  # spacer
108
135
  self._spacer = qt.QWidget(self)
109
136
  self._spacer.setSizePolicy(
@@ -118,6 +145,8 @@ class CastVolumeWidget(qt.QWidget):
118
145
  self._useDefaultSaveDirQCB.toggled.connect(self._configChanged)
119
146
  self._overwriteCB.toggled.connect(self._configChanged)
120
147
  self._useDefaultSaveDirQCB.toggled.connect(self._updateOutputDirVis)
148
+ self._minMaxAuto.toggled.connect(self._configChanged)
149
+ self._minMaxAuto.toggled.connect(self._updatePixMinMaxVis)
121
150
 
122
151
  def getOutputDataType(self) -> str:
123
152
  return self._outputDataTypeCB.currentText()
@@ -154,6 +183,38 @@ class CastVolumeWidget(qt.QWidget):
154
183
  def setOverwrite(self, remove) -> None:
155
184
  self._overwriteCB.setChecked(remove)
156
185
 
186
+ def getDataMin(self) -> Optional[float]:
187
+ if (
188
+ self._minMaxAuto.isChecked()
189
+ or self._minPixValue.text().replace(" ", "") == ""
190
+ ):
191
+ return None
192
+ else:
193
+ return float(self._minPixValue.text())
194
+
195
+ def setDataMin(self, value: Optional[float]) -> None:
196
+ with blockSignals(self._minMaxAuto):
197
+ self._minMaxAuto.setChecked(value is None)
198
+ if value is not None:
199
+ with blockSignals(self._minPixValue):
200
+ self._minPixValue.setText(str(value))
201
+
202
+ def getDataMax(self) -> Optional[float]:
203
+ if (
204
+ self._minMaxAuto.isChecked()
205
+ or self._maxPixValue.text().replace(" ", "") == ""
206
+ ):
207
+ return None
208
+ else:
209
+ return float(self._maxPixValue.text())
210
+
211
+ def setDataMax(self, value: Optional[float]) -> None:
212
+ with blockSignals(self._minMaxAuto):
213
+ self._minMaxAuto.setChecked(value is None)
214
+ if value is not None:
215
+ with blockSignals(self._maxPixValue):
216
+ self._maxPixValue.setText(str(value))
217
+
157
218
  def getConfiguration(self) -> dict:
158
219
  rescale_min_percentile, rescale_max_percentile = self.getRescalePercentiles()
159
220
  return {
@@ -163,6 +224,8 @@ class CastVolumeWidget(qt.QWidget):
163
224
  "overwrite": self.getOverwrite(),
164
225
  "rescale_min_percentile": rescale_min_percentile,
165
226
  "rescale_max_percentile": rescale_max_percentile,
227
+ "data_min": self.getDataMin(),
228
+ "data_max": self.getDataMax(),
166
229
  }
167
230
 
168
231
  def getRescalePercentiles(self) -> tuple:
@@ -187,7 +250,6 @@ class CastVolumeWidget(qt.QWidget):
187
250
  overwrite = config.get("overwrite", None)
188
251
  if overwrite is not None:
189
252
  self.setOverwrite(overwrite)
190
-
191
253
  if "rescale_percentiles" in config:
192
254
  rescale_min_percentile, rescale_max_percentile = config[
193
255
  "rescale_percentiles"
@@ -210,3 +272,10 @@ class CastVolumeWidget(qt.QWidget):
210
272
 
211
273
  def _updateOutputDirVis(self, *args, **kwargs):
212
274
  self._saveDirQLE.setVisible(not self._useDefaultSaveDirQCB.isChecked())
275
+
276
+ def _updatePixMinMaxVis(self, *args, **kwargs):
277
+ self._minPixValue.setVisible(not self._minMaxAuto.isChecked())
278
+ self._maxPixValue.setVisible(not self._minMaxAuto.isChecked())
279
+ self._percentilesLabel.setVisible(self._minMaxAuto.isChecked())
280
+ self._lowPercentileQSB.setVisible(self._minMaxAuto.isChecked())
281
+ self._highPercentileQSB.setVisible(self._minMaxAuto.isChecked())
@@ -30,7 +30,7 @@ __date__ = "02/12/2021"
30
30
 
31
31
  from tomwer.core.scan.hdf5scan import HDF5TomoScan
32
32
  from tomwer.core.utils.nxtomoutils import get_n_series
33
- from tomoscan.esrf.hdf5scan import ImageKey
33
+ from tomoscan.esrf.scan.hdf5scan import ImageKey
34
34
  from silx.gui import qt
35
35
 
36
36
 
@@ -0,0 +1,352 @@
1
+ from silx.gui import qt
2
+ from typing import Optional, Union
3
+ from tomwer.core.process.reconstruction.nabu.utils import _NabuStages
4
+ from tomwer.gui.reconstruction.nabu.nabuconfig import base
5
+ from tomwer.gui.utils.illustrations import _IllustrationWidget
6
+ from silx.gui.utils import blockSignals
7
+ from silx.utils.enum import Enum as _Enum
8
+ from .reconstruction import AnglesFileWidget as Filewidget
9
+
10
+
11
+ def nabu_param_ligne_to_dict(str_ligne: str) -> dict:
12
+ ddict = {}
13
+ if "=" in str_ligne:
14
+ for elmt in str_ligne.split(";"):
15
+ kwv = elmt.lstrip(" ").rstrip(" ")
16
+ key, value = kwv.split("=")
17
+ ddict[key] = value
18
+ return ddict
19
+
20
+
21
+ class _DoubleScientific(qt.QLineEdit):
22
+ """
23
+ A simple QLineEdit with a Doublevalidator with Scientific Notation
24
+ """
25
+
26
+ def __init__(self, parent=None, *args, **kwargs):
27
+ super().__init__(parent, *args, **kwargs)
28
+ validator = qt.QDoubleValidator(parent=self)
29
+ validator.setNotation(qt.QDoubleValidator.ScientificNotation)
30
+ self.setValidator(validator)
31
+
32
+ def value(self) -> float:
33
+ if self.text() == "":
34
+ return 0.0
35
+ else:
36
+ return float(self.text())
37
+
38
+ def setValue(self, value):
39
+ self.setText(str(value))
40
+
41
+
42
+ class OptionalDouble(qt.QWidget):
43
+ """
44
+ A spin box with a Check box to handle 'None' case of the nabu CTF options
45
+ """
46
+
47
+ sigChanged = qt.Signal()
48
+ """emit when the combobox of the double spin box value changed"""
49
+
50
+ def __init__(self, parent) -> None:
51
+ super().__init__(parent)
52
+ self.setLayout(qt.QHBoxLayout())
53
+ self._cb = qt.QCheckBox("", self)
54
+ self.layout().addWidget(self._cb)
55
+ self._dsb = _DoubleScientific(self)
56
+ self.layout().addWidget(self._dsb)
57
+
58
+ # connect signal ? slot
59
+ self._cb.toggled.connect(self._updateVisibility)
60
+ self._cb.toggled.connect(self._changed)
61
+ self._dsb.textChanged.connect(self._changed)
62
+
63
+ # set up
64
+ self._updateVisibility()
65
+
66
+ def _changed(self, *args, **kwargs):
67
+ self.sigChanged.emit()
68
+
69
+ def value(self) -> Optional[float]:
70
+ if self._cb.isChecked():
71
+ return self._dsb.value()
72
+ else:
73
+ return None
74
+
75
+ def setValue(self, value: Optional[float]):
76
+ if value in (None, "None"):
77
+ self._cb.setChecked(False)
78
+ else:
79
+ self._cb.setChecked(True)
80
+ self._dsb.setValue(float(value))
81
+
82
+ def setText(self, text: str):
83
+ self._cb.setText(text)
84
+
85
+ def _updateVisibility(self, *args, **kwargs):
86
+ self._dsb.setVisible(self._cb.isChecked())
87
+
88
+
89
+ class _BeamShape(_Enum):
90
+ PARALLEL = "parallel"
91
+ CONE = "cone"
92
+
93
+
94
+ class ConeBeamOpts(qt.QGroupBox):
95
+ """Specific settings for cone beam geometry"""
96
+
97
+ sigConfChanged = qt.Signal()
98
+ """emit when ctf parameters changed"""
99
+
100
+ def __init__(self, parent=None, title="cone settings"):
101
+ super().__init__(parent, title=title)
102
+ self.setLayout(qt.QGridLayout())
103
+ # z1_v
104
+ self._z1_v = _DoubleScientific(self)
105
+ self._z1_v.setPlaceholderText("z1_v in meter")
106
+ self.layout().addWidget(qt.QLabel("z1_v", self), 0, 0, 1, 1)
107
+ self.layout().addWidget(self._z1_v, 0, 1, 1, 1)
108
+ # z1_h
109
+ self._z1_h = _DoubleScientific(self)
110
+ self._z1_h.setPlaceholderText("z1_h in meter")
111
+ self.layout().addWidget(qt.QLabel("z1_h", self), 1, 0, 1, 1)
112
+ self.layout().addWidget(self._z1_h, 1, 1, 1, 1)
113
+
114
+ # illustration to define z1, z2
115
+ self._ctfIllustration = _IllustrationWidget(parent=self, img="ctf_z1")
116
+ self._ctfIllustration.setMinimumSize(qt.QSize(200, 90))
117
+ self._ctfIllustration.setSizePolicy(
118
+ qt.QSizePolicy.Expanding, qt.QSizePolicy.Expanding
119
+ )
120
+
121
+ self._ctfIllustration.setContentsMargins(0, 0, 0, 0)
122
+ self._ctfIllustration.layout().setSpacing(0)
123
+ self.layout().addWidget(self._ctfIllustration, 0, 2, 2, 2)
124
+
125
+ # connect signal / slot
126
+ self._z1_v.textChanged.connect(self._confChanged)
127
+ self._z1_h.textChanged.connect(self._confChanged)
128
+
129
+ def _confChanged(self, *args, **kwargs):
130
+ self.sigConfChanged.emit()
131
+
132
+ def getGeometry(self) -> dict:
133
+ return {
134
+ "z1_v": self._z1_v.value(),
135
+ "z1_h": self._z1_h.value(),
136
+ }
137
+
138
+ def setGeometry(self, config: dict) -> None:
139
+ with blockSignals(self):
140
+ if "z1_v" in config:
141
+ self._z1_v.setValue(float(config["z1_v"]))
142
+ if "z1_h" in config:
143
+ self._z1_h.setValue(float(config["z1_h"]))
144
+
145
+
146
+ class CTFGeometry(qt.QGroupBox):
147
+ """
148
+ widget for the ctf_geometry parameter of nabu
149
+ """
150
+
151
+ sigConfChanged = qt.Signal()
152
+ """emit when ctf parameters changed"""
153
+
154
+ def __init__(self, parent=None, title="ctf-geometry") -> None:
155
+ super().__init__(parent, title=title)
156
+ self.setLayout(qt.QFormLayout())
157
+ self._beamShapeCB = qt.QComboBox(self)
158
+ for shape in _BeamShape.values():
159
+ self._beamShapeCB.addItem(shape)
160
+ self.layout().addRow("shape", self._beamShapeCB)
161
+
162
+ # cone beam settings
163
+ self._coneBeamSettings = ConeBeamOpts(self)
164
+ self.layout().addRow(self._coneBeamSettings)
165
+
166
+ # detector pixel size
167
+ self._detectorPixelSize = OptionalDouble(self)
168
+ self._detectorPixelSize.setText("overwrite")
169
+ self._detectorPixelSize._dsb.setPlaceholderText("pixel size in meter")
170
+ self.layout().addRow("detector pixel size", self._detectorPixelSize)
171
+ # magnification
172
+ self._magnification = qt.QCheckBox("magnification", self)
173
+ self.layout().addRow(self._magnification)
174
+
175
+ # set up
176
+ self._magnification.setChecked(True)
177
+ self._updateView()
178
+
179
+ # connect signal / slot
180
+ self._coneBeamSettings.sigConfChanged.connect(self._confChanged)
181
+ self._detectorPixelSize.sigChanged.connect(self._confChanged)
182
+ self._magnification.toggled.connect(self._confChanged)
183
+ self._beamShapeCB.currentIndexChanged.connect(self._updateView)
184
+ self._beamShapeCB.currentIndexChanged.connect(self._confChanged)
185
+
186
+ def getBeamShape(self):
187
+ return _BeamShape.from_value(self._beamShapeCB.currentText())
188
+
189
+ def setBeamShape(self, shape: Union[str, _BeamShape]):
190
+ shape = _BeamShape.from_value(shape)
191
+ self._beamShapeCB.setCurrentText(shape.value)
192
+
193
+ def _updateView(self, *args, **kwargs):
194
+ self._coneBeamSettings.setVisible(self.getBeamShape() == _BeamShape.CONE)
195
+
196
+ def _confChanged(self, *args, **kwargs):
197
+ self.sigConfChanged.emit()
198
+
199
+ def getConfiguration(self) -> dict:
200
+ magnification = "True" if self._magnification.isChecked() else "False"
201
+ beam_shape = self.getBeamShape()
202
+ if beam_shape is _BeamShape.PARALLEL:
203
+ z1_v = None
204
+ z1_h = None
205
+ elif beam_shape is _BeamShape.CONE:
206
+ cone_params = self._coneBeamSettings.getGeometry()
207
+ z1_v = cone_params["z1_v"]
208
+ z1_h = cone_params["z1_h"]
209
+ else:
210
+ raise NotImplementedError(f"Geometry {beam_shape.value} is not handled")
211
+
212
+ geometry = f" z1_v={z1_v}; z1_h={z1_h}; detec_pixel_size={self._detectorPixelSize.value()}; magnification={magnification}"
213
+
214
+ return {"ctf_geometry": geometry, "beam_shape": beam_shape.value}
215
+
216
+ def setConfiguration(self, ddict: dict) -> None:
217
+ params = nabu_param_ligne_to_dict(ddict.get("ctf_geometry", ""))
218
+ with blockSignals(self):
219
+ for key, value in params.items():
220
+ if key == "detec_pixel_size":
221
+ self._detectorPixelSize.setValue(value)
222
+ elif key == "magnification":
223
+ self._magnification.setChecked(value.lower() == "true")
224
+
225
+ beam_shape = ddict.get("beam_shape", None)
226
+ if beam_shape is not None:
227
+ if _BeamShape.from_value(beam_shape) is _BeamShape.CONE:
228
+ self._coneBeamSettings.setGeometry(params)
229
+ self.setBeamShape(beam_shape)
230
+
231
+
232
+ class CTFAdvancedParams(qt.QGroupBox):
233
+ """
234
+ widget for the ctf_advanced_params parameter of nabu
235
+ """
236
+
237
+ sigConfChanged = qt.Signal()
238
+ """emit when ctf parameters changed"""
239
+
240
+ def __init__(self, parent=None, title="ctf-advanced-params") -> None:
241
+ super().__init__(parent, title=title)
242
+ self.setLayout(qt.QFormLayout())
243
+ # length_scale
244
+ self._length_scale = _DoubleScientific(self)
245
+ self.layout().addRow("length_scale", self._length_scale)
246
+ # lim1
247
+ self._lim1 = _DoubleScientific(self)
248
+ self._lim1Label = qt.QLabel("lim1")
249
+ self.layout().addRow(self._lim1Label, self._lim1)
250
+ # lim2
251
+ self._lim2 = _DoubleScientific(self)
252
+ self._lim2Label = qt.QLabel("lim2")
253
+ self.layout().addRow(self._lim2Label, self._lim2)
254
+ for w in (self._lim1, self._lim1Label, self._lim2, self._lim2Label):
255
+ w.setToolTip(
256
+ "parameter of the low-pass filter. Used in equation: 'lim = lim1 * r + lim2 * (1 - r)' where r is some low-pass filter (image dimensionality)"
257
+ )
258
+
259
+ # normalize_by_mean
260
+ self._normalize_by_mean = qt.QCheckBox("normalize by mean", self)
261
+ self.layout().addRow(self._normalize_by_mean)
262
+
263
+ # set up
264
+ self._length_scale.setText("1e-5")
265
+ self._lim1.setText("1e-5")
266
+ self._lim2.setText("0.2")
267
+ self._normalize_by_mean.setChecked(True)
268
+
269
+ # connect sginal / slot
270
+ self._length_scale.textChanged.connect(self._confChanged)
271
+ self._lim1.textChanged.connect(self._confChanged)
272
+ self._lim2.textChanged.connect(self._confChanged)
273
+ self._normalize_by_mean.toggled.connect(self._confChanged)
274
+
275
+ def getLengthScale(self) -> str:
276
+ if self._length_scale.text() == "":
277
+ return "0.0"
278
+ else:
279
+ return self._length_scale.text()
280
+
281
+ def _confChanged(self, *args, **kwargs):
282
+ self.sigConfChanged.emit()
283
+
284
+ def getConfiguration(self) -> dict:
285
+ normalize_by_mean = "True" if self._normalize_by_mean.isChecked() else "False"
286
+ ctf_advanced_params = f" length_scale={self._length_scale.value()}; lim1={self._lim1.value()}; lim2={self._lim2.value()}; normalize_by_mean={normalize_by_mean}"
287
+ return {
288
+ "ctf_advanced_params": ctf_advanced_params,
289
+ }
290
+
291
+ def setConfiguration(self, ddict: dict) -> None:
292
+ params = nabu_param_ligne_to_dict(ddict.get("ctf_advanced_params", {}))
293
+ with blockSignals(self):
294
+ for key, value in params.items():
295
+ if key == "length_scale":
296
+ self._length_scale.setText(value)
297
+ elif key == "lim1":
298
+ self._lim1.setText(value)
299
+ elif key == "lim2":
300
+ self._lim2.setText(value)
301
+ elif key == "normalize_by_mean":
302
+ self._normalize_by_mean.setChecked(value.lower() == "true")
303
+
304
+
305
+ class CTFConfig(qt.QGroupBox, base._NabuStageConfigBase):
306
+ """
307
+ Widget dedicated for the CTF parameters
308
+ """
309
+
310
+ sigConfChanged = qt.Signal(str)
311
+ """emit when ctf parameters changed"""
312
+
313
+ def __init__(self, parent=None, title="ctf parameters"):
314
+ qt.QGroupBox.__init__(self, parent, title=title, stage=_NabuStages.PHASE)
315
+ base._NabuStageConfigBase.__init__(self, stage=_NabuStages.PHASE)
316
+
317
+ self.setLayout(qt.QFormLayout())
318
+
319
+ # geometry
320
+ self._geometryWidget = CTFGeometry(parent=self, title="geometry")
321
+ self.layout().addRow(self._geometryWidget)
322
+ self.registerWidget(self._geometryWidget, "optional")
323
+ # translation file
324
+ self._translationFile = Filewidget(self)
325
+ self.layout().addRow("translation file", self._translationFile)
326
+ self.registerWidget(self._translationFile, "optional")
327
+ # advanced parameters
328
+ self._advancedParamsWidget = CTFAdvancedParams(
329
+ parent=self, title="advanced parameters"
330
+ )
331
+ self.layout().addRow(self._advancedParamsWidget)
332
+ self.registerWidget(self._advancedParamsWidget, "advanced")
333
+
334
+ # connect signal / slot
335
+ self._geometryWidget.sigConfChanged.connect(self._confChanged)
336
+ self._advancedParamsWidget.sigConfChanged.connect(self._confChanged)
337
+ self._translationFile._qle.textEdited.connect(self._confChanged)
338
+
339
+ def _confChanged(self, *args, **kwargs):
340
+ self.sigConfChanged.emit("phase")
341
+
342
+ def getConfiguration(self) -> dict:
343
+ ddict = self._geometryWidget.getConfiguration()
344
+ ddict.update(self._advancedParamsWidget.getConfiguration())
345
+ ddict["ctf_translations_file"] = self._translationFile.getFile()
346
+ return ddict
347
+
348
+ def setConfiguration(self, ddict):
349
+ self._geometryWidget.setConfiguration(ddict=ddict)
350
+ self._advancedParamsWidget.setConfiguration(ddict=ddict)
351
+ if "ctf_translations_file" in ddict:
352
+ self._translationFile.setFile(ddict["ctf_translations_file"])
@@ -293,12 +293,3 @@ class NabuConfigurationTab(qt.QTabWidget):
293
293
  self._reconstructionWidget.setConfiguration(config["reconstruction"])
294
294
  if "tomwer_slices" in config:
295
295
  self._reconstructionWidget.setSlices(config["tomwer_slices"])
296
-
297
-
298
- if __name__ == "__main__":
299
- app = qt.QApplication([])
300
- widget = NabuConfiguration(None, None)
301
- widget.show()
302
- print(widget.getConfiguration())
303
- print(widget.getSlices())
304
- app.exec_()
@@ -119,7 +119,7 @@ class NabuOutputLocationWidget(qt.QWidget):
119
119
  self._outputDirQLE.setVisible(not hide)
120
120
  self._selectOutputPB.setVisible(not hide)
121
121
 
122
- def _selectOutput(self):
122
+ def _selectOutput(self): # pragma: no cover
123
123
  defaultDirectory = self._outputDirQLE.text()
124
124
  if os.path.isdir(defaultDirectory):
125
125
  defaultDirectory = get_default_directory()
@@ -33,6 +33,7 @@ from tomwer.utils import docstring
33
33
  from silx.gui import qt
34
34
  from tomwer.gui.utils.scrollarea import QComboBoxIgnoreWheel as QComboBox
35
35
  from tomwer.gui.reconstruction.nabu.nabuconfig import base
36
+ from tomwer.gui.reconstruction.nabu.nabuconfig.ctf import CTFConfig
36
37
  from tomwer.gui.utils.inputwidget import SelectionLineEdit
37
38
  from tomwer.core.utils.char import BETA_CHAR, DELTA_CHAR
38
39
  from tomwer.core.process.reconstruction.nabu.utils import _NabuStages, _NabuPhaseMethod
@@ -75,11 +76,15 @@ class _NabuPhaseConfig(qt.QWidget, base._NabuStageConfigBase):
75
76
  self._methodCB = QComboBox(parent=self, scrollArea=scrollArea)
76
77
  for method in _NabuPhaseMethod:
77
78
  self._methodCB.addItem(method.value)
79
+ idx_ctf = self._methodCB.findText(_NabuPhaseMethod.CTF.value)
80
+ self._methodCB.setItemData(
81
+ idx_ctf, "Contrast Transfert Function", qt.Qt.ToolTipRole
82
+ )
78
83
  self.layout().addWidget(self._methodCB, 1, 1, 1, 3)
79
84
  self.registerWidget(self._methodLabel, "required")
80
85
  self.registerWidget(self._methodCB, "required")
81
86
 
82
- # paganin options
87
+ # paganin & ctf options
83
88
  self._paganinOpts = NabuPaganinConfig(parent=self, scrollArea=scrollArea)
84
89
  self.layout().addWidget(self._paganinOpts, 2, 0, 3, 3)
85
90
 
@@ -87,6 +92,11 @@ class _NabuPhaseConfig(qt.QWidget, base._NabuStageConfigBase):
87
92
  self._unsharpOpts = NabuUnsharpConfig(parent=self)
88
93
  self.layout().addWidget(self._unsharpOpts, 6, 0, 3, 3)
89
94
 
95
+ # ctf options
96
+ self._ctfOpts = CTFConfig(parent=self)
97
+ self.layout().addWidget(self._ctfOpts, 9, 0, 3, 4)
98
+ self.registerWidget(self._ctfOpts, "advanced")
99
+
90
100
  # spacer for style
91
101
  spacer = qt.QWidget(self)
92
102
  spacer.setSizePolicy(qt.QSizePolicy.Minimum, qt.QSizePolicy.Expanding)
@@ -101,12 +111,15 @@ class _NabuPhaseConfig(qt.QWidget, base._NabuStageConfigBase):
101
111
  self._methodCB.currentIndexChanged.connect(self._methodChanged)
102
112
  self._paganinOpts.sigConfChanged.connect(self._signalConfChanged)
103
113
  self._unsharpOpts.sigConfChanged.connect(self._signalConfChanged)
114
+ self._ctfOpts.sigConfChanged.connect(self._signalConfChanged)
104
115
 
105
116
  # set up
106
117
  self._paganinOpts.setEnabled(self.getMethod() is not _NabuPhaseMethod.NONE)
118
+ self._ctfOpts.setEnabled(self.getMethod() is _NabuPhaseMethod.CTF)
107
119
 
108
120
  def _methodChanged(self, *args, **kwargs):
109
121
  self._paganinOpts.setEnabled(self.getMethod() is not _NabuPhaseMethod.NONE)
122
+ self._ctfOpts.setEnabled(self.getMethod() is _NabuPhaseMethod.CTF)
110
123
  self._signalConfChanged("method")
111
124
 
112
125
  def _signalConfChanged(self, param):
@@ -129,13 +142,15 @@ class _NabuPhaseConfig(qt.QWidget, base._NabuStageConfigBase):
129
142
  else:
130
143
  _logger.warning("unable to find method {method}")
131
144
  self._unsharpOpts.setConfiguration(config)
145
+ self._ctfOpts.setConfiguration(config)
132
146
 
133
147
  @docstring(base._NabuStageConfigBase)
134
148
  def getConfiguration(self) -> dict:
135
149
  configuration = {"method": self.getMethod().value}
136
- if self.getMethod() is _NabuPhaseMethod.PAGANIN:
150
+ if self.getMethod() in (_NabuPhaseMethod.PAGANIN, _NabuPhaseMethod.CTF):
137
151
  configuration.update(self._paganinOpts.getConfiguration())
138
152
  configuration.update(self._unsharpOpts.getConfiguration())
153
+ configuration.update(self._ctfOpts.getConfiguration())
139
154
  return configuration
140
155
 
141
156
  def setConfigurationLevel(self, level):
@@ -169,22 +184,6 @@ class NabuPaganinConfig(qt.QWidget, base._NabuStageConfigBase):
169
184
  self.registerWidget(self._db_label, "required")
170
185
  self.registerWidget(self._deltaBetaQLE, "required")
171
186
 
172
- # paganin lmicron
173
- # we skip this paramter, only used for compatibility
174
-
175
- # paganin margin
176
- # note: hide for now margin as it is not connected at nabu side
177
- # self.layout().addWidget(qt.QLabel("margin"), 1, 0, 1, 1)
178
- # self._margeQSB = qt.QSpinBox(self)
179
- # self._margeQSB.setMinimum(0)
180
- # self._margeQSB.setMaximum(9999)
181
- # self._margeQSB.setToolTip(
182
- # "Marge (in pixels) in the Paganin filtering "
183
- # "to avoid local tomography artefacts"
184
- # )
185
- # self.layout().addWidget(self._margeQSB, 1, 1, 1, 1)
186
- # self.registerWidget(self._margeQSB, "optional")
187
-
188
187
  # paganin padding_type
189
188
  self._paddingLabel = qt.QLabel("padding", self)
190
189
  self.layout().addWidget(self._paddingLabel, 2, 0, 1, 1)
@@ -192,7 +191,7 @@ class NabuPaganinConfig(qt.QWidget, base._NabuStageConfigBase):
192
191
  self._paddingTypeCB.setToolTip(
193
192
  "Padding type for the filtering step " "in Paganin/CTR."
194
193
  )
195
- for padding_type in (PaddingMode.ZEROS, PaddingMode.ZEROS.EDGE):
194
+ for padding_type in (PaddingMode.ZEROS, PaddingMode.EDGE):
196
195
  self._paddingTypeCB.addItem(padding_type.value)
197
196
  self.layout().addWidget(self._paddingTypeCB, 2, 1, 1, 3)
198
197
  self.registerWidget(self._paddingLabel, "advanced")