tomwer 1.0.3__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 (269) 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 +3 -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 -129
  20. orangecontrib/tomwer/widgets/control/NotifierOW.py +34 -9
  21. orangecontrib/tomwer/widgets/control/SingleTomoObjOW.py +3 -5
  22. orangecontrib/tomwer/widgets/control/TomoObjSerieOW.py +19 -13
  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 +73 -78
  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 -11
  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 -20
  47. orangecontrib/tomwer/widgets/reconstruction/SADeltaBetaOW.py +24 -18
  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/intensitynormalization.py +0 -1
  66. tomwer/app/nxtomoeditor.py +103 -0
  67. tomwer/app/rsync.py +1 -1
  68. tomwer/core/cluster/cluster.py +1 -1
  69. tomwer/core/futureobject.py +1 -0
  70. tomwer/core/process/control/datalistener/datalistener.py +7 -1
  71. tomwer/core/process/control/datalistener/rpcserver.py +3 -4
  72. tomwer/core/process/control/datawatcher/datawatcher.py +18 -18
  73. tomwer/core/process/control/datawatcher/datawatcherobserver.py +5 -8
  74. tomwer/core/process/control/datawatcher/datawatcherprocess.py +2 -3
  75. tomwer/core/process/control/datawatcher/edfdwprocess.py +2 -2
  76. tomwer/core/process/control/nxtomomill.py +33 -58
  77. tomwer/core/process/control/scanlist.py +2 -1
  78. tomwer/core/process/control/scanselector.py +7 -0
  79. tomwer/core/process/control/scantransfer.py +2 -2
  80. tomwer/core/process/control/scanvalidator.py +6 -5
  81. tomwer/core/process/control/singletomoobj.py +2 -1
  82. tomwer/core/process/control/timer.py +2 -1
  83. tomwer/core/process/control/tomoobjserie.py +8 -2
  84. tomwer/core/process/control/volumeselector.py +2 -1
  85. tomwer/core/process/control/volumesymlink.py +2 -1
  86. tomwer/core/process/edit/darkflatpatch.py +2 -1
  87. tomwer/core/process/edit/imagekeyeditor.py +4 -3
  88. tomwer/core/process/reconstruction/axis/axis.py +29 -32
  89. tomwer/core/process/reconstruction/axis/mode.py +3 -2
  90. tomwer/core/process/reconstruction/axis/params.py +35 -16
  91. tomwer/core/process/reconstruction/darkref/darkrefs.py +90 -707
  92. tomwer/core/process/reconstruction/darkref/darkrefscopy.py +44 -16
  93. tomwer/core/process/reconstruction/darkref/params.py +62 -67
  94. tomwer/core/process/reconstruction/lamino/tofu.py +1 -2
  95. tomwer/core/process/reconstruction/nabu/castvolume.py +21 -26
  96. tomwer/core/process/reconstruction/nabu/nabucommon.py +36 -38
  97. tomwer/core/process/reconstruction/nabu/nabuscores.py +28 -13
  98. tomwer/core/process/reconstruction/nabu/nabuslices.py +41 -14
  99. tomwer/core/process/reconstruction/nabu/nabuvolume.py +21 -12
  100. tomwer/core/process/reconstruction/nabu/utils.py +32 -3
  101. tomwer/core/process/reconstruction/normalization/normalization.py +9 -8
  102. tomwer/core/process/reconstruction/saaxis/saaxis.py +46 -20
  103. tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +38 -12
  104. tomwer/core/process/reconstruction/test/__init__.py +0 -39
  105. tomwer/core/process/reconstruction/test/test_axis_params.py +25 -3
  106. tomwer/core/process/reconstruction/test/test_darkref_copy.py +117 -1
  107. tomwer/core/process/script/python.py +16 -12
  108. tomwer/core/process/task.py +3 -7
  109. tomwer/core/process/test/test_axis.py +1 -1
  110. tomwer/core/process/test/test_dark_and_flat.py +41 -111
  111. tomwer/core/process/test/test_data_listener.py +0 -29
  112. tomwer/core/process/test/test_data_transfer.py +10 -14
  113. tomwer/core/process/test/test_nabu.py +1 -1
  114. tomwer/core/process/test/test_normalization.py +1 -1
  115. tomwer/core/process/visualization/liveslice.py +6 -0
  116. tomwer/core/scan/blissscan.py +37 -2
  117. tomwer/core/scan/edfscan.py +19 -8
  118. tomwer/core/scan/hdf5scan.py +10 -4
  119. tomwer/core/scan/scanbase.py +35 -29
  120. tomwer/core/scan/scanfactory.py +3 -17
  121. tomwer/core/scan/test/test_h5.py +1 -1
  122. tomwer/core/scan/test/test_process_registration.py +0 -11
  123. tomwer/core/scan/test/test_scan.py +32 -30
  124. tomwer/core/settings.py +2 -2
  125. tomwer/core/test/test_utils.py +1 -1
  126. tomwer/core/tomwer_object.py +19 -0
  127. tomwer/core/utils/__init__.py +0 -45
  128. tomwer/core/utils/char.py +2 -0
  129. tomwer/core/utils/gpu.py +5 -5
  130. tomwer/core/utils/nxtomoutils.py +2 -2
  131. tomwer/core/utils/scanutils.py +50 -0
  132. tomwer/core/utils/volumeutils.py +13 -0
  133. tomwer/core/volume/edfvolume.py +4 -0
  134. tomwer/core/volume/hdf5volume.py +4 -0
  135. tomwer/core/volume/jp2kvolume.py +4 -0
  136. tomwer/core/volume/rawvolume.py +22 -5
  137. tomwer/core/volume/tiffvolume.py +4 -0
  138. tomwer/core/volume/volumebase.py +19 -12
  139. tomwer/core/volume/volumefactory.py +20 -1
  140. tomwer/gui/cluster/slurm.py +1 -1
  141. tomwer/gui/cluster/supervisor.py +0 -2
  142. tomwer/gui/cluster/test/test_cluster.py +2 -2
  143. tomwer/gui/control/datalist.py +109 -36
  144. tomwer/gui/control/datatransfert.py +1 -1
  145. tomwer/gui/control/datawatcher/configuration.py +0 -2
  146. tomwer/gui/control/datawatcher/datawatcher.py +23 -13
  147. tomwer/gui/control/datawatcher/datawatcherobserver.py +1 -1
  148. tomwer/gui/control/observations.py +0 -3
  149. tomwer/gui/control/selectorwidgetbase.py +42 -12
  150. tomwer/gui/control/serie/seriecreator.py +967 -0
  151. tomwer/{web/__init__.py → gui/control/serie/seriewaiter.py} +5 -7
  152. tomwer/gui/control/singletomoobj.py +15 -4
  153. tomwer/gui/control/test/test_datalist.py +1 -1
  154. tomwer/gui/control/test/test_datalistener.py +1 -1
  155. tomwer/gui/control/test/test_inputwidget.py +1 -1
  156. tomwer/gui/control/test/test_process_manager.py +1 -13
  157. tomwer/gui/control/test/test_scanselector.py +1 -1
  158. tomwer/gui/control/test/test_scanvalidator.py +1 -1
  159. tomwer/gui/control/test/test_single_tomo_obj.py +1 -1
  160. tomwer/gui/control/test/test_volume_dialog.py +19 -7
  161. tomwer/gui/control/test/test_volumeselector.py +4 -4
  162. tomwer/gui/debugtools/datasetgenerator.py +1 -9
  163. tomwer/gui/edit/dkrfpatch.py +2 -3
  164. tomwer/gui/edit/imagekeyeditor.py +12 -11
  165. tomwer/gui/edit/nxtomoeditor.py +475 -0
  166. tomwer/gui/edit/test/test_dkrf_patch.py +2 -14
  167. tomwer/gui/edit/test/test_image_key_editor.py +2 -2
  168. tomwer/gui/edit/test/test_nx_editor.py +155 -0
  169. tomwer/gui/icons.py +0 -1
  170. tomwer/gui/qfolderdialog.py +11 -0
  171. tomwer/gui/reconstruction/axis/CompareImages.py +27 -29
  172. tomwer/gui/reconstruction/axis/axis.py +2 -0
  173. tomwer/gui/reconstruction/axis/radioaxis.py +70 -14
  174. tomwer/gui/reconstruction/darkref/darkrefcopywidget.py +7 -9
  175. tomwer/gui/reconstruction/darkref/darkrefwidget.py +22 -24
  176. tomwer/gui/reconstruction/lamino/tofu/projections.py +1 -1
  177. tomwer/gui/reconstruction/lamino/tofu/tofu.py +3 -3
  178. tomwer/gui/reconstruction/lamino/tofu/tofuexpert.py +4 -4
  179. tomwer/gui/reconstruction/lamino/tofu/tofuoutput.py +10 -5
  180. tomwer/gui/reconstruction/nabu/castvolume.py +103 -24
  181. tomwer/gui/reconstruction/nabu/check.py +1 -1
  182. tomwer/gui/reconstruction/nabu/nabuconfig/ctf.py +352 -0
  183. tomwer/gui/reconstruction/nabu/nabuconfig/nabuconfig.py +0 -9
  184. tomwer/gui/reconstruction/nabu/nabuconfig/output.py +1 -1
  185. tomwer/gui/reconstruction/nabu/nabuconfig/phase.py +18 -19
  186. tomwer/gui/reconstruction/nabu/nabuconfig/preprocessing.py +30 -7
  187. tomwer/gui/reconstruction/nabu/nabuconfig/reconstruction.py +26 -15
  188. tomwer/gui/reconstruction/nabu/slices.py +10 -4
  189. tomwer/gui/reconstruction/nabu/slurm.py +1 -1
  190. tomwer/gui/reconstruction/nabu/volume.py +13 -7
  191. tomwer/gui/reconstruction/normalization/intensity.py +1 -5
  192. tomwer/gui/reconstruction/saaxis/corrangeselector.py +10 -37
  193. tomwer/gui/reconstruction/saaxis/saaxis.py +11 -7
  194. tomwer/gui/reconstruction/saaxis/sliceselector.py +11 -26
  195. tomwer/gui/reconstruction/sadeltabeta/saadeltabeta.py +13 -8
  196. tomwer/gui/reconstruction/scores/scoreplot.py +67 -62
  197. tomwer/gui/reconstruction/test/test_axis.py +2 -2
  198. tomwer/gui/reconstruction/test/test_lamino.py +2 -2
  199. tomwer/gui/reconstruction/test/test_nabu.py +14 -1
  200. tomwer/gui/reconstruction/test/test_saaxis.py +8 -17
  201. tomwer/gui/reconstruction/test/test_sadeltabeta.py +7 -13
  202. tomwer/gui/stackplot.py +11 -28
  203. tomwer/gui/test/test_axis_gui.py +4 -4
  204. tomwer/gui/test/test_qfolder_dialog.py +12 -0
  205. tomwer/gui/utils/inputwidget.py +42 -22
  206. tomwer/gui/utils/lineselector/lineselector.py +13 -21
  207. tomwer/gui/utils/scandescription.py +2 -4
  208. tomwer/gui/utils/slider.py +1 -102
  209. tomwer/gui/utils/unitsystem.py +48 -11
  210. tomwer/gui/visualization/dataviewer.py +24 -17
  211. tomwer/gui/visualization/diffviewer/diffviewer.py +2 -11
  212. tomwer/gui/visualization/nxtomometadata.py +21 -0
  213. tomwer/gui/visualization/scanoverview.py +0 -1
  214. tomwer/gui/visualization/test/test_nx_tomo_metadata_viewer.py +72 -0
  215. tomwer/gui/visualization/test/test_stacks.py +1 -1
  216. tomwer/gui/visualization/tomoobjoverview.py +49 -0
  217. tomwer/gui/visualization/volumeoverview.py +64 -0
  218. tomwer/gui/visualization/volumeviewer.py +1 -1
  219. tomwer/io/utils/utils.py +2 -2
  220. tomwer/resources/gui/icons/multi-document-save.png +0 -0
  221. tomwer/resources/gui/icons/multi-document-save.svg +101 -0
  222. tomwer/resources/gui/illustrations/ctf_z1.png +0 -0
  223. tomwer/resources/gui/illustrations/ctf_z1.svg +471 -0
  224. tomwer/synctools/axis.py +0 -1
  225. tomwer/synctools/darkref.py +0 -1
  226. tomwer/synctools/datalistener.py +5 -1
  227. tomwer/synctools/imageloaderthread.py +2 -2
  228. tomwer/synctools/saaxis.py +0 -1
  229. tomwer/synctools/sadeltabeta.py +0 -1
  230. tomwer/synctools/stacks/edit/imagekeyeditor.py +1 -1
  231. tomwer/synctools/stacks/processingstack.py +2 -2
  232. tomwer/synctools/stacks/reconstruction/castvolume.py +1 -0
  233. tomwer/synctools/stacks/reconstruction/dkrefcopy.py +1 -1
  234. tomwer/synctools/stacks/reconstruction/lamino.py +1 -3
  235. tomwer/synctools/stacks/reconstruction/sadeltabeta.py +0 -2
  236. tomwer/synctools/test/test_darkRefs.py +32 -149
  237. tomwer/synctools/test/test_foldertransfer.py +1 -1
  238. tomwer/synctools/test/test_scanstages.py +2 -2
  239. tomwer/tests/conftest.py +51 -0
  240. tomwer/{test → tests}/test_scripts.py +1 -1
  241. tomwer/tests/test_utils.py +10 -0
  242. tomwer/{test → tests}/utils/utilstest.py +0 -11
  243. tomwer/version.py +3 -3
  244. {tomwer-1.0.3.dist-info → tomwer-1.1.0.dist-info}/METADATA +14 -16
  245. {tomwer-1.0.3.dist-info → tomwer-1.1.0.dist-info}/RECORD +255 -235
  246. {tomwer-1.0.3.dist-info → tomwer-1.1.0.dist-info}/WHEEL +1 -1
  247. {tomwer-1.0.3.dist-info → tomwer-1.1.0.dist-info}/entry_points.txt +6 -0
  248. orangecontrib/tomwer/setup.py +0 -45
  249. orangecontrib/tomwer/widgets/setup.py +0 -49
  250. tomwer/app/process.py +0 -153
  251. tomwer/core/process/reconstruction/nabu/slurm.py +0 -36
  252. tomwer/core/process/reconstruction/utils/nabu_slice_exec.py +0 -10
  253. tomwer/core/utils/laminoutils.py +0 -80
  254. tomwer/gui/utils/lineselector/lineselection.py +0 -76
  255. tomwer/setup.py +0 -52
  256. tomwer/slurm/executor.py +0 -36
  257. tomwer/slurm/job.py +0 -349
  258. tomwer/slurm/utils.py +0 -44
  259. tomwer/web/client.py +0 -43
  260. tomwer/web/config.py +0 -36
  261. tomwer/web/test/test_graylog_connection.py +0 -59
  262. {tomwer/slurm → orangecontrib/tomwer/tutorials}/__init__.py +0 -0
  263. /tomwer/{test → gui/control/serie}/__init__.py +0 -0
  264. /tomwer/{web/test → tests}/__init__.py +0 -0
  265. /tomwer/{test → tests}/utils/__init__.py +0 -0
  266. /tomwer-1.0.3-py3.8-nspkg.pth → /tomwer-1.1.0-py3.9-nspkg.pth +0 -0
  267. {tomwer-1.0.3.dist-info → tomwer-1.1.0.dist-info}/LICENSE +0 -0
  268. {tomwer-1.0.3.dist-info → tomwer-1.1.0.dist-info}/namespace_packages.txt +0 -0
  269. {tomwer-1.0.3.dist-info → tomwer-1.1.0.dist-info}/top_level.txt +0 -0
