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
@@ -10,7 +10,6 @@ from typing import Union
10
10
  from nabu.stitching import config as _nabu_stitching_config
11
11
  from nabu.stitching.config import StitchingType
12
12
  from nabu.stitching.overlap import OverlapStitchingStrategy
13
- from nabu.stitching.utils import ScoreMethod as _NabuScoreMethod
14
13
  from nabu.stitching.utils import ShiftAlgorithm as _NabuShiftAlgorithm
15
14
  from silx.gui import qt
16
15
  from tomoscan.serie import Serie
@@ -39,44 +38,8 @@ class Axis_N_Params(qt.QGroupBox):
39
38
  )
40
39
  self.layout().addRow("image registration method", self._imageRegMethodCB)
41
40
 
42
- # window size
43
- self._windowSize = qt.QSpinBox(self)
44
- self._windowSizeLabel = qt.QLabel(
45
- _nabu_stitching_config.KEY_WINDOW_SIZE.replace("_", " "), self
46
- )
47
- self.layout().addRow(self._windowSizeLabel, self._windowSize)
48
- self._windowSize.setToolTip("research window width to find shifts")
49
-
50
- # score method
51
- self._scoreCB = qt.QComboBox(self)
52
- for score_method in _NabuScoreMethod.values():
53
- self._scoreCB.addItem(score_method)
54
- self._scoreCBLabel = qt.QLabel(
55
- _nabu_stitching_config.KEY_SCORE_METHOD.replace("_", " "), self
56
- )
57
- self.layout().addRow(self._scoreCBLabel, self._scoreCB)
58
- self._windowSize.setToolTip(
59
- "method to use in order to compute score and determine the best shift"
60
- )
61
-
62
- # connect signal / slot
63
- self._imageRegMethodCB.currentTextChanged.connect(self._updatePossibleOpts)
64
-
65
41
  # set up
66
42
  self._imageRegMethodCB.setCurrentText(_NabuShiftAlgorithm.NONE.value)
67
- self._updatePossibleOpts()
68
-
69
- def getWindowSize(self):
70
- return self._windowSize.value()
71
-
72
- def setWindowSize(self, window_size):
73
- return self._windowSize.setValue(int(window_size))
74
-
75
- def getScoreMethod(self):
76
- return _NabuScoreMethod.from_value(self._scoreCB.currentText())
77
-
78
- def setScoreMethod(self, method):
79
- self._scoreCB.setCurrentText(_NabuScoreMethod.from_value(method).value)
80
43
 
81
44
  def getCurrentMethod(self):
82
45
  return _NabuShiftAlgorithm.from_value(self._imageRegMethodCB.currentText())
@@ -89,13 +52,6 @@ class Axis_N_Params(qt.QGroupBox):
89
52
  def getOptsLine(self) -> str:
90
53
  current_method = self.getCurrentMethod()
91
54
  line_ = f"{_nabu_stitching_config.KEY_IMG_REG_METHOD}={current_method.value}"
92
- if current_method is _NabuShiftAlgorithm.SHIFT_GRID:
93
- line_ = ",".join(
94
- (
95
- line_,
96
- f"{_nabu_stitching_config.KEY_WINDOW_SIZE}={self.getWindowSize()},{_nabu_stitching_config.KEY_SCORE_METHOD}={self.getScoreMethod().value}",
97
- )
98
- )
99
55
  return line_
100
56
 
101
57
  def setOptsLine(self, opt_line: str) -> None:
@@ -113,13 +69,6 @@ class Axis_N_Params(qt.QGroupBox):
113
69
  except Exception as e:
114
70
  _logger.error(e)
115
71
 
116
- score_method = opts.get(_nabu_stitching_config.KEY_SCORE_METHOD, None)
117
- if score_method is not None:
118
- try:
119
- self.setScoreMethod(score_method)
120
- except Exception as e:
121
- _logger.error(e)
122
-
123
72
  img_reg_exp_method = opts.get(_nabu_stitching_config.KEY_IMG_REG_METHOD, None)
