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
@@ -31,7 +31,7 @@ __date__ = "15/09/2017"
31
31
  import logging
32
32
  from silx.gui import qt
33
33
  from silx.gui.plot import PlotWidget
34
- from typing import Union
34
+ from typing import Union, Optional
35
35
  from collections.abc import Iterable
36
36
  from collections import OrderedDict
37
37
  import numpy
@@ -50,7 +50,6 @@ class QSliceSelectorDialog(qt.QDialog):
50
50
 
51
51
  def __init__(self, parent, n_required_slice=None):
52
52
  qt.QDialog.__init__(self, parent=parent)
53
- self.__selection = None
54
53
  self.setLayout(qt.QVBoxLayout())
55
54
  self.setWindowTitle("select slices on radio")
56
55
 
@@ -87,14 +86,11 @@ class QSliceSelectorDialog(qt.QDialog):
87
86
  selection = selection.replace(")", "")
88
87
  selection = selection.replace(" ", "")
89
88
  selection = selection.replace(",", ";")
90
- self.__selection = []
91
- for val in selection.split(";"):
92
- try:
93
- self.__selection.append(int(val))
94
- except ValueError:
95
- pass
96
- else:
97
- self.__selection = selection
89
+ try:
90
+ selection = [int(item) for item in selection.split(";")]
91
+ except Exception as e:
92
+ logger.error(f"Fail to set selection. Error is {e}")
93
+ self.mainWidget.setSelection(selection)
98
94
 
99
95
  def getSelection(self) -> tuple:
100
96
  """
@@ -102,7 +98,7 @@ class QSliceSelectorDialog(qt.QDialog):
102
98
  :return: the selection of slices to use
103
99
  :rtype: tuple
104
100
  """
105
- return self.__selection
101
+ return self.mainWidget.getSelection()
106
102
 
107
103
  def exec_(self):
108
104
  if not self.mainWidget._has_data:
@@ -111,13 +107,9 @@ class QSliceSelectorDialog(qt.QDialog):
111
107
  qt.QMessageBox.warning(self, "Selection tool not available", mess)
112
108
  self.reject()
113
109
  else:
114
- self.mainWidget.setSelection(self.__selection)
115
- res = qt.QDialog.exec_(self)
116
- if res == qt.QDialog.Accepted:
117
- self.setSelection(self.mainWidget.getSelection())
118
- return res
110
+ return qt.QDialog.exec_(self)
119
111
 
120
- def nRequiredSlice(self) -> Union[None, int]:
112
+ def nRequiredSlice(self) -> Optional[int]:
121
113
  return self.mainWidget.nRequiredSlice()
122
114
 
123
115
 
@@ -139,7 +131,7 @@ class QLineSelector(qt.QWidget):
139
131
  # connect signal / slot
140
132
  self._plot.sigPlotSignal.connect(self._plotDrawEvent)
141
133
 
142
- def nRequiredSlice(self) -> Union[None, int]:
134
+ def nRequiredSlice(self) -> Optional[int]:
143
135
  return self._n_required_slice
144
136
 
145
137
  def setData(self, data: numpy.ndarray):
@@ -160,7 +152,7 @@ class QLineSelector(qt.QWidget):
160
152
  :rtype: tuple