@@ -246,49 +246,60 @@ class ListSelAction(SelectionAction):
246
246
 
247
247
 
248
248
  class NXTomomillOutputDirSelector(qt.QWidget):
249
-
250
249
  sigChanged = qt.Signal()
251
250
  """Signal emit when the output directory of the nx file change"""
252
251
 
252
+ DEFAULT_PROCESSED_DIR = (
253
+ "{scan_parent_dir_basename}/../PROCESSED_DATA/{scan_dir_name}"
254
+ )
255
+ """Default pattern to find the 'processed' directory"""
256
+
253
257
  def __init__(self, parent=None):
254
258
  qt.QWidget.__init__(self, parent)
255
259
  self.setLayout(qt.QGridLayout())
256
260
  self.__buttonGroup = qt.QButtonGroup(self)
257
261
  self.__buttonGroup.setExclusive(True)
258
262
 
259
- # automatic
260
- self._automaticRB = qt.QRadioButton("automatic", self)
261
- self._automaticRB.setToolTip(
262
- "Define the output directory of the "
263
- "nexus (.nx) file. Will be created at the"
264
- " same level as the bliss input file "
265
- "(.h5)"
266
- )
267
- self.layout().addWidget(self._automaticRB, 0, 0, 1, 1)
268
- self.__buttonGroup.addButton(self._automaticRB)
263
+ tooltip = f"""Define the output directory of the nexus (.nx) file. Options are:
264
+ \n - next to bliss file: create the NXtomos at the same level as the bliss input file
265
+ \n - 'PROCESSED_DATA' folder: create NXtomos on the default 'PROCESSED_DATA' folder (bliss default folder, nearby the 'raw' folder). Uses {self.DEFAULT_PROCESSED_DIR} pattern
266
+ \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'
267
+ """
268
+
269
+ # output dir is the folder containing the .nx file
270
+ self._closeToNxRB = qt.QRadioButton("next to bliss file", self)
271
+ self._closeToNxRB.setToolTip(tooltip)
272
+ self.layout().addWidget(self._closeToNxRB, 0, 0, 1, 1)
273
+ self.__buttonGroup.addButton(self._closeToNxRB)
274
+ # output dir is the default 'reduced'folder
275
+ self._processedFolderRB = qt.QRadioButton("'PROCESSED_DATA' folder", self)
276
+ self._processedFolderRB.setToolTip(tooltip)
277
+ self.layout().addWidget(self._processedFolderRB, 1, 0, 1, 1)
278
+ self.__buttonGroup.addButton(self._processedFolderRB)
269
279
  # manual