124
73
  if img_reg_exp_method is not None:
125
74
  try:
@@ -127,15 +76,6 @@ class Axis_N_Params(qt.QGroupBox):
127
76
  except Exception as e:
128
77
  _logger.error(e)
129
78
 
130
- def _updatePossibleOpts(self, *args, **kwargs):
131
- current_method = self.getCurrentMethod()
132
- self._windowSizeLabel.setVisible(
133
- current_method is _NabuShiftAlgorithm.SHIFT_GRID
134
- )
135
- self._windowSize.setVisible(current_method is _NabuShiftAlgorithm.SHIFT_GRID)
136
- self._scoreCBLabel.setVisible(current_method is _NabuShiftAlgorithm.SHIFT_GRID)
137
- self._scoreCB.setVisible(current_method is _NabuShiftAlgorithm.SHIFT_GRID)
138
-
139
79
 
140
80
  class AutoRefineWidget(qt.QWidget):
141
81
  """
@@ -1,39 +1,20 @@
1
- # coding: utf-8
2
- # /*##########################################################################
3
- # Copyright (C) 2017 European Synchrotron Radiation Facility
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the "Software"), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in
13
- # all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- # THE SOFTWARE.
22
- #
23
- #############################################################################*/
24
-
25
1
  """
26
2
  Button of general usage.
