tomwer 1.2.0a1__py3-none-any.whl → 1.2.0a3__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 (219) hide show
  1. orangecontrib/tomwer/tutorials/append_raw_darks_and_flats_frames_to_NXtomos.ows +44 -0
  2. orangecontrib/tomwer/tutorials/copy_reduced_darks_and_flats_meth1.ows +55 -0
  3. orangecontrib/tomwer/tutorials/copy_reduced_darks_and_flats_meth2.ows +48 -0
  4. orangecontrib/tomwer/tutorials/default_cor_search.ows +40 -0
  5. orangecontrib/tomwer/tutorials/hello_world_python_script.ows +50 -0
  6. orangecontrib/tomwer/tutorials/simple_slice_reconstruction_on_slurm.ows +50 -0
  7. orangecontrib/tomwer/tutorials/simple_volume_to_slurm_reconstruction.ows +8 -8
  8. orangecontrib/tomwer/widgets/__init__.py +1 -1
  9. orangecontrib/tomwer/widgets/cluster/FutureSupervisorOW.py +0 -1
  10. orangecontrib/tomwer/widgets/cluster/SlurmClusterOW.py +8 -6
  11. orangecontrib/tomwer/widgets/control/AdvancementOW.py +0 -1
  12. orangecontrib/tomwer/widgets/control/DataDiscoveryOW.py +1 -6
  13. orangecontrib/tomwer/widgets/control/DataListOW.py +0 -1
  14. orangecontrib/tomwer/widgets/control/DataListenerOW.py +4 -4
  15. orangecontrib/tomwer/widgets/control/DataSelectorOW.py +0 -1
  16. orangecontrib/tomwer/widgets/control/DataTransfertOW.py +7 -7
  17. orangecontrib/tomwer/widgets/control/DataValidatorOW.py +0 -1
  18. orangecontrib/tomwer/widgets/control/DataWatcherOW.py +0 -3
  19. orangecontrib/tomwer/widgets/control/EDF2NXTomomillOW.py +3 -2
  20. orangecontrib/tomwer/widgets/control/EmailOW.py +82 -0
  21. orangecontrib/tomwer/widgets/control/FilterOW.py +3 -3
  22. orangecontrib/tomwer/widgets/control/NXTomomillOW.py +1 -1
  23. orangecontrib/tomwer/widgets/control/NotifierOW.py +0 -1
  24. orangecontrib/tomwer/widgets/control/ReduceDarkFlatSelectorOW.py +93 -0
  25. orangecontrib/tomwer/widgets/control/SingleTomoObjOW.py +29 -5
  26. orangecontrib/tomwer/widgets/control/TimerOW.py +1 -2
  27. orangecontrib/tomwer/widgets/control/TomoObjSerieOW.py +0 -1
  28. orangecontrib/tomwer/widgets/control/VolumeSelector.py +0 -1
  29. orangecontrib/tomwer/widgets/control/VolumeSymLinkOW.py +4 -10
  30. orangecontrib/tomwer/widgets/control/icons/email.png +0 -0
  31. orangecontrib/tomwer/widgets/control/icons/email.svg +58 -0
  32. orangecontrib/tomwer/widgets/control/icons/reduced_darkflat_selector.png +0 -0
  33. orangecontrib/tomwer/widgets/control/icons/reduced_darkflat_selector.svg +199 -0
  34. orangecontrib/tomwer/widgets/debugtools/DatasetGeneratorOW.py +0 -1
  35. orangecontrib/tomwer/widgets/debugtools/ObjectInspectorOW.py +0 -1
  36. orangecontrib/tomwer/widgets/edit/DarkFlatPatchOW.py +1 -2
  37. orangecontrib/tomwer/widgets/edit/ImageKeyEditorOW.py +1 -2
  38. orangecontrib/tomwer/widgets/edit/ImageKeyUpgraderOW.py +0 -1
  39. orangecontrib/tomwer/widgets/edit/NXtomoEditorOW.py +0 -1
  40. orangecontrib/tomwer/widgets/other/PythonScriptOW.py +29 -1
  41. orangecontrib/tomwer/widgets/other/TomoObjsHub.py +28 -0
  42. orangecontrib/tomwer/widgets/other/icons/hub.png +0 -0
  43. orangecontrib/tomwer/widgets/other/icons/hub.svg +113 -0
  44. orangecontrib/tomwer/widgets/reconstruction/AxisOW.py +18 -12
  45. orangecontrib/tomwer/widgets/reconstruction/CastNabuVolumeOW.py +0 -2
  46. orangecontrib/tomwer/widgets/reconstruction/DarkRefAndCopyOW.py +21 -6
  47. orangecontrib/tomwer/widgets/reconstruction/NabuOW.py +29 -7
  48. orangecontrib/tomwer/widgets/reconstruction/NabuVolumeOW.py +18 -5
  49. orangecontrib/tomwer/widgets/reconstruction/SAAxisOW.py +40 -13
  50. orangecontrib/tomwer/widgets/reconstruction/SADeltaBetaOW.py +37 -10
  51. orangecontrib/tomwer/widgets/reconstruction/SinoNormOW.py +2 -3
  52. orangecontrib/tomwer/widgets/reconstruction/TofuOW.py +5 -4
  53. orangecontrib/tomwer/widgets/stitching/StitcherOW.py +0 -1
  54. orangecontrib/tomwer/widgets/stitching/ZStitchingConfigOW.py +0 -1
  55. orangecontrib/tomwer/widgets/visualization/DataViewerOW.py +10 -4
  56. orangecontrib/tomwer/widgets/visualization/DiffViewerOW.py +1 -1
  57. orangecontrib/tomwer/widgets/visualization/LivesliceOW.py +0 -1
  58. orangecontrib/tomwer/widgets/visualization/NXtomoMetadataViewerOW.py +0 -1
  59. orangecontrib/tomwer/widgets/visualization/RadioStackOW.py +7 -5
  60. orangecontrib/tomwer/widgets/visualization/SampleMovedOW.py +1 -1
  61. orangecontrib/tomwer/widgets/visualization/SinogramViewerOW.py +0 -3
  62. orangecontrib/tomwer/widgets/visualization/SliceStackOW.py +7 -5
  63. orangecontrib/tomwer/widgets/visualization/VolumeViewerOW.py +4 -4
  64. tomwer/__main__.py +139 -5
  65. tomwer/app/axis.py +16 -5
  66. tomwer/app/canvas_launcher/config.py +1 -1
  67. tomwer/app/canvas_launcher/mainwindow.py +164 -6
  68. tomwer/app/darkref.py +10 -181
  69. tomwer/app/darkrefpatch.py +10 -131
  70. tomwer/app/diffframe.py +11 -0
  71. tomwer/app/imagekeyeditor.py +12 -19
  72. tomwer/app/intensitynormalization.py +1 -0
  73. tomwer/app/lamino.py +7 -2
  74. tomwer/app/patchrawdarkflat.py +131 -0
  75. tomwer/app/radiostack.py +10 -0
  76. tomwer/app/reducedarkflat.py +205 -0
  77. tomwer/app/saaxis.py +27 -8
  78. tomwer/app/sadeltabeta.py +29 -8
  79. tomwer/app/samplemoved.py +11 -0
  80. tomwer/app/scanviewer.py +12 -0
  81. tomwer/app/sinogramviewer.py +11 -0
  82. tomwer/app/slicestack.py +11 -0
  83. tomwer/app/zstitching.py +12 -0
  84. tomwer/core/futureobject.py +4 -2
  85. tomwer/core/process/conditions/filters.py +26 -4
  86. tomwer/core/process/control/datadiscovery.py +4 -0
  87. tomwer/core/process/control/datawatcher/datawatcher.py +5 -1
  88. tomwer/core/process/control/email.py +148 -0
  89. tomwer/core/process/control/nxtomoconcatenate.py +9 -2
  90. tomwer/core/process/control/nxtomomill.py +58 -16
  91. tomwer/core/process/control/scanselector.py +4 -0
  92. tomwer/core/process/control/scantransfer.py +52 -23
  93. tomwer/core/process/control/test/test_concatenate_nxtomos.py +1 -0
  94. tomwer/core/process/control/test/test_email.py +52 -0
  95. tomwer/core/process/control/test/test_h52nx_process.py +106 -0
  96. tomwer/core/process/control/test/test_volume_link.py +5 -4
  97. tomwer/core/process/control/timer.py +27 -6
  98. tomwer/core/process/control/tomoobjserie.py +4 -0
  99. tomwer/core/process/control/volumeselector.py +4 -0
  100. tomwer/core/process/control/volumesymlink.py +47 -8
  101. tomwer/core/process/edit/darkflatpatch.py +49 -8
  102. tomwer/core/process/edit/imagekeyeditor.py +63 -13
  103. tomwer/core/process/reconstruction/axis/__init__.py +1 -1
  104. tomwer/core/process/reconstruction/axis/axis.py +61 -41
  105. tomwer/core/process/reconstruction/axis/params.py +4 -6
  106. tomwer/core/process/reconstruction/darkref/darkrefs.py +53 -16
  107. tomwer/core/process/reconstruction/darkref/darkrefscopy.py +12 -2
  108. tomwer/core/process/reconstruction/lamino/__init__.py +1 -1
  109. tomwer/core/process/reconstruction/lamino/tofu.py +22 -2
  110. tomwer/core/process/reconstruction/nabu/nabucommon.py +93 -14
  111. tomwer/core/process/reconstruction/nabu/nabuscores.py +70 -33
  112. tomwer/core/process/reconstruction/nabu/nabuslices.py +219 -41
  113. tomwer/core/process/reconstruction/nabu/nabuvolume.py +240 -108
  114. tomwer/core/process/reconstruction/nabu/utils.py +10 -36
  115. tomwer/core/process/reconstruction/normalization/normalization.py +10 -3
  116. tomwer/core/process/reconstruction/saaxis/__init__.py +1 -0
  117. tomwer/core/process/reconstruction/saaxis/saaxis.py +564 -376
  118. tomwer/core/process/reconstruction/sadeltabeta/__init__.py +1 -0
  119. tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +481 -268
  120. tomwer/core/process/reconstruction/scores/params.py +21 -8
  121. tomwer/core/process/reconstruction/test/test_darkref_copy.py +2 -0
  122. tomwer/core/process/reconstruction/test/test_saaxis.py +21 -8
  123. tomwer/core/process/reconstruction/test/test_sadeltabeta.py +8 -5
  124. tomwer/core/process/script/python.py +7 -2
  125. tomwer/core/process/stitching/nabustitcher.py +10 -3
  126. tomwer/core/process/task.py +2 -9
  127. tomwer/core/process/test/test_axis.py +25 -15
  128. tomwer/core/process/test/test_conditions.py +6 -6
  129. tomwer/core/process/test/test_dark_and_flat.py +20 -15
  130. tomwer/core/process/test/test_data_transfer.py +8 -8
  131. tomwer/core/process/test/test_data_watcher.py +1 -1
  132. tomwer/core/process/test/test_lamino.py +6 -6
  133. tomwer/core/process/test/test_nabu.py +13 -8
  134. tomwer/core/process/test/test_normalization.py +1 -0
  135. tomwer/core/process/test/test_timer.py +6 -6
  136. tomwer/core/process/visualization/dataviewer.py +4 -0
  137. tomwer/core/process/visualization/diffviewer.py +4 -0
  138. tomwer/core/process/visualization/imagestackviewer.py +4 -0
  139. tomwer/core/process/visualization/radiostack.py +4 -0
  140. tomwer/core/process/visualization/samplemoved.py +4 -0
  141. tomwer/core/process/visualization/sinogramviewer.py +4 -0
  142. tomwer/core/process/visualization/slicestack.py +4 -0
  143. tomwer/core/process/visualization/volumeviewer.py +4 -0
  144. tomwer/core/scan/hdf5scan.py +4 -4
  145. tomwer/core/scan/scanbase.py +5 -1
  146. tomwer/core/scan/test/test_process_registration.py +9 -9
  147. tomwer/core/settings.py +59 -1
  148. tomwer/core/test/test_lamino.py +2 -1
  149. tomwer/core/utils/__init__.py +16 -0
  150. tomwer/core/utils/locker.py +0 -1
  151. tomwer/core/utils/resource.py +6 -11
  152. tomwer/core/utils/scanutils.py +2 -0
  153. tomwer/gui/cluster/slurm.py +91 -7
  154. tomwer/gui/cluster/supervisor.py +16 -11
  155. tomwer/gui/cluster/test/test_cluster.py +16 -1
  156. tomwer/gui/conditions/filter.py +3 -3
  157. tomwer/gui/control/datalist.py +24 -11
  158. tomwer/gui/control/email.py +183 -0
  159. tomwer/gui/control/reducedarkflatselector.py +545 -0
  160. tomwer/gui/control/singletomoobj.py +23 -1
  161. tomwer/gui/control/test/test_email.py +35 -0
  162. tomwer/gui/control/test/test_reducedarkflat_selector.py +280 -0
  163. tomwer/gui/reconstruction/axis/CompareImages.py +1 -1
  164. tomwer/gui/reconstruction/axis/axis.py +10 -6
  165. tomwer/gui/reconstruction/axis/radioaxis.py +14 -6
  166. tomwer/gui/reconstruction/darkref/darkrefcopywidget.py +2 -0
  167. tomwer/gui/reconstruction/darkref/darkrefwidget.py +4 -4
  168. tomwer/gui/reconstruction/nabu/nabuconfig/phase.py +3 -1
  169. tomwer/gui/reconstruction/nabu/nabuconfig/preprocessing.py +34 -33
  170. tomwer/gui/reconstruction/nabu/nabuconfig/reconstruction.py +1 -1
  171. tomwer/gui/reconstruction/normalization/intensity.py +5 -5
  172. tomwer/gui/reconstruction/saaxis/corrangeselector.py +1 -0
  173. tomwer/gui/reconstruction/saaxis/saaxis.py +6 -6
  174. tomwer/gui/reconstruction/sadeltabeta/saadeltabeta.py +6 -6
  175. tomwer/gui/reconstruction/scores/scoreplot.py +6 -4
  176. tomwer/gui/samplemoved/__init__.py +2 -2
  177. tomwer/gui/stackplot.py +18 -7
  178. tomwer/gui/stacks.py +2 -2
  179. tomwer/gui/stitching/stitchandbackground.py +2 -2
  180. tomwer/gui/stitching/stitching.py +1 -1
  181. tomwer/gui/stitching/stitching_raw.py +1 -1
  182. tomwer/gui/utils/__init__.py +1 -85
  183. tomwer/gui/utils/illustrations.py +1 -1
  184. tomwer/gui/utils/inputwidget.py +41 -36
  185. tomwer/gui/utils/slider.py +2 -2
  186. tomwer/gui/utils/utils.py +93 -0
  187. tomwer/gui/visualization/dataviewer.py +8 -5
  188. tomwer/gui/visualization/diffviewer/diffviewer.py +4 -4
  189. tomwer/gui/visualization/reconstructionparameters.py +26 -6
  190. tomwer/gui/visualization/sinogramviewer.py +7 -1
  191. tomwer/gui/visualization/test/test_reconstruction_parameters.py +2 -4
  192. tomwer/gui/visualization/volumeviewer.py +2 -0
  193. tomwer/resources/__init__.py +55 -43
  194. tomwer/resources/gui/icons/compose.png +0 -0
  195. tomwer/resources/gui/icons/compose.svg +75 -0
  196. tomwer/synctools/datatransfert.py +3 -1
  197. tomwer/synctools/stacks/edit/darkflatpatch.py +39 -34
  198. tomwer/synctools/stacks/edit/imagekeyeditor.py +8 -27
  199. tomwer/synctools/stacks/processingstack.py +45 -9
  200. tomwer/synctools/stacks/reconstruction/axis.py +6 -5
  201. tomwer/synctools/stacks/reconstruction/dkrefcopy.py +1 -0
  202. tomwer/synctools/stacks/reconstruction/lamino.py +3 -3
  203. tomwer/synctools/stacks/reconstruction/nabu.py +49 -140
  204. tomwer/synctools/stacks/reconstruction/normalization.py +1 -0
  205. tomwer/synctools/stacks/reconstruction/saaxis.py +19 -33
  206. tomwer/synctools/stacks/reconstruction/sadeltabeta.py +16 -32
  207. tomwer/synctools/test/test_darkRefs.py +19 -10
  208. tomwer/synctools/test/test_foldertransfer.py +7 -7
  209. tomwer/third_party/nabu/preproc/phase.py +6 -8
  210. tomwer/third_party/nabu/utils.py +2 -3
  211. tomwer/version.py +1 -1
  212. {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/METADATA +15 -54
  213. {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/RECORD +219 -192
  214. {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/WHEEL +1 -1
  215. {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/entry_points.txt +3 -3
  216. /tomwer-1.2.0a1-py3.9-nspkg.pth → /tomwer-1.2.0a3-py3.11-nspkg.pth +0 -0
  217. {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/LICENSE +0 -0
  218. {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/namespace_packages.txt +0 -0
  219. {tomwer-1.2.0a1.dist-info → tomwer-1.2.0a3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,280 @@
1
+ import numpy
2
+ from silx.gui.utils.testutils import SignalListener
3
+ from tomwer.tests.conftest import qtapp # noqa F401
4
+ from tomwer.gui.control.reducedarkflatselector import (
5
+ filter_selected_reduced_frames,
6
+ filter_unselected_reduced_frames,
7
+ ReduceDarkFlatSelectorWidget,
8
+ ReduceDarkFlatSelectorDialog,
9
+ )
10
+
11
+
12
+ def test_reduce_darkflat_selector(
13
+ qtapp, # noqa F811
14
+ ):
15
+ widget = ReduceDarkFlatSelectorWidget()
16
+ widget.show()
17
+
18
+ widget.addReduceFrames(
19
+ {
20
+ 0: numpy.random.random(100 * 100).reshape(100, 100),
21
+ 1: numpy.random.random(100 * 100).reshape(100, 100),
22
+ }
23
+ )
24
+
25
+ widget.addReduceFrames(
26
+ {
27
+ "reduce_frames_name": "my_dict",
28
+ -1: numpy.random.random(100 * 100).reshape(100, 100),
29
+ 2: numpy.random.random(100 * 100).reshape(100, 100),
30
+ }
31
+ )
32
+
33
+ config = widget.getConfiguration()
34
+ assert len(config) == 2
35
+ assert config[0]["reduce_frames_name"] == "reduced frames #0"
36
+ assert config[1]["reduce_frames_name"] == "my_dict"
37
+
38
+ widget.setConfiguration(
39
+ (
40
+ {
41
+ "reduce_frames_name": "toto frames",
42
+ "reduce_frames": (
43
+ {
44
+ "index": -1, # -1 will be interpreated as at the end of the acquisition
45
+ "data": numpy.random.random(20 * 20).reshape(20, 20),
46
+ "selected": True,
47
+ },
48
+ {
49
+ "index": 0,
50
+ "data": numpy.random.random(20 * 20).reshape(20, 20),
51
+ "selected": True,
52
+ },
53
+ ),
54
+ },
55
+ {
56
+ "reduce_frames_name": "tata frames",
57
+ "reduce_frames": (
58
+ {
59
+ "index": "0.25r",
60
+ "data": numpy.random.random(40 * 20).reshape(40, 20),
61
+ "selected": False,
62
+ },
63
+ ),
64
+ },
65
+ )
66
+ )
67
+
68
+ config = widget.getConfiguration()
69
+ assert len(config) == 2
70
+ # check selection has been well take into account
71
+ assert config[0]["reduce_frames"][0]["selected"]
72
+ assert config[0]["reduce_frames"][1]["selected"]
73
+ assert not config[1]["reduce_frames"][0]["selected"]
74
+
75
+ selected_frames = widget.getSelectedReduceFrames()
76
+ assert -1 in selected_frames
77
+ assert 0 in selected_frames
78
+ assert 0.25 not in selected_frames
79
+
80
+ # test receive twice the same 'reduce_frames_name'
81
+ widget.clear()
82
+ assert len(widget.getConfiguration()) == 0
83
+ for i in range(2):
84
+ widget.addReduceFrames(
85
+ {
86
+ "reduce_frames_name": "my_dict",
87
+ -1: numpy.random.random(100 * 100).reshape(100, 100),
88
+ 2: numpy.random.random(100 * 100).reshape(100, 100),
89
+ }
90
+ )
91
+ assert len(widget.getConfiguration()) == 1
92
+
93
+
94
+ def test_reduce_darkflat_selector_dialog(
95
+ qtapp, # noqa F811
96
+ ):
97
+ dialog = ReduceDarkFlatSelectorDialog()
98
+
99
+ flat_sel_signal_listener = SignalListener()
100
+ dialog.sigSelectActiveAsFlats.connect(flat_sel_signal_listener)
101
+
102
+ dark_sel_signal_listener = SignalListener()
103
+ dialog.sigSelectActiveAsDarks.connect(dark_sel_signal_listener)
104
+
105
+ dialog.show()
106
+
107
+ dialog.addReduceFrames(
108
+ {
109
+ 0: numpy.random.random(100 * 100).reshape(100, 100),
110
+ 1: numpy.random.random(100 * 100).reshape(100, 100),
111
+ },
112
+ selected=(1,),
113
+ )
114
+
115
+ dialog.addReduceFrames(
116
+ {
117
+ "reduce_frames_name": "my_dict",
118
+ -1: numpy.random.random(100 * 100).reshape(100, 100),
119
+ 2: numpy.random.random(100 * 100).reshape(100, 100),
120
+ },
121
+ selected=(-1,),
122
+ )
123
+
124
+ # check dark selection
125
+ assert dark_sel_signal_listener.callCount() == 0
126
+ dialog._darkSelected()
127
+ assert dark_sel_signal_listener.callCount() == 1
128
+ assert -1 in dark_sel_signal_listener.arguments()[0][0]
129
+
130
+ # check flat selection
131
+ assert flat_sel_signal_listener.callCount() == 0
132
+ dialog._flatSelected()
133
+ assert flat_sel_signal_listener.callCount() == 1
134
+ assert -1 in flat_sel_signal_listener.arguments()[0][0]
135
+
136
+ # check remove selected
137
+ dialog._removeSelected()
138
+ assert dialog._widget.getSelectedReduceFrames() == {}
139
+
140
+ # check clear selection
141
+ dialog.addReduceFrames(
142
+ {
143
+ "reduce_frames_name": "new dict",
144
+ -1: numpy.random.random(100 * 100).reshape(100, 100),
145
+ 2: numpy.random.random(100 * 100).reshape(100, 100),
146
+ },
147
+ selected=(-1, 2),
148
+ )
149
+
150
+ assert len(dialog._widget.getSelectedReduceFrames()) == 2
151
+ dialog._clearSelection()
152
+ assert len(dialog._widget.getSelectedReduceFrames()) == 0
153
+
154
+
155
+ def test_reduced_frames_filtering():
156
+ """
157
+ dummy test of the filter_selected_reduced_frames filter_unselected_reduced_frames function
158
+ """
159
+ check_reduce_frames_configuration(
160
+ filter_selected_reduced_frames(
161
+ (
162
+ {
163
+ "reduce_frames_name": "toto frames",
164
+ "reduce_frames": (
165
+ {
166
+ "index": -1, # -1 will be interpreated as at the end of the acquisition
167
+ "data": numpy.random.random(20 * 20).reshape(20, 20),
168
+ "selected": True,
169
+ },
170
+ {
171
+ "index": 0,
172
+ "data": numpy.random.random(20 * 20).reshape(20, 20),
173
+ "selected": True,
174
+ },
175
+ ),
176
+ },
177
+ {
178
+ "reduce_frames_name": "tata frames",
179
+ "reduce_frames": (
180
+ {
181
+ "index": "0.25r",
182
+ "data": numpy.random.random(40 * 20).reshape(40, 20),
183
+ "selected": False,
184
+ },
185
+ ),
186
+ },
187
+ )
188
+ ),
189
+ (
190
+ {
191
+ "reduce_frames_name": "toto frames",
192
+ "reduce_frames": (
193
+ {
194
+ "index": -1, # -1 will be interpreated as at the end of the acquisition
195
+ "data": numpy.random.random(20 * 20).reshape(20, 20),
196
+ "selected": True,
197
+ },
198
+ {
199
+ "index": 0,
200
+ "data": numpy.random.random(20 * 20).reshape(20, 20),
201
+ "selected": True,
202
+ },
203
+ ),
204
+ },
205
+ ),
206
+ )
207
+
208
+ check_reduce_frames_configuration(
209
+ filter_unselected_reduced_frames(
210
+ (
211
+ {
212
+ "reduce_frames_name": "toto frames",
213
+ "reduce_frames": (
214
+ {
215
+ "index": -1, # -1 will be interpreated as at the end of the acquisition
216
+ "data": numpy.random.random(20 * 20).reshape(20, 20),
217
+ "selected": True,
218
+ },
219
+ {
220
+ "index": 0,
221
+ "data": numpy.random.random(20 * 20).reshape(20, 20),
222
+ "selected": False,
223
+ },
224
+ ),
225
+ },
226
+ {
227
+ "reduce_frames_name": "tata frames",
228
+ "reduce_frames": (
229
+ {
230
+ "index": "0.25r",
231
+ "data": numpy.random.random(40 * 20).reshape(40, 20),
232
+ "selected": False,
233
+ },
234
+ ),
235
+ },
236
+ )
237
+ ),
238
+ (
239
+ {
240
+ "reduce_frames_name": "toto frames",
241
+ "reduce_frames": (
242
+ {
243
+ "index": 0,
244
+ "data": numpy.random.random(20 * 20).reshape(20, 20),
245
+ "selected": False,
246
+ },
247
+ ),
248
+ },
249
+ {
250
+ "reduce_frames_name": "tata frames",
251
+ "reduce_frames": (
252
+ {
253
+ "index": "0.25r",
254
+ "data": numpy.random.random(40 * 20).reshape(40, 20),
255
+ "selected": False,
256
+ },
257
+ ),
258
+ },
259
+ ),
260
+ )
261
+
262
+ check_reduce_frames_configuration(filter_unselected_reduced_frames(()), ())
263
+
264
+
265
+ def check_reduce_frames_configuration(config_1, config_2):
266
+ """
267
+ simple comparaison of two configurations
268
+ """
269
+ assert len(config_1) == len(config_2)
270
+ for reduce_frame_group_1, reduce_frame_group_2 in zip(config_1, config_2):
271
+ assert reduce_frame_group_1.get(
272
+ "reduce_frames_name", None
273
+ ) == reduce_frame_group_2.get("reduce_frames_name", None)
274
+
275
+ for reduce_frame_group_1, reduce_frame_group_2 in zip(
276
+ reduce_frame_group_1.get("reduce_frames", tuple()),
277
+ reduce_frame_group_2.get("reduce_frames", tuple()),
278
+ ):
279
+ assert reduce_frame_group_1["index"] == reduce_frame_group_2["index"]
280
+ assert reduce_frame_group_1["selected"] == reduce_frame_group_2["selected"]
@@ -202,7 +202,7 @@ class CompareImages(_CompareImages.CompareImages):
202
202
  """Emit when cropping of the compared images has changed"""
203
203
 
204
204
  def __init__(self, parent=None, backend=None):
205
- super().__init__(parent, backend)
205
+ super().__init__(parent, backend=backend)
206
206
  self.__cropComparedImages = True
207
207
 
208
208
  def cropComparedImages(self) -> bool:
@@ -101,8 +101,8 @@ class AxisWindow(qt.QMainWindow):
101
101
  sigLockModeChanged = qt.Signal()
102
102
  """Signal emitted when the lock on the method change"""
103
103
 
104
- def __init__(self, axis_params, parent=None):
105
- qt.QMainWindow.__init__(self, parent=parent)
104
+ def __init__(self, axis_params, parent=None, backend=None):
105
+ super().__init__(parent=parent)
106
106
  self._mainWidget = qt.QWidget(self)
107
107
  self._mainWidget.setLayout(qt.QVBoxLayout())
108
108
  self.setCentralWidget(self._mainWidget)
@@ -119,7 +119,9 @@ class AxisWindow(qt.QMainWindow):
119
119
  self._selectionGB.hide()
120
120
 
121
121
  # add widget for radio and sinogram axis
122
- self._axisWidget = _AxisWidget(parent=self, axis_params=axis_params)
122
+ self._axisWidget = _AxisWidget(
123
+ parent=self, axis_params=axis_params, backend=backend
124
+ )
123
125
  self._mainWidget.layout().addWidget(self._axisWidget)
124
126
 
125
127
  self.setCentralWidget(self._mainWidget)
@@ -226,8 +228,8 @@ class _AxisWidget(qt.QMainWindow):
226
228
 
227
229
  sigSinogramReady = qt.Signal()
228
230
 
229
- def __init__(self, parent, axis_params):
230
- qt.QMainWindow.__init__(self, parent)
231
+ def __init__(self, parent, axis_params, backend=None):
232
+ super().__init__(parent)
231
233
  self._settingsWidget = None
232
234
  self.setDockOptions(qt.QMainWindow.AnimatedDocks)
233
235
 
@@ -253,7 +255,9 @@ class _AxisWidget(qt.QMainWindow):
253
255
  self.addDockWidget(qt.Qt.RightDockWidgetArea, self._controlDockWidget)
254
256
 
255
257
  self._axis_params = axis_params
256
- self._radioAxis = RadioAxisWindow(parent=self, axis=axis_params)
258
+ self._radioAxis = RadioAxisWindow(
259
+ parent=self, axis=axis_params, backend=backend
260
+ )
257
261
  self._plotWidgets = qt.QWidget(self)
258
262
  self._plotWidgets.setLayout(qt.QVBoxLayout())
259
263
  self.setCentralWidget(self._plotWidgets)
@@ -80,8 +80,8 @@ class RadioAxisWindow(qt.QMainWindow):
80
80
  sigPositionChanged = qt.Signal(tuple)
81
81
  """signal emitted when the center of rotation center change"""
82
82
 
83
- def __init__(self, axis, parent=None):
84
- qt.QMainWindow.__init__(self, parent)
83
+ def __init__(self, axis, parent=None, backend=None):
84
+ super().__init__(parent)
85
85
  if isinstance(axis, QAxisRP):
86
86
  self.__recons_params = axis
87
87
  else:
@@ -106,7 +106,7 @@ class RadioAxisWindow(qt.QMainWindow):
106
106
  # cache to know if the y origin has changed since
107
107
 
108
108
  self.setWindowFlags(qt.Qt.Widget)
109
- self._plot = CompareImages(parent=self)
109
+ self._plot = CompareImages(parent=self, backend=backend)
110
110
  self._plot.setAutoResetZoom(False)
111
111
  _mode = CompareImages.VisualizationMode.COMPOSITE_A_MINUS_B
112
112
  self._plot.setVisualizationMode(_mode)
@@ -2565,10 +2565,18 @@ class _ManualFramesSelection(qt.QWidget):
2565
2565
  idx = self._frame1CB.findText(current_angle1)
2566
2566
  if idx >= 0:
2567
2567
  self._frame1CB.setCurrentIndex(idx)
2568
+ if current_angle1 == current_angle2:
2569
+ # if the two current angle are close then we consider it is better to look for angleX - angleX + 180 angles
2570
+ # instead of finding back angles
2571
+ self._findAssociatedAngle()
2572
+ else:
2573
+ idx = self._frame1CB.findText(current_angle1)
2574
+ if idx >= 0:
2575
+ self._frame1CB.setCurrentIndex(idx)
2568
2576
 
2569
- idx = self._frame2CB.findText(current_angle2)
2570
- if idx >= 0:
2571
- self._frame2CB.setCurrentIndex(idx)
2577
+ idx = self._frame2CB.findText(current_angle2)
2578
+ if idx >= 0:
2579
+ self._frame2CB.setCurrentIndex(idx)
2572
2580
 
2573
2581
  def getFramesUrl(self, as_txt=False) -> tuple:
2574
2582
  """
@@ -253,6 +253,7 @@ class RefCopyWidget(qt.QGroupBox):
253
253
  _logger.error(f"Fails to define flat url. Error is {e}")
254
254
  return False
255
255
  else:
256
+ self._statusBar.showMessage(f"darks set from {url.path()}")
256
257
  DarkRefsCopy.save_flats_to_be_copied(self.__save_dir, data=url)
257
258
  return True
258
259
  return False
@@ -268,6 +269,7 @@ class RefCopyWidget(qt.QGroupBox):
268
269
  _logger.error(f"Fails to define flat url. Error is {e}")
269
270
  return False
270
271
  else:
272
+ self._statusBar.showMessage(f"darks set from {url.path()}")
271
273
  DarkRefsCopy.save_darks_to_be_copied(self.__save_dir, data=url)
272
274
  return True
273
275
  return False
@@ -33,7 +33,7 @@ import logging
33
33
  from silx.gui import qt
34
34
 
35
35
  from tomwer.core.process.reconstruction.darkref import params as dkrf
36
- from tomwer.core.process.reconstruction.darkref.darkrefs import DarkRefs
36
+ from tomwer.core.process.reconstruction.darkref.darkrefs import DarkRefsTask
37
37
  from tomwer.core.scan.scanbase import TomwerScanBase
38
38
  from tomwer.gui.utils.sandboxes import RegularExpressionSandBox
39
39
  from tomwer.synctools.darkref import QDKRFRP
@@ -89,7 +89,7 @@ class DarkRefWidget(qt.QWidget):
89
89
  return self.mainWidget.recons_params
90
90
 
91
91
 
92
- class QDarkRefs(DarkRefs):
92
+ class QDarkRefs(DarkRefsTask):
93
93
  def _computationStarts(self):
94
94
  pass
95
95
 
@@ -232,14 +232,14 @@ class _TabExpert(qt.QWidget):
232
232
  qt.QLabel("pyhst dark file pattern", parent=self._patternsWidget), 0, 0
233
233
  )
234
234
  self._darkLE = qt.QLineEdit(parent=self._patternsWidget)
235
- self._darkLE.setToolTip(DarkRefs.getDarkPatternTooltip())
235
+ self._darkLE.setToolTip(DarkRefsTask.getDarkPatternTooltip())
236
236
  self._darkLE.editingFinished.connect(self._darkPatternEdited)
237
237
  self._patternsWidget.layout().addWidget(self._darkLE, 0, 1)
238
238
  self._patternsWidget.layout().addWidget(
239
239
  qt.QLabel("pyhst flat file pattern", parent=self._patternsWidget), 1, 0
240
240
  )
241
241
  self._refLE = qt.QLineEdit(parent=self._patternsWidget)
242
- self._refLE.setToolTip(DarkRefs.getRefPatternTooltip())
242
+ self._refLE.setToolTip(DarkRefsTask.getRefPatternTooltip())
243
243
  self._refLE.editingFinished.connect(self._refPatternEdited)
244
244
 
245
245
  self._patternsWidget.layout().addWidget(self._refLE, 1, 1)
@@ -181,7 +181,9 @@ class NabuPaganinConfig(qt.QWidget, base._NabuStageConfigBase):
181
181
  label = DELTA_CHAR + " / " + BETA_CHAR
182
182
  self._db_label = qt.QLabel(label, self)
183
183
  self.layout().addWidget(self._db_label, 0, 0, 1, 1)
184
- self._deltaBetaQLE = SelectionLineEdit("100.0", self)
184
+ self._deltaBetaQLE = SelectionLineEdit(
185
+ "100.0", self, allow_negative_indices=False
186
+ )
185
187
  self.layout().addWidget(self._deltaBetaQLE, 0, 1, 1, 3)
186
188
  self.registerWidget(self._db_label, "required")
187
189
  self.registerWidget(self._deltaBetaQLE, "required")
@@ -372,42 +372,43 @@ class _NabuPreProcessingConfig(_NabuStageConfigBase, qt.QWidget):
372
372
  except Exception as e:
373
373
  _logger.error(e)
374
374
 
375
- def _setConfiguration(self, conf):
376
- if "flatfield" in conf:
377
- ff = conf["flatfield"]
378
- if ff is not None:
379
- self._flatFieldCB.setChecked(bool(ff))
380
- if "double_flatfield_enabled" in conf:
381
- dff = conf["double_flatfield_enabled"]
382
- if dff is not None:
383
- self._dffCB.setChecked(bool(dff))
384
- if "dff_sigma" in conf:
385
- dff_sigma = conf["dff_sigma"]
386
- if dff_sigma not in (None, "", "none"):
387
- self._dffSigmaQDSB.setValue(float(dff_sigma))
388
- if "ccd_filter_enabled" in conf:
389
- ccd_filter = conf["ccd_filter_enabled"]
390
- if ccd_filter not in (None, "", "none"):
391
- self._ccdFilterCB.setChecked(bool(ccd_filter))
392
- if "ccd_filter_threshold" in conf:
393
- ccd_filter_threshold = conf["ccd_filter_threshold"]
394
- if ccd_filter_threshold not in (None, "", "none"):
395
- self._ccdThreshold.setValue(float(ccd_filter_threshold))
375
+ def _setConfiguration(self, conf: dict):
376
+ ff = conf.get("flatfield", None)
377
+ if ff is not None:
378
+ self._flatFieldCB.setChecked(bool(ff))
379
+
380
+ dff = conf.get("double_flatfield_enabled", None)
381
+ if dff is not None:
382
+ self._dffCB.setChecked(bool(dff))
383
+
384
+ dff_sigma = conf.get("dff_sigma", None)
385
+ if dff_sigma not in (None, "", "none"):
386
+ self._dffSigmaQDSB.setValue(float(dff_sigma))
387
+
388
+ ccd_filter = conf.get("ccd_filter_enabled", None)
389
+ if ccd_filter not in (None, "", "none"):
390
+ self._ccdFilterCB.setChecked(bool(ccd_filter))
391
+
392
+ ccd_filter_threshold = conf.get("ccd_filter_threshold", None)
393
+ if ccd_filter_threshold not in (None, "", "none"):
394
+ self._ccdThreshold.setValue(float(ccd_filter_threshold))
395
+
396
396
  normalize_srcurrent = conf.get("normalize_srcurrent", None)
397
397
  if normalize_srcurrent is not None:
398
398
  self.setNormalizeCurrent(bool(normalize_srcurrent))
399
- if "take_logarithm" in conf:
400
- take_logarithm = conf["take_logarithm"]
401
- if take_logarithm not in (None, "", "none"):
402
- self._takeLogarithmCB.setChecked(bool(take_logarithm))
403
- if "log_min_clip" in conf:
404
- clip_value = conf["log_min_clip"]
405
- if clip_value not in (None, "", "none"):
406
- self._clipMinLogValue.setValue(float(clip_value))
407
- if "log_max_clip" in conf:
408
- clip_value = conf["log_max_clip"]
409
- if clip_value not in (None, "", "none"):
410
- self._clipMaxLogValue.setValue(float(clip_value))
399
+
400
+ take_logarithm = conf.get("take_logarithm", None)
401
+ if take_logarithm not in (None, "", "none"):
402
+ self._takeLogarithmCB.setChecked(bool(take_logarithm))
403
+
404
+ clip_value = conf.get("log_min_clip", None)
405
+ if clip_value not in (None, "", "none"):
406
+ self._clipMinLogValue.setValue(float(clip_value))
407
+
408
+ clip_value = conf.get("log_max_clip", None)
409
+ if clip_value not in (None, "", "none"):
410
+ self._clipMaxLogValue.setValue(float(clip_value))
411
+
411
412
  sino_rings_correction = conf.get("sino_rings_correction", None)
412
413
  if sino_rings_correction is not None:
413
414
  if sino_rings_correction == "":
@@ -71,7 +71,7 @@ class SliceGroupBox(qt.QGroupBox):
71
71
  self.layout().addWidget(self._modeCB)
72
72
  self._modeCB.setFocusPolicy(qt.Qt.FocusPolicy.NoFocus)
73
73
 
74
- self._sliceQLE = SelectionLineEdit(parent=self)
74
+ self._sliceQLE = SelectionLineEdit(parent=self, allow_negative_indices=True)
75
75
  self.layout().addWidget(self._sliceQLE)
76
76
 
77
77
  spacer = qt.QWidget(parent=self)
@@ -58,13 +58,13 @@ class SinoNormWindow(qt.QMainWindow):
58
58
  sigConfigurationChanged = qt.Signal()
59
59
  """signal emit when the configuration change"""
60
60
 
61
- def __init__(self, parent):
61
+ def __init__(self, parent, backend=None):
62
62
  qt.QMainWindow.__init__(self, parent)
63
63
  self._scan = None
64
64
  self.setWindowFlags(qt.Qt.Widget)
65
65
 
66
66
  # central widget
67
- self._centralWidget = _Viewer(self)
67
+ self._centralWidget = _Viewer(self, backend=backend)
68
68
  self.setCentralWidget(self._centralWidget)
69
69
 
70
70
  # control widget (options + ctrl buttons)
@@ -198,13 +198,13 @@ class SinoNormWindow(qt.QMainWindow):
198
198
 
199
199
 
200
200
  class _Viewer(qt.QTabWidget):
201
- def __init__(self, parent):
201
+ def __init__(self, parent, backend=None):
202
202
  if not isinstance(parent, SinoNormWindow):
203
203
  raise TypeError("Expect a NormIntensityWindow as parrent")
204
204
  qt.QTabWidget.__init__(self, parent)
205
- self._projView = _ProjPlotWithROI(parent=self)
205
+ self._projView = _ProjPlotWithROI(parent=self, backend=backend)
206
206
  self.addTab(self._projView, "projection view")
207
- self._sinoView = SinogramViewer(parent=self)
207
+ self._sinoView = SinogramViewer(parent=self, backend=backend)
208
208
  self.addTab(self._sinoView, "sinogram view")
209
209
 
210
210
  # connect signal / Slot
@@ -550,6 +550,7 @@ class _EstimatedCorWidget(qt.QGroupBox):
550
550
  self._relLabel.setVisible(manual_opt_visible)
551
551
  self._manualCORRel.setVisible(manual_opt_visible)
552
552
  self._manualCORAbs.setVisible(manual_opt_visible)
553
+ self._autoCorPB.setVisible(manual_opt_visible)
553
554
 
554
555
  def _relativePositionChanged(self, *args, **kwargs):
555
556
  if self._frameWidth is not None:
@@ -43,7 +43,7 @@ from silx.gui import qt
43
43
  from tomwer.core.process.reconstruction.axis import mode as axis_mode
44
44
  from tomwer.core.process.reconstruction.nabu.utils import _NabuMode
45
45
  from tomwer.core.process.reconstruction.saaxis.params import SAAxisParams
46
- from tomwer.core.process.reconstruction.saaxis.saaxis import SAAxisProcess
46
+ from tomwer.core.process.reconstruction.saaxis.saaxis import SAAxisTask
47
47
  from tomwer.gui import icons
48
48
  from tomwer.gui.reconstruction.axis.radioaxis import _CalculationWidget
49
49
  from tomwer.gui.reconstruction.nabu.slices import NabuWindow
@@ -71,7 +71,7 @@ class ScorePlot(_ScorePlot, constructor=CorSelection):
71
71
  scan.saaxis_params.score_method = self.getScoreMethod()
72
72
  img_width = scan.dim_1
73
73
  # update autofocus
74
- SAAxisProcess.autofocus(scan)
74
+ SAAxisTask.autofocus(scan)
75
75
  else:
76
76
  img_width = None
77
77
  self.setVarScores(
@@ -145,7 +145,7 @@ class _SAAxisTabWidget(qt.QTabWidget):
145
145
  like slice to reconstruct, number of reconstruction, research width,
146
146
  nabu reconstruction parameters..."""
147
147
 
148
- def __init__(self, parent):
148
+ def __init__(self, parent, backend=None):
149
149
  qt.QTabWidget.__init__(self, parent)
150
150
  # select slice & cor range
151
151
 
@@ -159,7 +159,7 @@ class _SAAxisTabWidget(qt.QTabWidget):
159
159
  nabu_icon = icons.getQIcon("nabu")
160
160
  self.addTab(self._nabuSettings, nabu_icon, "reconstruction settings")
161
161
  # results
162
- self._resultsViewer = ScorePlot(self, variable_name="cor")
162
+ self._resultsViewer = ScorePlot(self, variable_name="cor", backend=backend)
163
163
  results_icon = icons.getQIcon("results")
164
164
  self.addTab(self._resultsViewer, results_icon, "reconstructed slices")
165
165
 
@@ -312,7 +312,7 @@ class SAAxisWindow(qt.QMainWindow):
312
312
  Widget used to determine half-automatically the center of rotation
313
313
  """
314
314
 
315
- def __init__(self, parent=None):
315
+ def __init__(self, parent=None, backend=None):
316
316
  qt.QMainWindow.__init__(self, parent)
317
317
  self._scan = None
318
318
  self._automaticCorWidget = None
@@ -324,7 +324,7 @@ class SAAxisWindow(qt.QMainWindow):
324
324
 
325
325
  self._scanInfo = ScanNameLabelAndShape(self)
326
326
  self._mainWidget.layout().addWidget(self._scanInfo)
327
- self._tabWidget = _SAAxisTabWidget(self)
327
+ self._tabWidget = _SAAxisTabWidget(self, backend=backend)
328
328
  self._mainWidget.layout().addWidget(self._tabWidget)
329
329
  self.setCentralWidget(self._mainWidget)
330
330
  # next and previous buttons for browsing the tab widget