270
- self._manualRB = qt.QRadioButton("personalized output directory", self)
271
- self._manualRB.setToolTip("Define yourself the output directory")
272
- self.layout().addWidget(self._manualRB, 1, 0, 1, 1)
280
+ self._manualRB = qt.QRadioButton("custom output directory", self)
281
+ self._manualRB.setToolTip(tooltip)
282
+ self.layout().addWidget(self._manualRB, 2, 0, 1, 1)
273
283
  self._outputFolderQLE = qt.QLineEdit("", self)
274
- self.layout().addWidget(self._outputFolderQLE, 1, 1, 1, 1)
284
+ self.layout().addWidget(self._outputFolderQLE, 2, 1, 1, 1)
275
285
  self._selectButton = qt.QPushButton("", self)
276
286
  style = qt.QApplication.style()
277
287
  icon_opendir = style.standardIcon(qt.QStyle.SP_DirOpenIcon)
278
288
  self._selectButton.setIcon(icon_opendir)
279
289
  self._selectButton.setToolTip("select output directory")
280
- self.layout().addWidget(self._selectButton, 1, 2, 1, 1)
290
+ self.layout().addWidget(self._selectButton, 2, 2, 1, 1)
281
291
  self.__buttonGroup.addButton(self._manualRB)
282
292
 