161
153
  """
162
154
  res = []
163
- for legend, marker in self.__selection.items():
155
+ for _, marker in self.__selection.items():
164
156
  res.append(int(marker.getPoints()[0][1]))
165
157
  return tuple(sorted(res))
166
158
 
@@ -200,8 +192,8 @@ class QLineSelector(qt.QWidget):
200
192
  logger.warning("requested slice out of the data, ignored")
201
193
  return
202
194
 
203
- while self.nSelected() >= self.nRequiredSlice():
204
- self.removeSlice(row=int(list(self.__selection.items())[0][0]))
195
+ # while self.nSelected() >= self.nRequiredSlice():
196
+ # self.removeSlice(row=int(list(self.__selection.items())[0][0]))
205
197
 
206
198
  inf = 10000
207
199
  legend = self._getLegend(row_n=row_n)
@@ -29,8 +29,6 @@ __date__ = "04/02/2020"
29
29
 
30
30
  from typing import Optional
31
31
  from silx.gui import qt
32
- import os
33
-
34
32
  from tomwer.core.scan.scanbase import TomwerScanBase
35
33
 
36
34
 
@@ -66,8 +64,8 @@ class ScanNameLabelAndShape(qt.QWidget):
66
64
  self.clear()
67
65
  else:
68
66
  assert isinstance(scan, TomwerScanBase)
69
- self._scanNameLabel.setText(os.path.basename(scan.path))
70
- self._scanNameLabel.setToolTip(scan.path)
67
+ self._scanNameLabel.setText(scan.get_identifier().short_description())
68
+ self._scanNameLabel.setToolTip(scan.get_identifier().to_str())
71
69
 
72
70
  shape_x = scan.dim_1 if scan.dim_1 is not None else "?"
73
71
  shape_y = scan.dim_2 if scan.dim_2 is not None else "?"
@@ -29,8 +29,8 @@ __license__ = "MIT"
29
29
  __date__ = "17/02/2021"
30
30
 
31
31
 
32
- from silx.gui import qt
33
32
  import numpy
33
+ from silx.gui import qt
34
34
 
35
35
 
36
36
  class LogSlider(qt.QWidget):
@@ -92,104 +92,3 @@ class LogSlider(qt.QWidget):
92
92
 
93
93
  def setValue(self, value):
94
94
  self._valueQBSB.setValue(value)
95
-
96
-
97
- class _TickBar(qt.QWidget):
98
- _FONT_SIZE = 6
99
-
100
- def __init__(self, parent=None):
101
- qt.QWidget.__init__(self, parent)
102
- self._min = 1
103
- self._max = 100
104
- self._ticks = {}
105
-
106
- def setRange(self, min_, max_):
107
- self._min = min_
108
- self._max = max_
109
- tick_names = self._ticks.values()
110
- for tick_name in tick_names:
111
- tick_value = self._ticks[tick_name]
112
- self._ticks[tick_name] = min(max(self._min, tick_value), self._max)
113
-
114
- def addTick(self, name, value):
115
- value = min(max(self._valueQBSB.minimum(), value), self._valueQBSB.maximum())
116
- self._ticks[name] = value
117
-
118
- def paintEvent(self, event):
119
- painter = qt.QPainter(self)
120
- font = painter.font()
121
- font.setPixelSize(_TickBar._FONT_SIZE)
122
- painter.setFont(font)
123
-
124
- # paint ticks
125
- for tick_name, tick_value in self._ticks.items():
126
- self._paintTick(tick_value, painter, majorTick=True)
127
-
128
- def _getRelativePosition(self, val):
129
- """Return the relative position of val according to min and max value"""
130
- if self._normalizer is None:
131
- return 0.0
132
- normMin, normMax, normVal = self._normalizer.apply(
133
- [self._vmin, self._vmax, val], self._vmin, self._vmax
134
- )
135
-
136
- if normMin == normMax:
137
- return 0.0
138
- else:
139
- return 1.0 - (normVal - normMin) / (normMax - normMin)
140
-
141
- def _paintTick(self, val, painter, majorTick=True):
142
- """
143
-
144
- :param bool majorTick: if False will never draw text and will set a line
145
- with a smaller width
146
- """
147
- fm = qt.QFontMetrics(painter.font())
148
- viewportHeight = self.rect().height() - self.margin * 2 - 1
149
- relativePos = self._getRelativePosition(val)
150
- height = int(viewportHeight * relativePos + self.margin)
151
- lineWidth = _TickBar._LINE_WIDTH
152
- if majorTick is False:
153
- lineWidth /= 2
154
-
155
- painter.drawLine(
156
- qt.QLine(int(self.width() - lineWidth), height, self.width(), height)
157
- )
158
-
159
- if self.displayValues and majorTick is True:
160
- painter.drawText(
161
- qt.QPoint(0, int(height + fm.height() / 2)), self.form.format(val)
162
- )
163
-
164
-
165
- class LogSliderWithTick(LogSlider):
166
- def __init__(self, parent=None):
167
- super().__init__(parent=parent)
168
- # register ticks to be displayed with name as key and value as value
169
- # Double spin box
170
- self._ticksBar = _TickBar(self)
171
- self.layout().addWidget(self._ticksBar, 1, 0, 1, 1)
172
-
173
- def addTick(self, name, value):
174
- self._ticksBar.addTick(name, value)
175
-
176
- def setRange(self, min_: float, max_: float) -> None:
177
- super().setRange(min_=min_, max_=max_)
178
- if hasattr(self, "_ticksBar"):
179
- self._ticksBar.setRange(min_=min_, max_=max_)
180
-
181
- def clearTicks(self):
182
- self._ticks.clear()
183
-
184
-
185
- if __name__ == "__main__":
186
- app = qt.QApplication([])
187
- slider = LogSliderWithTick()
188
- slider.setFixedWidth(250)
189
- # slider.addTick("toto", 1)
190
- # slider.addTick("tata", 10)
191
- # slider.addTick("titi", 100)
192
- slider.setRange(0.01, 1000)
193
- slider.setValue(10)
194
- slider.show()
195
- app.exec_()
@@ -34,6 +34,7 @@ __date__ = "21/09/2018"
34
34
 
35
35
  from silx.gui import qt
36
36
  from tomoscan.unitsystem import metricsystem
37
+ from tomwer.core.utils.char import MU_CHAR
37
38
  import logging
38
39
 
39
40
  _logger = logging.getLogger(__name__)
@@ -48,8 +49,20 @@ class MetricEntry(qt.QWidget):
48
49
  :param str: base_unit. Default way to present a value when setted
49
50
  """