27
3
  """
28
4
 
29
- __authors__ = ["H.Payno"]
30
- __license__ = "MIT"
31
- __date__ = "03/10/2018"
32
-
33
-
5
+ import numpy
6
+ import logging
7
+ from typing import Optional, Union
34
8
  from silx.gui import qt
9
+ from silx.gui.plot.tools.roi import RegionOfInterestManager
10
+ from silx.gui.plot.items.roi import LineROI
11
+ from silx.gui.plot.PlotToolButtons import PlotToolButton
35
12
 
36
13
  from tomwer.gui import icons
14
+ from pyunitsystem.metricsystem import MetricSystem
15
+
16
+
17
+ _logger = logging.getLogger(__file__)
37
18
 
38
19
 
39
20
  class PadlockButton(qt.QPushButton):
@@ -100,3 +81,105 @@ class TabBrowsersButtons(qt.QWidget):
100
81
 
101
82
  def _nextReleased(self, *args, **kwargs):
102
83
  self.sigNextReleased.emit()
84
+
85
+
86
+ class TapeMeasureToolButton(PlotToolButton):
87
+ """Button to active measurement between two point of the plot"""
88
+
89
+ class TapeMeasureROI(LineROI):
90
+ def __init__(self, parent=None, pixel_size_m=None):
91
+ super().__init__(parent)
92
+ self._pixel_size_m = None
93
+ self.setPixelSize(pixel_size_m)
94
+
95
+ def setEndPoints(self, startPoint, endPoint):
96
+ distance_px = numpy.linalg.norm(endPoint - startPoint)
97
+ super().setEndPoints(startPoint=startPoint, endPoint=endPoint)
98
+ if self._pixel_size_m is None:
99
+ self._updateText(f"{distance_px :.1f}px")
100
+ else:
101
+ distance_m = distance_px * self._pixel_size_m
102
+ value, unit = MetricSystem.cast_metric_to_best_unit(distance_m)
103
+ self._updateText(f"{distance_px :.1f}px ({value:.2f}{unit})")
104
+
105
+ def setPixelSize(self, pixel_size_m: Optional[Union[tuple, float]]):
106
+ if isinstance(pixel_size_m, (tuple, list)):
107
+ assert (
108
+ len(pixel_size_m) == 2
109
+ ), "expects at most two pixel size values (x and y values)"
110
+ if not numpy.isclose(pixel_size_m[0], pixel_size_m[1]):
111
+ value, unit = MetricSystem.cast_metric_to_best_unit(pixel_size_m[0])
112
+ _logger.warning(
113
+ f"TapeMeasure is only handling square pixels for now. Will consider the pixel is {value:.2f}{unit}x{value:.2f}{unit}"
114
+ )
115
+ pixel_size_m = pixel_size_m[0]
116
+ self._pixel_size_m = pixel_size_m
117
+
118
+ def __init__(self, parent=None, plot=None, pixel_size_mm=None):
119
+ super().__init__(parent=parent, plot=plot)
120
+ self._roiManager = None
121
+ self._lastRoiCreated = None
122
+ self._pixel_sixel_m = pixel_size_mm
123
+ self.setIcon(icons.getQIcon("ruler"))
124
+ self.setToolTip("measure distance between two pixels")
125
+ self.toggled.connect(self._callback)
126
+ self._connectPlot(plot)
127
+
128
+ def setPlot(self, plot):
129
+ return super().setPlot(plot)
130
+
131
+ def setPixelSize(self, pixel_size_m: Optional[Union[tuple, float]]):
132
+ self._pixel_sixel_m = pixel_size_m
133
+
134
+ def _callback(self, toggled):
135
+ if not self._roiManager:
136
+ return
137
+ if self._lastRoiCreated is not None:
138
+ self._lastRoiCreated.setVisible(self.isChecked())
139
+ if self.isChecked():
140
+ self._roiManager.start(
141
+ self.TapeMeasureROI,
142
+ self,
143
+ )
144
+ self.__interactiveModeStarted(self._roiManager)
145
+ else:
146
+ source = self._roiManager.getInteractionSource()
147
+ if source is self:
148
+ self._roiManager.stop()
149
+
150
+ def __interactiveModeStarted(self, roiManager):
151
+ roiManager.sigInteractiveModeFinished.connect(self.__interactiveModeFinished)
152
+
153
+ def __interactiveModeFinished(self):
154
+ roiManager = self._roiManager
155
+ if roiManager is not None:
156
+ roiManager.sigInteractiveModeFinished.disconnect(
157
+ self.__interactiveModeFinished
158
+ )
159
+ self.setChecked(False)
160
+
161
+ def _connectPlot(self, plot):
162
+ """
163
+ Called when the plot is connected to the widget
164
+ :param plot: :class:`.PlotWidget` instance
165
+ """
166
+ if plot is None:
167
+ return
168
+ self._roiManager = RegionOfInterestManager(plot)
169
+ self._roiManager.setColor("yellow") # Set the color of ROI
170
+ self._roiManager.sigRoiAdded.connect(self._registerCurrentROI)
171
+
172
+ def _disconnectPlot(self, plot):
173
+ if plot and self._lastRoiCreated is not None:
174
+ self._roiManager.removeRoi(self._lastRoiCreated)
175
+ self._lastRoiCreated = None
176
+ return super()._disconnectPlot(plot)
177
+
178
+ def _registerCurrentROI(self, currentRoi):
179
+ if self._lastRoiCreated is None:
180
+ self._lastRoiCreated = currentRoi
181
+ self._lastRoiCreated.setPixelSize(self._pixel_sixel_m)
182
+ elif currentRoi != self._lastRoiCreated and self._roiManager is not None:
183
+ self._roiManager.removeRoi(self._lastRoiCreated)
184
+ self._lastRoiCreated = currentRoi
185
+ self._lastRoiCreated.setPixelSize(self._pixel_sixel_m)
@@ -28,7 +28,7 @@ __date__ = "16/08/2018"
28
28
 
29
29
  import logging
30
30
  import os
31
- from typing import Optional
31
+ from typing import Optional, Union
32
32
 
33
33
  import numpy
34
34
  from nxtomomill.io.config import TomoEDFConfig as EDFConfig
@@ -41,7 +41,7 @@ from tomwer.gui import icons
41
41
  from tomwer.gui.qlefilesystem import QLFileSystem
42
42
  from tomwer.io.utils import get_default_directory
43
43
  from tomwer.core.volume.volumefactory import VolumeFactory
44
- from tomwer.core.process.control.nxtomomill import NXtomomillNXDefaultOutput
44
+ from tomwer.core.process.output import ProcessDataOutputDirMode
45
45
 
46
46
  from tomwer.core.volume import (
47
47
  EDFVolume,
@@ -271,42 +271,49 @@ class NXTomomillOutputDirSelector(qt.QWidget):
271
271
  self.__buttonGroup.setExclusive(True)
272
272
 
273
273
  tooltip = """Define the output directory of the nexus (.nx) file. Options are:
274
- \n - next to bliss file: create the NXtomos at the same level as the bliss input file
274
+ \n - same folder as scan: create the NXtomos at the same level as the bliss input file or spec folder
275
+ \n - 'RAW_DATA' folder: create NXtomos on the default 'RAW_DATA' folder (bliss default folder, nearby the 'raw' folder).
275
276
  \n - 'PROCESSED_DATA' folder: create NXtomos on the default 'PROCESSED_DATA' folder (bliss default folder, nearby the 'raw' folder).
276
277
  \n - user defined folder: users can provide their own folders using keywords for string formatting such as 'scan_dir_name', 'scan_basename' or 'scan_parent_dir_basename'
277
278
  """
278
279
 
279
280
  # output dir is the folder containing the .nx file
280
- self._closeToBlissFileRB = qt.QRadioButton("near input file", self)
281
- self._closeToBlissFileRB.setToolTip(tooltip)
282
- self.layout().addWidget(self._closeToBlissFileRB, 0, 0, 1, 1)
283
- self.__buttonGroup.addButton(self._closeToBlissFileRB)
281
+ self._inScanFolder = qt.QRadioButton("same folder as scan", self)
282
+ self._inScanFolder.setToolTip(tooltip)
283
+ self.layout().addWidget(self._inScanFolder, 0, 0, 1, 1)
284
+ self.__buttonGroup.addButton(self._inScanFolder)
284
285
  # output dir is the default 'reduced'folder
285
286
  self._processedDataFolderRB = qt.QRadioButton("'PROCESSED_DATA' folder", self)
286
287
  self._processedDataFolderRB.setToolTip(tooltip)
287
288
  self.layout().addWidget(self._processedDataFolderRB, 1, 0, 1, 1)
288
289
  self.__buttonGroup.addButton(self._processedDataFolderRB)
290
+ # output dir is the default 'reduced'folder
291
+ self._rawDataFolderRB = qt.QRadioButton("'RAW_DATA' folder", self)
292
+ self._rawDataFolderRB.setToolTip(tooltip)
293
+ self.layout().addWidget(self._rawDataFolderRB, 2, 0, 1, 1)
294
+ self.__buttonGroup.addButton(self._rawDataFolderRB)
289
295
  # manual
290
296
  self._manualRB = qt.QRadioButton("custom output directory", self)
291
297
  self._manualRB.setToolTip(tooltip)
292
- self.layout().addWidget(self._manualRB, 2, 0, 1, 1)
298
+ self.layout().addWidget(self._manualRB, 3, 0, 1, 1)
293
299
  self._outputFolderQLE = QLFileSystem("", self)
294
- self.layout().addWidget(self._outputFolderQLE, 2, 1, 1, 1)
300
+ self.layout().addWidget(self._outputFolderQLE, 3, 1, 1, 1)
295
301
  self._selectButton = qt.QPushButton("", self)
296
302
  style = qt.QApplication.style()
297
303
  icon_opendir = style.standardIcon(qt.QStyle.SP_DirOpenIcon)
298
304
  self._selectButton.setIcon(icon_opendir)
299
305
  self._selectButton.setToolTip("select output directory")
300
- self.layout().addWidget(self._selectButton, 2, 2, 1, 1)
306
+ self.layout().addWidget(self._selectButton, 3, 2, 1, 1)
301
307
  self.__buttonGroup.addButton(self._manualRB)
302
308
 
303
309
  # connect signal / slot
304
310
  self._selectButton.released.connect(self._selectOutpuFolder)
305
311
  self.__buttonGroup.buttonReleased.connect(self._updateVisiblity)
306
- self._closeToBlissFileRB.toggled.connect(self._outputDirChanged)
307
- self._processedDataFolderRB.toggled.connect(self._outputDirChanged)
308
- self._manualRB.toggled.connect(self._outputDirChanged)
309
- self._outputFolderQLE.editingFinished.connect(self._outputDirChanged)
312
+ self._inScanFolder.toggled.connect(self.sigChanged)
313
+ self._processedDataFolderRB.toggled.connect(self.sigChanged)
314
+ self._rawDataFolderRB.toggled.connect(self.sigChanged)
315
+ self._manualRB.toggled.connect(self.sigChanged)
316
+ self._outputFolderQLE.editingFinished.connect(self.sigChanged)
310
317
 
311
318
  # set up
312
319
  self._processedDataFolderRB.setChecked(True)
@@ -316,9 +323,6 @@ class NXTomomillOutputDirSelector(qt.QWidget):
316
323
  self._selectButton.setVisible(self._manualRB.isChecked())
317
324
  self._outputFolderQLE.setVisible(self._manualRB.isChecked())
318
325
 
319
- def _outputDirChanged(self):
320
- self.sigChanged.emit()
321
-
322
326
  def _selectOutpuFolder(self): # pragma: no cover
323
327
  defaultDirectory = self._outputFolderQLE.text()
324
328
  if os.path.isdir(defaultDirectory):
@@ -334,13 +338,15 @@ class NXTomomillOutputDirSelector(qt.QWidget):
334
338
  self._outputFolderQLE.setText(dialog.selectedFiles()[0])
335
339
  self.sigChanged.emit()
336
340
 
337
- def getOutputFolder(self) -> str:
341
+ def getOutputFolder(self) -> Union[str, ProcessDataOutputDirMode]:
338
342
  if self._manualRB.isChecked():
339
343
  return self._outputFolderQLE.text()
340
344
  elif self._processedDataFolderRB.isChecked():
341
- return NXtomomillNXDefaultOutput.PROCESSED_DATA.value
342
- elif self._closeToBlissFileRB.isChecked():
343
- return NXtomomillNXDefaultOutput.NEAR_INPUT_FILE.value
345
+ return ProcessDataOutputDirMode.PROCESSED_DATA_FOLDER
346
+ elif self._inScanFolder.isChecked():
347
+ return ProcessDataOutputDirMode.IN_SCAN_FOLDER
348
+ elif self._rawDataFolderRB.isChecked():
349
+ return ProcessDataOutputDirMode.RAW_DATA_FOLDER
344
350
  else:
345
351
  raise RuntimeError("Use case - h52nx output dir - not handled")
346
352
 
@@ -348,15 +354,17 @@ class NXTomomillOutputDirSelector(qt.QWidget):
348
354
  old = self.blockSignals(True)
349
355
  self._manualRB.setChecked(output_folder is not None)
350
356
  try:
351
- default_output = NXtomomillNXDefaultOutput.from_value(output_folder)
357
+ default_output = ProcessDataOutputDirMode.from_value(output_folder)
352
358
  except ValueError:
353
359
  self._outputFolderQLE.setText(output_folder)
354
360
  self._manualRB.setChecked(True)
355
361
  else:
356
- if default_output is NXtomomillNXDefaultOutput.NEAR_INPUT_FILE:
362
+ if default_output is ProcessDataOutputDirMode.IN_SCAN_FOLDER:
357
363
  self._processedDataFolderRB.setChecked(True)
358
- elif default_output is NXtomomillNXDefaultOutput.PROCESSED_DATA:
359
- self._closeToBlissFileRB.setChecked(True)
364
+ elif default_output is ProcessDataOutputDirMode.PROCESSED_DATA_FOLDER:
365
+ self._inScanFolder.setChecked(True)
366
+ elif default_output is ProcessDataOutputDirMode.RAW_DATA_FOLDER:
367
+ self._rawDataFolderRB.setChecked(True)
360
368
  else:
361
369
  raise ValueError(f"default output not handled ({default_output})")
362
370
  finally:
@@ -64,6 +64,10 @@ class ScanNameLabelAndShape(qt.QWidget):
64
64
  def setScan(self, scan: Optional[TomwerScanBase]):
65
65
  if scan is None or scan.path is None:
66
66
  self.clear()
67
+ elif not isinstance(scan, TomwerScanBase):
68
+ raise TypeError(
69
+ f"Scan is expected to be an instance of {TomwerScanBase}. Get {type(scan)} instead"
70
+ )
67
71
  else:
68
72
  assert isinstance(scan, TomwerScanBase)
69
73
  self._scanNameLabel.setText(scan.get_identifier().short_description())
@@ -0,0 +1,144 @@
1
+ import functools
2
+ from silx.gui import qt
3
+ from typing import Optional, Union
4
+ from tomwer.gui.utils.qt_utils import block_signals
5
+
6
+
7
+ class StepSizeSelectorWidget(qt.QGroupBox):
8
+ """
9
+ Widget to define some steps size (as float). Used by the Axis and the AxisOrdered widgets
10
+
11
+ :param str title: title to provide to the group box
12
+ :param str label: text for the label set at the left of the QLineEdit
13
+ :param fine_value: (optional) value to provide for 'fine' step
14
+ :param medium_value: (optional) value to provide for 'medium' step
15
+ :param rough_value: (optional) value to provide for 'rough' step
16
+ :param dtype: type of the step. Can be int or float
17
+ """
18
+
19
+ valueChanged = qt.Signal()
20
+
21
+ def __init__(
22
+ self,
23
+ parent=None,
24
+ title="",
25
+ label: str = "step size",
26
+ fine_value: [float, int, None] = 0.1,
27
+ medium_value: [float, int, None] = 0.5,
28
+ rough_value: [float, int, None] = 1.0,
29
+ unit: Optional[str] = "px",
30
+ dtype: Union[int, float] = float,
31
+ ):
32
+ assert fine_value is None or isinstance(
33
+ fine_value, dtype
34
+ ), f"fine_value is expected to be None or a {dtype}. Get {type(fine_value)}"
35
+ assert medium_value is None or isinstance(
36
+ medium_value, dtype
37
+ ), f"medium_value is expected to be None or a {dtype}. Get {type(medium_value)}"
38
+ assert rough_value is None or isinstance(
39
+ rough_value, dtype
40
+ ), f"rough_value is expected to be None or a {dtype}. Get {type(rough_value)}"
41
+ super().__init__(title, parent)
42
+ self._dtype = dtype
43
+ if unit is None:
44
+ unit = ""
45
+ else:
46
+ unit = f" {unit}"
47
+ self.setLayout(qt.QGridLayout())
48
+ self.layout().setSpacing(2)
49
+
50
+ # label
51
+ self.layout().addWidget(qt.QLabel(label), 0, 0, 3, 1)
52
+
53
+ # QLE manual step size
54
+ default_value = medium_value or fine_value or rough_value
55
+ self._manualLE = qt.QLineEdit(str(default_value), parent=self)
56
+ if dtype is float:
57
+ validator = qt.QDoubleValidator(parent=self._manualLE, decimals=2)
58
+ validator.setBottom(0.0)
59
+ elif dtype is int:
60
+ validator = qt.QIntValidator(parent=self._manualLE)
61
+ validator.setBottom(0)
62
+ else:
63
+ raise ValueError("dtype is expected to be int or float")
64
+ self._manualLE.setValidator(validator)
65
+ self.layout().addWidget(self._manualLE, 0, 1, 3, 1)
66
+
67
+ # buttons
68
+ buttons_font = self.font()
69
+ buttons_font.setPixelSize(10)
70
+ self._expectedValues = {}
71
+ # for each button associate the expected value
72
+
73
+ # fine
74
+ if fine_value is not None:
75
+ self._fineButton = qt.QPushButton(f"fine ({fine_value}{unit})", parent=self)
76
+ self._fineButton.setCheckable(True)
77
+ self._fineButton.setFont(buttons_font)
78
+ self.layout().addWidget(self._fineButton, 0, 2, 1, 1)
79
+ self._fineButton.released.connect(
80
+ functools.partial(self.setStepSize, fine_value)
81
+ )
82
+ self._expectedValues[self._fineButton] = fine_value
83
+ else:
84
+ self._fineButton = None
85
+
86
+ # medium
87
+ if medium_value is not None:
88
+ self._mediumButton = qt.QPushButton(
89
+ f"medium ({medium_value}{unit})", parent=self
90
+ )
91
+ self._mediumButton.setCheckable(True)
92
+ self._mediumButton.setFont(buttons_font)
93
+ self.layout().addWidget(self._mediumButton, 1, 2, 1, 1)
94
+ self._mediumButton.released.connect(
95
+ functools.partial(self.setStepSize, medium_value)
96
+ )
97
+ self._expectedValues[self._mediumButton] = medium_value
98
+ else:
99
+ self._mediumButton = None
100
+
101
+ # rough
102
+ if rough_value is not None:
103
+ self._roughButton = qt.QPushButton(
104
+ f"rough ({rough_value}{unit})", parent=self
105
+ )
106
+ self._roughButton.setCheckable(True)
107
+ self._roughButton.setFont(buttons_font)
108
+ self.layout().addWidget(self._roughButton, 2, 2, 1, 1)
109
+ self._roughButton.released.connect(
110
+ functools.partial(self.setStepSize, rough_value)
111
+ )
112
+ self._expectedValues[self._roughButton] = rough_value
113
+ else:
114
+ self._roughButton = None
115
+
116
+ # connect signal / slot
117
+ self._manualLE.textChanged.connect(self._updateButtonChecked)
118
+ self._manualLE.textChanged.connect(self.valueChanged)
119
+ # set up
120
+ self._updateButtonChecked(self._manualLE.text())
121
+
122
+ def _updateButtonChecked(self, text):
123
+ if text == "":
124
+ return
125
+ current_value = self._dtype(text)
126
+ for button, activation_value in self._expectedValues.items():
127
+ with block_signals(button):
128
+ button.setChecked(activation_value == current_value)
129
+
130
+ def getStepSize(self) -> Union[float, int]:
131
+ """
132
+
133
+ :return: displacement shift defined
134
+ :rtype: float
135
+ """
136
+ return self._dtype(self._manualLE.text())
137
+
138
+ def setStepSize(self, value: Union[float, int]):
139
+ """
140
+
141
+ :param float value: shift step
142
+ """
143
+ assert isinstance(value, self._dtype)
144
+ self._manualLE.setText(str(value))
@@ -35,7 +35,7 @@ __date__ = "21/09/2018"
35
35
  import logging
36
36
 
37
37
  from silx.gui import qt
38
- from tomoscan.unitsystem import metricsystem
38
+ from pyunitsystem import metricsystem
39
39
 
40
40
  from tomwer.core.utils.char import MU_CHAR
41
41
 
@@ -64,10 +64,7 @@ class PixelEntry(qt.QWidget):
64
64
  self.layout().addWidget(self._qlePixelSize)
65
65
 
66
66
  # connect signal / slot
67
- self._qlePixelSize.editingFinished.connect(self._callbackEditingFinished)
68
-
69
- def _callbackEditingFinished(self):
70
- self.valueChanged.emit()
67
+ self._qlePixelSize.editingFinished.connect(self.valueChanged)
71
68
 
72
69
  def getValue(self):
73
70
  if self._qlePixelSize.text() in ("unknown", ""):