283
293
  # connect signal / slot
284
294
  self._selectButton.released.connect(self._selectOutpuFolder)
285
295
  self.__buttonGroup.buttonReleased.connect(self._updateVisiblity)
286
- self._automaticRB.toggled.connect(self._outputDirChanged)
296
+ self._closeToNxRB.toggled.connect(self._outputDirChanged)
297
+ self._processedFolderRB.toggled.connect(self._outputDirChanged)
287
298
  self._manualRB.toggled.connect(self._outputDirChanged)
288
299
  self._outputFolderQLE.editingFinished.connect(self._outputDirChanged)
289
300
 
290
301
  # set up
291
- self._automaticRB.setChecked(True)
302
+ self._closeToNxRB.setChecked(True)
292
303
  self._updateVisiblity()
293
304
 
294
305
  def _updateVisiblity(self, *args, **kwargs):
@@ -298,7 +309,7 @@ class NXTomomillOutputDirSelector(qt.QWidget):
298
309
  def _outputDirChanged(self):
299
310
  self.sigChanged.emit()
300
311
 
301
- def _selectOutpuFolder(self):
312
+ def _selectOutpuFolder(self): # pragma: no cover
302
313
  defaultDirectory = self._outputFolderQLE.text()
303
314
  if os.path.isdir(defaultDirectory):