50
51
 
52
+ class DoubleValidator(qt.QDoubleValidator):
53
+ def __init__(self, *args, **kwargs):
54
+ super().__init__(*args, **kwargs)
55
+ self.setNotation(qt.QDoubleValidator.ScientificNotation)
56
+
57
+ def validate(self, a0: str, a1: int):
58
+ if a0 == "unknown":
59
+ return (qt.QDoubleValidator.Acceptable, a0, a1)
60
+ else:
61
+ return super().validate(a0, a1)
62
+
51
63
  _CONVERSION = {
52
64
  "nm": metricsystem.nanometer.value,
65
+ f"{MU_CHAR}m": metricsystem.micrometer.value,
53
66
  "mm": metricsystem.millimeter.value,
54
67
  "cm": metricsystem.centimeter.value,
55
68
  "m": metricsystem.meter.value,
@@ -58,24 +71,29 @@ class MetricEntry(qt.QWidget):
58
71
  def __init__(self, name, default_unit="m", parent=None):
59
72
  qt.QWidget.__init__(self, parent)
60
73
  assert type(default_unit) is str
61
- assert default_unit in ("nm", "mm", "cm", "m")
74
+ assert default_unit in ("nm", "mm", "cm", "m", f"{MU_CHAR}m")
62
75
  self._base_unit = default_unit
63
76
 
64
77
  self.setLayout(qt.QHBoxLayout())
65
78
  self._label = qt.QLabel(name, parent=self)
66
79
  self.layout().addWidget(self._label)
67
80
  self._qlePixelSize = qt.QLineEdit("0.0", parent=self)
68
- self._qlePixelSize.setValidator(qt.QDoubleValidator(self._qlePixelSize))
81
+ self._qlePixelSize.setValidator(self.DoubleValidator(self._qlePixelSize))
69
82
  self.layout().addWidget(self._qlePixelSize)
70
83
 
71
84
  self._qcbUnit = qt.QComboBox(parent=self)
72
85
  self._qcbUnit.addItem("nm")
86
+ self._qcbUnit.addItem(f"{MU_CHAR}m")
73
87
  self._qcbUnit.addItem("mm")
74
88
  self._qcbUnit.addItem("cm")
75
89
  self._qcbUnit.addItem("m")
76
90
  self.layout().addWidget(self._qcbUnit)
77
91
  self._resetBaseUnit()
78
92
 
93
+ def setReadOnly(self, a0: bool):
94
+ self._qlePixelSize.setReadOnly(a0)
95
+ self._qcbUnit.setEnabled(not a0)
96
+
79
97
  def getCurrentUnit(self):
80
98
  assert self._qcbUnit.currentText() in self._CONVERSION
81
99
  return self._CONVERSION[self._qcbUnit.currentText()]
@@ -86,14 +104,22 @@ class MetricEntry(qt.QWidget):
86
104
  :param float value: pixel size in international metric system (meter)
87
105
  """
88
106
  _value = value
89
- if type(_value) is str:
90
- try:
91
- _value = float(_value)
92
- except Exception as error:
93
- raise ValueError("Given string does not represent a float", error)
94
- return
95
- assert isinstance(_value, float)
96
- self._qlePixelSize.setText(str(_value))
107
+ if _value in (None, "unknown"):
108
+ txt = "unknown"
109
+ elif isinstance(_value, str):
110
+ if "..." in _value:
111
+ txt = _value
112
+ else:
113
+ try:
114
+ _value = float(_value)
115
+ except Exception as error:
116
+ raise ValueError("Given string does not represent a float", error)
117
+ else:
118
+ assert isinstance(_value, float)
119
+ txt = str(_value)
120
+ else:
121
+ txt = str(_value)
122
+ self._qlePixelSize.setText(txt)
97
123
  self._resetBaseUnit()
98
124
 
99
125
  def _resetBaseUnit(self):
@@ -110,7 +136,18 @@ class MetricEntry(qt.QWidget):
110
136
  :return: the value in meter
111
137
  :rtype: float
112
138
  """
113
- return float(self._qlePixelSize.text()) * self.getCurrentUnit()
139
+ if self._qlePixelSize.text() in ("unknown", ""):
140
+ return None
141
+ else:
142
+ return float(self._qlePixelSize.text()) * self.getCurrentUnit()
143
+
144
+ def setValidator(self, validator):
145
+ self._qlePixelSize.setValidator(validator)
146
+
147
+ def setUnit(self, unit):
148
+ unit = str(metricsystem.MetricSystem.from_value(unit))
149
+ idx = self._qcbUnit.findText(unit)
150
+ self._qcbUnit.setCurrentIndex(idx)
114
151
 
115
152
 
116
153
  class CentimeterEntry(MetricEntry):
@@ -45,14 +45,14 @@ from tomwer.core.volume.volumefactory import VolumeFactory
45
45
 
46
46
  try:
47
47
  from PIL import Image
48
- except ImportError:
49
- has_PIL = False
48
+ except ImportError: # pragma: no cover
49
+ has_PIL = False # pragma: no cover
50
50
  else:
51
51
  has_PIL = True
52
52
  try:
53
- import cv2
54
- except ImportError:
55
- has_cv2 = False
53
+ import cv2 # pragma: no cover
54
+ except ImportError: # pragma: no cover
55
+ has_cv2 = False # pragma: no cover
56
56
  else:
57
57
  has_cv2 = True
58
58
  import numpy
@@ -97,8 +97,10 @@ class DataViewer(qt.QMainWindow):
97
97
  self._controls = DisplayControl(parent=self)
98
98
  self._controlsDW = qt.QDockWidget(self)
99
99
  self._controlsDW.setWidget(self._controls)
100
- self._controlsDW.setFeatures(qt.QDockWidget.DockWidgetMovable)
100
+ self._controlsDW.setWindowTitle("infos")
101
101
  self.addDockWidget(qt.Qt.TopDockWidgetArea, self._controlsDW)
102
+ self._controlsDW.setTitleBarWidget(qt.QWidget(self))
103
+ self._controlsDW.setFloating(False)
102
104
 
103
105
  # connect signal / slot
104
106
  self._controls.sigDisplayModeChanged.connect(self._updateDisplay)
@@ -220,6 +222,12 @@ class DataViewer(qt.QMainWindow):
220
222
  elif self.getDisplayMode() is _DisplayMode.FLATS:
221
223
  self._viewer.setNormalizationFct(None)
222
224
  slices = self._scan().flats
225
+ elif self.getDisplayMode() is _DisplayMode.REDUCED_DARKS:
226
+ self._viewer.setNormalizationFct(None)
227
+ slices = self._scan().load_reduced_darks(return_as_url=True)
228
+ elif self.getDisplayMode() is _DisplayMode.REDUCED_FLATS:
229
+ self._viewer.setNormalizationFct(None)
230
+ slices = self._scan().load_reduced_flats(return_as_url=True)
223
231
  else:
224
232
  raise ValueError("DisplayMode should be RADIOS or SLICES")
225
233
 
@@ -250,8 +258,10 @@ class DataViewer(qt.QMainWindow):
250
258
  class _DisplayMode(_Enum):
251
259
  RADIOS = "projections-radios"
252
260
  SLICES = "slices"
253
- DARKS = "darks"
254
- FLATS = "flats"
261
+ DARKS = "raw darks"
262
+ FLATS = "raw flats"
263
+ REDUCED_DARKS = "reduced darks"
264
+ REDUCED_FLATS = "reduced flats"
255
265
 
256
266
 
257
267
  class _RadioMode(_Enum):
@@ -372,9 +382,12 @@ class DisplayControl(qt.QWidget):
372
382
  config = mode, self.getRadioOption()
373
383
  elif mode is _DisplayMode.SLICES:
374
384
  config = mode, self.getSliceOption()
375
- elif mode is _DisplayMode.DARKS:
376
- config = mode, None
377
- elif mode is _DisplayMode.FLATS:
385
+ elif mode in (
386
+ _DisplayMode.DARKS,
387
+ _DisplayMode.FLATS,
388
+ _DisplayMode.REDUCED_DARKS,
389
+ _DisplayMode.REDUCED_FLATS,
390
+ ):
378
391
  config = mode, None
379
392
  else:
380
393
  raise ValueError("mode should be RADIOS or SLICES")
@@ -544,12 +557,6 @@ class _TomwerUrlLoader(UrlLoader):
544
557
  Thread use to load DataUrl
545
558
  """
546
559
 
547
- def __init__(self, parent, url):
548
- super(UrlLoader, self).__init__(parent=parent)
549
- assert isinstance(url, DataUrl)
550
- self.url = url
551
- self.data = None
552
-
553
560
  def run(self):
554
561
  if self.url.file_path().endswith(".vol"):
555
562
  self.data = self._load_vol()
@@ -358,6 +358,7 @@ class DiffFrameViewer(qt.QMainWindow):
358
358
  self._framesSelector.setContentsMargins(0, 0, 0, 0)
359
359
  self._framesSelector.layout().setContentsMargins(0, 0, 0, 0)
360
360
  self._framesSelectorDW = qt.QDockWidget(parent=self)
361
+ self._framesSelectorDW.setWindowTitle("inputs")
361
362
  self._framesSelectorDW.setWidget(self._framesSelector)
362
363
  self._framesSelectorDW.setFeatures(qt.QDockWidget.DockWidgetMovable)
363
364
  self.addDockWidget(qt.Qt.TopDockWidgetArea, self._framesSelectorDW)
@@ -369,6 +370,7 @@ class DiffFrameViewer(qt.QMainWindow):
369
370
  self._shiftDW = qt.QDockWidget(parent=self)
370
371
  self._shiftDW.setWidget(self._shiftsWidget)
371
372
  self._shiftDW.setFeatures(qt.QDockWidget.DockWidgetMovable)
373
+ self._shiftDW.setWindowTitle("shifts")
372
374
  self.addDockWidget(qt.Qt.BottomDockWidgetArea, self._shiftDW)
373
375
 
374
376
  # define central widget
@@ -387,13 +389,6 @@ class DiffFrameViewer(qt.QMainWindow):
387
389
  toolbar.setFloatable(False)
388
390
  self.addToolBar(qt.Qt.TopToolBarArea, toolbar)
389
391
 
390
- # add filtering
391
- style = qt.QApplication.instance().style()
392
- icon = style.standardIcon(qt.QStyle.SP_DialogResetButton)
393
- self._clearAction = qt.QAction(icon, "Clear", toolbar)
394
- toolbar.addAction(self._clearAction)
395
- self._clearAction.triggered.connect(self.clear)
396
-
397
392
  # set up
398
393
  self._mainWidget.setAutoResetZoom(False)
399
394
  self._shiftsWidget.setFocus(qt.Qt.OtherFocusReason)
@@ -492,10 +487,6 @@ class DiffFrameViewer(qt.QMainWindow):
492
487
  )
493
488
  self._mainWidget.setImage2(shifted_image)
494
489
 
495
- def clear(self):
496
- self._framesSelector.clear()
497
- self._mainWidget.getPlot().clear()
498
-
499
490
  def _frameShiftsChanged(self):
500
491
  self._resetLeftFrame()
501
492
  self._resetRightFrame()
@@ -0,0 +1,21 @@
1
+ from silx.gui import qt
2
+ from tomwer.gui.edit.nxtomoeditor import NXtomoEditor as _NXtomoEditor
3
+
4
+
5
+ class NXtomoMetadataViewer(_NXtomoEditor):
6
+ """
7
+ class to display metadata of a NXtomo.
8
+ inherit from the `NXtomoEditor` and make sure not edition is possible
9
+ """
10
+
11
+ def __init__(self, parent=None):
12
+ super().__init__(parent)
13
+ for widget in self.getEditableWidgets():
14
+ if isinstance(widget, (qt.QComboBox, qt.QCheckBox)):
15
+ widget.setEnabled(False)
16
+ else:
17
+ widget.setReadOnly(True)
18
+
19
+ def overwriteNXtomo(self):
20
+ """overwrite data on disk"""
21
+ raise NotImplementedError("viewer not editor")
@@ -95,7 +95,6 @@ class ScanOverviewWidget(qt.QWidget):
95
95
  def setScan(self, scan):
96
96
  if scan is None:
97
97
  self._scan = scan
98
- self.clear()
99
98
  elif not isinstance(scan, TomwerScanBase):
100
99
  raise TypeError(f"{scan} is expected to be an instance of {TomwerScanBase}")
101
100
  else:
@@ -0,0 +1,72 @@
1
+ import os
2
+ import pytest
3
+ import numpy
4
+ from tomoscan.esrf.scan.hdf5scan import ImageKey
5
+ from tomwer.core.scan.hdf5scan import HDF5TomoScan
6
+ from tomwer.gui.visualization.nxtomometadata import NXtomoMetadataViewer
7
+ from nxtomomill.nexus.nxtomo import NXtomo
8
+ from tomwer.tests.conftest import qtapp # noqa F401
9
+ from silx.gui import qt
10
+
11
+
12
+ def test_nx_editor(
13
+ tmp_path,
14
+ qtapp, # noqa F811
15
+ ):
16
+ # 1.0 create nx tomo with raw data
17
+ nx_tomo = NXtomo()
18
+ nx_tomo.instrument.detector.x_pixel_size = 2.6e-6
19
+ nx_tomo.instrument.detector.y_pixel_size = 2.5e-6
20
+ nx_tomo.instrument.detector.field_of_view = "Half"
21
+ nx_tomo.instrument.detector.distance = 59.0
22
+ nx_tomo.instrument.detector.x_flipped = True
23
+ nx_tomo.instrument.detector.y_flipped = False
24
+ nx_tomo.energy = 12.8
25
+ nx_tomo.sample.x_translation = numpy.arange(12)
26
+ nx_tomo.sample.z_translation = numpy.arange(2, 14)
27
+ nx_tomo.instrument.detector.image_key_control = [ImageKey.PROJECTION.value] * 12
28
+ nx_tomo.instrument.detector.data = numpy.empty(shape=(12, 10, 10))
29
+ nx_tomo.sample.rotation_angle = numpy.linspace(0, 180, num=12)
30
+
31
+ file_path = os.path.join(tmp_path, "nxtomo.nx")
32
+ entry = "entry0000"
33
+ nx_tomo.save(
34
+ file_path=file_path,
35
+ data_path=entry,
36
+ )
37
+
38
+ scan = HDF5TomoScan(file_path, entry)
39
+
40
+ # 2.0 create the widget and do the edition
41
+ widget = NXtomoMetadataViewer()
42
+ widget.setScan(scan=scan)
43
+ widget.show()
44
+
45
+ # 3.0 check data have been corrcetly loaded
46
+ def check_metric(expected_value, current_value):
47
+ if expected_value is None:
48
+ return current_value is None
49
+ return expected_value == current_value
50
+
51
+ assert check_metric(2.6e-6, widget._xPixelSizeMetricEntry.getValue())
52
+ assert widget._xPixelSizeMetricEntry._qcbUnit.currentText() == "m"
53
+ assert check_metric(2.5e-6, widget._yPixelSizeMetricEntry.getValue())
54
+ assert widget._yPixelSizeMetricEntry._qcbUnit.currentText() == "m"
55
+
56
+ assert check_metric(59, widget._distanceMetricEntry.getValue())
57
+ assert widget._distanceMetricEntry._qcbUnit.currentText() == "m"
58
+
59
+ assert "Half" == widget._fieldOfViewCB.currentText()
60
+ assert widget._xFlippedCB.isChecked()
61
+ assert not widget._yFlippedCB.isChecked()
62
+
63
+ assert "12.8" == widget._energyQLE.text()
64
+
65
+ # make sure saving raises an error (viewer inherit from the editor)
66
+ with pytest.raises(NotImplementedError):
67
+ widget.overwriteNXtomo()
68
+
69
+ # end
70
+ widget.setAttribute(qt.Qt.WA_DeleteOnClose)
71
+ widget.close()
72
+ widget = None
@@ -38,7 +38,7 @@ import logging
38
38
  import time
39
39
  import pytest
40
40
  from tomoscan.esrf.volume.edfvolume import EDFVolume
41
- from tomwer.test.utils import skip_gui_test
41
+ from tomwer.tests.utils import skip_gui_test
42
42
  import weakref
43
43
 
44
44
  logging.disable(logging.INFO)
@@ -0,0 +1,49 @@
1
+ from .volumeoverview import VolumeOverviewWidget
2
+ from .scanoverview import ScanOverviewWidget
3
+ from silx.gui import qt
4
+ from tomwer.core.tomwer_object import TomwerObject
5
+ from tomwer.core.volume.volumebase import TomwerVolumeBase
6
+ from tomwer.core.scan.scanbase import TomwerScanBase
7
+ from typing import Optional
8
+
9
+
10
+ class TomoObjOverview(qt.QWidget):
11
+ """
12
+ Dummy widget to show ScanOverviewWidget if the object is a scan or VolumeOverviewWidget if the object is a Volume
13
+ """
14
+
15
+ def __init__(self, parent=None) -> None:
16
+ super().__init__(parent)
17
+ self.setLayout(qt.QVBoxLayout())
18
+ self._scanOverview = ScanOverviewWidget(self)
19
+ self.layout().addWidget(self._scanOverview)
20
+
21
+ self._volumeOverview = VolumeOverviewWidget(self)
22
+ self.layout().addWidget(self._volumeOverview)
23
+
24
+ self._scanOverview.setVisible(False)
25
+ self._volumeOverview.setVisible(False)
26
+
27
+ def setTomoObj(self, tomo_obj: Optional[TomwerObject]):
28
+ """
29
+ update sub widgets according to the type of tomo_obj
30
+ """
31
+ if tomo_obj is not None and not isinstance(tomo_obj, TomwerObject):
32
+ raise TypeError(
33
+ f"tomo_obj is expected to be an instance of {TomwerObject} and not {type(tomo_obj)}"
34
+ )
35
+ # handle visibility
36
+ self._volumeOverview.setVisible(isinstance(tomo_obj, TomwerVolumeBase))
37
+ self._scanOverview.setVisible(isinstance(tomo_obj, TomwerScanBase))
38
+
39
+ if isinstance(tomo_obj, TomwerVolumeBase):
40
+ self._scanOverview.setScan(None)
41
+ self._volumeOverview.setVolume(tomo_obj)
42
+ elif isinstance(tomo_obj, TomwerScanBase):
43
+ self._scanOverview.setScan(tomo_obj)
44
+ self._volumeOverview.setVolume(None)
45
+ elif tomo_obj is None:
46
+ self._volumeOverview.setVolume(None)
47
+ self._scanOverview.setScan(None)
48
+ else:
49
+ raise RuntimeError(f"TomwerObject of type {type(tomo_obj)} is not handled")