304
315
  defaultDirectory = get_default_directory()
@@ -316,14 +327,23 @@ class NXTomomillOutputDirSelector(qt.QWidget):
316
327
  def getOutputFolder(self) -> Union[None, str]:
317
328
  if self._manualRB.isChecked():
318
329
  return self._outputFolderQLE.text()
330
+ elif self._processedFolderRB.isChecked():
331
+ return self.DEFAULT_PROCESSED_DIR
319
332
  else:
320
333
  return None
321
334
 
322
335
  def setOutputFolder(self, output_folder: Optional[str]):
323
336
  old = self.blockSignals(True)
324
337
  self._manualRB.setChecked(output_folder is not None)
325
- if output_folder is not None:
326
- self._outputFolderQLE.setText(output_folder)
338
+ if output_folder is None:
339
+ self._closeToNxRB.setChecked()
340
+ else:
341
+ is_default_processed_folder = output_folder == self.DEFAULT_PROCESSED_DIR
342
+ if is_default_processed_folder:
343
+ self._processedFolderRB.setChecked(True)
344
+ else:
345
+ self._outputFolderQLE.setText(output_folder)
346
+ self._manualRB.setChecked(True)
327
347
  self._updateVisiblity()
328
348
  self.blockSignals(old)
329
349
 
@@ -360,7 +380,7 @@ class _ConfigFileSelector(qt.QWidget):
360
380
  def _clearFilePath(self):
361
381
  self._lineEdit.clear()
362
382
 
363
- def _selectCFGFile(self):
383
+ def _selectCFGFile(self): # pragma: no cover
364
384
  dialog = qt.QFileDialog(self)
365
385
  dialog.setFileMode(qt.QFileDialog.ExistingFile)
366
386
 
@@ -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: