tomwer 1.3.12__py3-none-any.whl → 1.3.26__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.
- orangecontrib/tomwer/widgets/reconstruction/DarkRefAndCopyOW.py +1 -0
- orangecontrib/tomwer/widgets/reconstruction/NabuHelicalPrepareWeightsDoubleOW.py +184 -184
- tomwer/app/canvas_launcher/mainwindow.py +0 -1
- tomwer/app/zstitching.py +0 -1
- tomwer/core/cluster/cluster.py +0 -9
- tomwer/core/process/control/datalistener/datalistener.py +4 -1
- tomwer/core/process/reconstruction/axis/params.py +3 -3
- tomwer/core/process/reconstruction/darkref/darkrefscopy.py +34 -6
- tomwer/core/process/reconstruction/nabu/utils.py +4 -2
- tomwer/core/utils/scanutils.py +5 -1
- tomwer/gui/cluster/slurm.py +1 -21
- tomwer/gui/cluster/test/test_cluster.py +0 -1
- tomwer/gui/control/selectorwidgetbase.py +3 -1
- tomwer/gui/edit/nxtomoeditor.py +28 -20
- tomwer/gui/edit/test/test_nx_editor.py +58 -1
- tomwer/gui/reconstruction/axis/axis.py +16 -13
- tomwer/gui/reconstruction/axis/radioaxis.py +0 -1
- tomwer/gui/reconstruction/darkref/darkrefcopywidget.py +11 -0
- tomwer/gui/reconstruction/nabu/nabuconfig/preprocessing.py +5 -4
- tomwer/gui/stitching/stitching.py +8 -3
- tomwer/gui/visualization/dataviewer.py +27 -15
- tomwer/gui/visualization/diffviewer/diffviewer.py +9 -8
- tomwer/synctools/stacks/reconstruction/dkrefcopy.py +10 -0
- tomwer/tests/datasets.py +5 -1
- tomwer/utils.py +1 -4
- tomwer/version.py +1 -1
- {tomwer-1.3.12.dist-info → tomwer-1.3.26.dist-info}/METADATA +34 -48
- {tomwer-1.3.12.dist-info → tomwer-1.3.26.dist-info}/RECORD +34 -34
- {tomwer-1.3.12.dist-info → tomwer-1.3.26.dist-info}/WHEEL +1 -1
- /tomwer-1.3.12-py3.11-nspkg.pth → /tomwer-1.3.26-py3.11-nspkg.pth +0 -0
- {tomwer-1.3.12.dist-info → tomwer-1.3.26.dist-info}/LICENSE +0 -0
- {tomwer-1.3.12.dist-info → tomwer-1.3.26.dist-info}/entry_points.txt +0 -0
- {tomwer-1.3.12.dist-info → tomwer-1.3.26.dist-info}/namespace_packages.txt +0 -0
- {tomwer-1.3.12.dist-info → tomwer-1.3.26.dist-info}/top_level.txt +0 -0
@@ -156,7 +156,9 @@ class _SelectorWidget(qt.QMainWindow):
|
|
156
156
|
|
157
157
|
def removeSelectedDatasets(self):
|
158
158
|
sItem = self.dataList.selectedItems()
|
159
|
-
selection = [
|
159
|
+
selection = [
|
160
|
+
_item.data(qt.Qt.UserRole).get_identifier().to_str() for _item in sItem
|
161
|
+
]
|
160
162
|
|
161
163
|
with block_signals(self):
|
162
164
|
# make sure sigUpdated is called only once.
|
tomwer/gui/edit/nxtomoeditor.py
CHANGED
@@ -574,28 +574,36 @@ class NXtomoEditor(qt.QWidget):
|
|
574
574
|
),
|
575
575
|
solve_empty_dependency=True,
|
576
576
|
)
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
577
|
+
if nexus_paths.nx_detector_paths.NX_TRANSFORMATIONS is not None:
|
578
|
+
# old NXtomo are not handling NX_TRANSFORMATIONS
|
579
|
+
detector_transformation_path = "/".join(
|
580
|
+
(
|
581
|
+
nexus_paths.INSTRUMENT_PATH,
|
582
|
+
nexus_paths.nx_instrument_paths.DETECTOR_PATH,
|
583
|
+
nexus_paths.nx_detector_paths.NX_TRANSFORMATIONS,
|
584
|
+
),
|
585
|
+
)
|
586
|
+
if detector_transformation_path in entry:
|
587
|
+
del entry[detector_transformation_path]
|
588
|
+
|
589
|
+
detector_transformation_path = "/".join(
|
590
|
+
(scan.entry, detector_transformation_path)
|
591
|
+
)
|
592
|
+
else:
|
593
|
+
_logger.debug(
|
594
|
+
"Old version of NXtomo found. No information about transformation will be saved"
|
595
|
+
)
|
596
|
+
detector_transformation_path = None
|
597
|
+
|
598
|
+
if detector_transformation_path is not None:
|
599
|
+
dicttonx(
|
600
|
+
nx_dict,
|
601
|
+
h5file=scan.master_file,
|
602
|
+
h5path=detector_transformation_path,
|
603
|
+
update_mode="replace",
|
604
|
+
mode="a",
|
589
605
|
)
|
590
606
|
|
591
|
-
dicttonx(
|
592
|
-
nx_dict,
|
593
|
-
h5file=scan.master_file,
|
594
|
-
h5path=detector_transformation_path,
|
595
|
-
update_mode="replace",
|
596
|
-
mode="a",
|
597
|
-
)
|
598
|
-
|
599
607
|
# clear caches to make sure all modifications will be considered
|
600
608
|
scan.clear_caches()
|
601
609
|
scan.clear_frames_caches()
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import os
|
2
|
+
import h5py
|
2
3
|
|
3
4
|
import numpy
|
4
5
|
import pytest
|
@@ -252,7 +253,7 @@ def test_nx_editor_lock(
|
|
252
253
|
# 3.0 save the nxtomo
|
253
254
|
widget.overwriteNXtomo()
|
254
255
|
|
255
|
-
# 4.0 check save went
|
256
|
+
# 4.0 check save went well
|
256
257
|
overwrite_nx_tomo = NXtomo().load(
|
257
258
|
file_path=file_path,
|
258
259
|
data_path=entry,
|
@@ -305,3 +306,59 @@ def test_nx_editor_lock(
|
|
305
306
|
"instrument.detector.x_flipped": (False, False),
|
306
307
|
"instrument.detector.y_flipped": (True, False),
|
307
308
|
}
|
309
|
+
|
310
|
+
|
311
|
+
def test_nxtomo_editor_with_missing_paths(
|
312
|
+
tmp_path,
|
313
|
+
qtapp, # noqa F811
|
314
|
+
):
|
315
|
+
"""
|
316
|
+
test widget behavior in the case some nxtomo path don't exist
|
317
|
+
"""
|
318
|
+
|
319
|
+
# create nx tomo with raw data
|
320
|
+
nx_tomo = NXtomo()
|
321
|
+
nx_tomo.instrument.detector.image_key_control = [ImageKey.PROJECTION.value] * 12
|
322
|
+
nx_tomo.instrument.detector.data = numpy.empty(shape=(12, 10, 10))
|
323
|
+
nx_tomo.sample.rotation_angle = numpy.linspace(0, 20, num=12)
|
324
|
+
|
325
|
+
file_path = os.path.join(tmp_path, "nxtomo.nx")
|
326
|
+
entry = "entry0000"
|
327
|
+
nx_tomo.save(
|
328
|
+
file_path=file_path,
|
329
|
+
data_path=entry,
|
330
|
+
)
|
331
|
+
# delete some path that can be missing in some case
|
332
|
+
with h5py.File(file_path, mode="a") as h5f:
|
333
|
+
assert "entry0000" in h5f
|
334
|
+
assert "entry0000/beam" not in h5f
|
335
|
+
assert "entry0000/instrument/beam" not in h5f
|
336
|
+
assert "entry0000/instrument/detector/distance" not in h5f
|
337
|
+
assert "entry0000/instrument/detector/x_pixel_size" not in h5f
|
338
|
+
assert "entry0000/instrument/detector/y_pixel_size" not in h5f
|
339
|
+
assert "entry0000/instrument/detector/transformations" not in h5f
|
340
|
+
|
341
|
+
scan = NXtomoScan(file_path, entry)
|
342
|
+
|
343
|
+
# create the widget and do the edition
|
344
|
+
widget = NXtomoEditor()
|
345
|
+
|
346
|
+
widget.setScan(scan=scan)
|
347
|
+
|
348
|
+
widget._distanceMetricEntry.setValue(0.05)
|
349
|
+
widget._energyEntry.setValue(50)
|
350
|
+
widget._xPixelSizeMetricEntry.setValue(0.02)
|
351
|
+
widget._yPixelSizeMetricEntry.setValue(0.03)
|
352
|
+
|
353
|
+
# overwrite the NXtomo
|
354
|
+
widget.overwriteNXtomo()
|
355
|
+
|
356
|
+
# check save went well
|
357
|
+
overwrite_nx_tomo = NXtomo().load(
|
358
|
+
file_path=file_path,
|
359
|
+
data_path=entry,
|
360
|
+
)
|
361
|
+
assert overwrite_nx_tomo.instrument.detector.x_pixel_size.value == 0.02
|
362
|
+
assert overwrite_nx_tomo.instrument.detector.y_pixel_size.value == 0.03
|
363
|
+
assert overwrite_nx_tomo.energy.value == 50
|
364
|
+
assert overwrite_nx_tomo.instrument.detector.distance.value == 0.05
|
@@ -31,6 +31,7 @@ __license__ = "MIT"
|
|
31
31
|
__date__ = "14/10/2019"
|
32
32
|
|
33
33
|
|
34
|
+
import numpy
|
34
35
|
import logging
|
35
36
|
from typing import Optional
|
36
37
|
|
@@ -272,6 +273,7 @@ class _AxisWidget(qt.QMainWindow):
|
|
272
273
|
self._axis_params.relative_cor_value,
|
273
274
|
self._axis_params.absolute_cor_value,
|
274
275
|
)
|
276
|
+
self._controlWidget._positionInfo.setAxis(self._axis_params)
|
275
277
|
|
276
278
|
# connect signal / slots
|
277
279
|
self._controlWidget.sigComputationRequest.connect(self.sigComputationRequested)
|
@@ -663,7 +665,13 @@ class _PositionInfoWidget(qt.QWidget):
|
|
663
665
|
if self._relativePositionQLE.text().startswith((".", "?")):
|
664
666
|
return
|
665
667
|
else:
|
666
|
-
|
668
|
+
value = float(self._relativePositionQLE.text())
|
669
|
+
# make sure we only emit the signal if the value changed (and when the Qline has been edited).
|
670
|
+
if self._axis.relative_cor_value is None or (
|
671
|
+
self._axis is not None
|
672
|
+
and not numpy.isclose(value, self._axis.relative_cor_value, atol=1e-3)
|
673
|
+
):
|
674
|
+
self.sigRelativeValueSet.emit(value)
|
667
675
|
|
668
676
|
def _userUpdatedAbsolutePosition(self, *args, **kwargs):
|
669
677
|
palette = self.palette()
|
@@ -675,24 +683,19 @@ class _PositionInfoWidget(qt.QWidget):
|
|
675
683
|
if self._absolutePositionQLE.text().startswith((".", "?")):
|
676
684
|
return
|
677
685
|
else:
|
678
|
-
|
686
|
+
value = float(self._absolutePositionQLE.text())
|
687
|
+
# make sure we only emit the signal if the value changed (and when the Qline has been edited).
|
688
|
+
if self._axis.absolute_cor_value is None or (
|
689
|
+
self._axis is not None
|
690
|
+
and not numpy.isclose(value, self._axis.absolute_cor_value, atol=1e-3)
|
691
|
+
):
|
692
|
+
self.sigAbsolueValueSet.emit(value)
|
679
693
|
|
680
694
|
def setAxis(self, axis):
|
681
695
|
assert isinstance(axis, QAxisRP)
|
682
696
|
if axis == self._axis:
|
683
697
|
return
|
684
|
-
if self._axis is not None:
|
685
|
-
self._axis.sigChanged.disconnect(self._updatePosition)
|
686
698
|
self._axis = axis
|
687
|
-
self._axis.sigChanged.connect(self._updatePosition)
|
688
|
-
self._updatePosition()
|
689
|
-
|
690
|
-
def _updatePosition(self):
|
691
|
-
if self._axis:
|
692
|
-
self.setPosition(
|
693
|
-
relative_cor=self._axis.relative_cor_value,
|
694
|
-
abs_cor=self._axis.absolute_cor_value,
|
695
|
-
)
|
696
699
|
|
697
700
|
def getPosition(self):
|
698
701
|
return float(self._relativePositionQLE.text())
|
@@ -54,6 +54,7 @@ class DarkRefAndCopyWidget(DarkRefWidget):
|
|
54
54
|
"""Signal emitted when the mode auto change"""
|
55
55
|
sigCopyActivationChanged = qt.Signal()
|
56
56
|
"""Signal emitted when the copy is activated or deactivated"""
|
57
|
+
sigClearCache = qt.Signal()
|
57
58
|
|
58
59
|
def __init__(self, save_dir: str, parent=None, reconsparams=None, process_id=None):
|
59
60
|
DarkRefWidget.__init__(
|
@@ -79,6 +80,7 @@ class DarkRefAndCopyWidget(DarkRefWidget):
|
|
79
80
|
self._refCopyWidget.sigCopyActivationChanged.connect(
|
80
81
|
self._triggerCopyActivation
|
81
82
|
)
|
83
|
+
self._refCopyWidget.sigClearCache.connect(self.sigClearCache)
|
82
84
|
|
83
85
|
def setRefSetBy(self, scan_id: str):
|
84
86
|
self._refCopyWidget._statusBar.showMessage(f"ref set from {scan_id}")
|
@@ -155,6 +157,8 @@ class RefCopyWidget(qt.QGroupBox):
|
|
155
157
|
"""Signal emitted when the mode auto change"""
|
156
158
|
sigCopyActivationChanged = qt.Signal()
|
157
159
|
"""Signal emitted when the copy is activated or deactivated"""
|
160
|
+
sigClearCache = qt.Signal()
|
161
|
+
"""Signal when the cache needs to be cleared"""
|
158
162
|
|
159
163
|
_DEFAULT_DIRECTORY = "/lbsram/data/visitor"
|
160
164
|
"""Default directory used when the user need to set path to references"""
|
@@ -190,6 +194,12 @@ class RefCopyWidget(qt.QGroupBox):
|
|
190
194
|
spacer = qt.QWidget(self)
|
191
195
|
spacer.setSizePolicy(qt.QSizePolicy.Minimum, qt.QSizePolicy.Expanding)
|
192
196
|
self.layout().addWidget(spacer)
|
197
|
+
self._removeCacheFile = qt.QPushButton("clear cache")
|
198
|
+
self._removeCacheFile.setToolTip(
|
199
|
+
"Remove the file used for cacheing reduce dark / flat."
|
200
|
+
)
|
201
|
+
self.layout().addWidget(self._removeCacheFile)
|
202
|
+
|
193
203
|
self.layout().addWidget(self.__createStatusBarGUI())
|
194
204
|
|
195
205
|
self.setModeAuto(True)
|
@@ -201,6 +211,7 @@ class RefCopyWidget(qt.QGroupBox):
|
|
201
211
|
# connect signal / slot
|
202
212
|
self.toggled.connect(self._triggerCopyActivated)
|
203
213
|
self._qcbAutoMode.toggled.connect(self._triggerModeAutoChanged)
|
214
|
+
self._removeCacheFile.released.connect(self.sigClearCache)
|
204
215
|
|
205
216
|
def _triggerCopyActivated(self, *args, **kwargs):
|
206
217
|
self.sigCopyActivationChanged.emit()
|
@@ -188,13 +188,14 @@ class _NabuPreProcessingConfig(_NabuStageConfigBase, qt.QWidget):
|
|
188
188
|
|
189
189
|
# option dedicated to Helical
|
190
190
|
## process file
|
191
|
-
self.
|
191
|
+
self._processFileLabel = qt.QLabel("file containing weights maps", self)
|
192
|
+
self.registerWidget(self._processFileLabel, "advanced")
|
193
|
+
self.layout().addWidget(self._processFileLabel, 20, 0, 1, 1)
|
194
|
+
self._processFileQLE = qt.QLineEdit("", self)
|
195
|
+
self.registerWidget(self._processFileQLE, "advanced")
|
192
196
|
self._processFileQLE.setToolTip(
|
193
197
|
"also know as 'process_file'. If you don't have this file it can be created from the 'helical-prepare-weights' widget"
|
194
198
|
)
|
195
|
-
self.layout().addWidget(self._processFileQLE, 20, 0, 1, 1)
|
196
|
-
self._processFileQLE = qt.QLineEdit("", self)
|
197
|
-
self.registerWidget(self._processFileQLE, "advanced")
|
198
199
|
self.layout().addWidget(self._processFileQLE, 20, 1, 1, 3)
|
199
200
|
|
200
201
|
# style
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import logging
|
2
2
|
import os
|
3
|
+
import shutil
|
3
4
|
import tempfile
|
4
5
|
import functools
|
5
6
|
|
@@ -399,7 +400,7 @@ class ZStitchingWindow(qt.QMainWindow):
|
|
399
400
|
# separator
|
400
401
|
toolbar.addSeparator()
|
401
402
|
|
402
|
-
#
|
403
|
+
# configuration level / mode
|
403
404
|
self.__configurationModesAction = qt.QAction(self)
|
404
405
|
self.__configurationModesAction.setCheckable(False)
|
405
406
|
menu = qt.QMenu(self)
|
@@ -602,6 +603,8 @@ class ZStitchingWindow(qt.QMainWindow):
|
|
602
603
|
self._callbackToSetSlurmConfig = callback
|
603
604
|
|
604
605
|
def close(self):
|
606
|
+
# remove folder used for preview
|
607
|
+
shutil.rmtree(self._previewFolder, ignore_errors=True)
|
605
608
|
self._widget.close()
|
606
609
|
# requested for the waiting plot update
|
607
610
|
super().close()
|
@@ -618,7 +621,6 @@ class ZStitchingWindow(qt.QMainWindow):
|
|
618
621
|
|
619
622
|
def getPreviewFolder(self):
|
620
623
|
if self._previewFolder is None:
|
621
|
-
# TODO: improve management of file: must be removed when the widget is closed...
|
622
624
|
self._previewFolder = tempfile.mkdtemp(prefix="tomwer_stitcher_preview")
|
623
625
|
return self._previewFolder
|
624
626
|
|
@@ -782,7 +784,6 @@ class ZStitchingWindow(qt.QMainWindow):
|
|
782
784
|
tomo_obj = existing_tomo_obj.get(tomo_obj_id, None)
|
783
785
|
if tomo_obj is None:
|
784
786
|
continue
|
785
|
-
# TODO: recuperer le tomo obj a partir de l'identifiant
|
786
787
|
if update_requested[0]:
|
787
788
|
tomo_obj.stitching_metadata.setPxPos(int(new_axis_0_pos), 0)
|
788
789
|
if update_requested[2]:
|
@@ -859,6 +860,10 @@ class ZStitchingWindow(qt.QMainWindow):
|
|
859
860
|
level >= ConfigurationLevel.ADVANCED
|
860
861
|
)
|
861
862
|
|
863
|
+
def close(self):
|
864
|
+
shutil.rmtree(self._previewFolder, ignore_errors=True)
|
865
|
+
super().close()
|
866
|
+
|
862
867
|
|
863
868
|
def concatenate_dict(dict_1, dict_2) -> dict:
|
864
869
|
"""update dict which has dict as values. And we want concatenate those values to"""
|
@@ -34,7 +34,6 @@ from silx.gui import qt
|
|
34
34
|
from silx.gui.dialog.ColormapDialog import DisplayMode
|
35
35
|
from silx.gui.plot.ImageStack import ImageStack as _ImageStack
|
36
36
|
from silx.gui.plot.ImageStack import UrlLoader
|
37
|
-
from silx.gui.utils.signal import SignalProxy
|
38
37
|
from silx.io.url import DataUrl
|
39
38
|
from silx.utils.enum import Enum as _Enum
|
40
39
|
|
@@ -86,17 +85,6 @@ class DataViewer(qt.QMainWindow):
|
|
86
85
|
self._viewer.getPlotWidget().setKeepDataAspectRatio(True)
|
87
86
|
self.setCentralWidget(self._viewer)
|
88
87
|
|
89
|
-
# signal / slot
|
90
|
-
# add a signal proxy on the QSlider
|
91
|
-
self._viewer._slider.sigCurrentUrlIndexChanged.disconnect(
|
92
|
-
self._viewer.setCurrentUrlIndex
|
93
|
-
)
|
94
|
-
self._proxySig = SignalProxy(
|
95
|
-
self._viewer._slider.sigCurrentUrlIndexChanged,
|
96
|
-
delay=0.3,
|
97
|
-
slot=self._urlIndexDelayed,
|
98
|
-
)
|
99
|
-
|
100
88
|
# display control
|
101
89
|
self._controls = DisplayControl(parent=self)
|
102
90
|
self._controlsDW = qt.QDockWidget(self)
|
@@ -110,6 +98,33 @@ class DataViewer(qt.QMainWindow):
|
|
110
98
|
self._controls.sigDisplayModeChanged.connect(self._updateDisplay)
|
111
99
|
self._controls.sigDisplayModeChanged.connect(self.sigConfigChanged)
|
112
100
|
|
101
|
+
# upgrade of the slider (see details in '__sliderPressed' docstring).
|
102
|
+
horizontal_slider = self._viewer._slider
|
103
|
+
horizontal_slider._slider.sliderReleased.connect(self.__sliderReleased)
|
104
|
+
horizontal_slider._slider.sliderPressed.connect(self.__sliderPressed)
|
105
|
+
|
106
|
+
def __sliderPressed(self):
|
107
|
+
"""
|
108
|
+
today each time the slider value is modified it will load the frame and display it
|
109
|
+
but in our case we cannot afford it as it will take too much memory.
|
110
|
+
So we will disconnect the callback (self._viewer.setCurrentUrlIndex) until the slider is active
|
111
|
+
and reactivate it afterwards
|
112
|
+
"""
|
113
|
+
self._viewer._slider.sigCurrentUrlIndexChanged.disconnect(
|
114
|
+
self._viewer.setCurrentUrlIndex
|
115
|
+
)
|
116
|
+
|
117
|
+
def __sliderReleased(self):
|
118
|
+
"""
|
119
|
+
See details in '__sliderPressed'
|
120
|
+
"""
|
121
|
+
horizontal_slider = self._viewer._slider
|
122
|
+
self._viewer._slider.sigCurrentUrlIndexChanged.connect(
|
123
|
+
self._viewer.setCurrentUrlIndex
|
124
|
+
)
|
125
|
+
# set the url with the latest value to display the requested frame
|
126
|
+
self._viewer.setCurrentUrlIndex(horizontal_slider.value())
|
127
|
+
|
113
128
|
def getPlotWidget(self):
|
114
129
|
return self._viewer.getPlotWidget()
|
115
130
|
|
@@ -134,9 +149,6 @@ class DataViewer(qt.QMainWindow):
|
|
134
149
|
self._viewer = None
|
135
150
|
super().close()
|
136
151
|
|
137
|
-
def _urlIndexDelayed(self, *args, **kwargs):
|
138
|
-
self._viewer.setCurrentUrlIndex(args[0][0])
|
139
|
-
|
140
152
|
def getScan(self):
|
141
153
|
if self._scan:
|
142
154
|
return self._scan()
|
@@ -25,6 +25,7 @@
|
|
25
25
|
"""
|
26
26
|
contains gui relative frame difference display
|
27
27
|
"""
|
28
|
+
from __future__ import annotations
|
28
29
|
|
29
30
|
__authors__ = ["H. Payno"]
|
30
31
|
__license__ = "MIT"
|
@@ -148,7 +149,7 @@ class _FrameSelector(qt.QWidget):
|
|
148
149
|
return
|
149
150
|
|
150
151
|
urls = []
|
151
|
-
|
152
|
+
urls_to_angles: dict[str, float] = {}
|
152
153
|
self._currentFrameUrlsText.clear()
|
153
154
|
self._frameUrlCB.clear()
|
154
155
|
if type_selected == self.FrameType.DARKS:
|
@@ -162,7 +163,7 @@ class _FrameSelector(qt.QWidget):
|
|
162
163
|
angles_and_urls = self._scan.get_proj_angle_url(with_alignment=False)
|
163
164
|
for angle, url in angles_and_urls.items():
|
164
165
|
urls.append(url)
|
165
|
-
|
166
|
+
urls_to_angles[url.path()] = angle
|
166
167
|
else:
|
167
168
|
urls = self._scan.projections.values()
|
168
169
|
elif type_selected == self.FrameType.ALIGN_PROJ:
|
@@ -174,14 +175,14 @@ class _FrameSelector(qt.QWidget):
|
|
174
175
|
raise ValueError(f"Type {type_selected} not managed")
|
175
176
|
urls = sorted(urls, key=lambda url: url.path())
|
176
177
|
|
177
|
-
# if
|
178
|
+
# if there is some angles missing, avoiding setting any angle because they are probably wrong
|
178
179
|
# this will probably fail with EDF but this is legacy
|
179
|
-
if len(
|
180
|
-
|
180
|
+
if len(urls_to_angles) != len(urls):
|
181
|
+
urls_to_angles.clear()
|
181
182
|
|
182
|
-
for
|
183
|
-
if len(
|
184
|
-
text = f"angle={
|
183
|
+
for url in urls:
|
184
|
+
if len(urls_to_angles) > 0:
|
185
|
+
text = f"angle={urls_to_angles[url.path()]}&"
|
185
186
|
else:
|
186
187
|
text = ""
|
187
188
|
if url.data_slice() is not None:
|
@@ -30,6 +30,7 @@ import functools
|
|
30
30
|
import logging
|
31
31
|
import shutil
|
32
32
|
import tempfile
|
33
|
+
import os
|
33
34
|
|
34
35
|
from processview.core.manager import DatasetState, ProcessManager
|
35
36
|
from processview.core.superviseprocess import SuperviseProcess
|
@@ -132,6 +133,15 @@ class DarkRefCopyProcessStack(FIFO, qt.QObject):
|
|
132
133
|
def _create_processing_thread(self, process_id=None) -> qt.QThread:
|
133
134
|
return _ProcessingThread(process_id=process_id, save_dir=self._save_dir)
|
134
135
|
|
136
|
+
def clear_cache(self):
|
137
|
+
"""
|
138
|
+
remove the file used to cache the reduced darks / flats.
|
139
|
+
This can be used in the case it contain unrelevant data. Like frame with another shape...
|
140
|
+
"""
|
141
|
+
cache_file = DarkRefsCopy.get_save_file(self._save_dir)
|
142
|
+
if os.path.exists(cache_file):
|
143
|
+
os.remove(cache_file)
|
144
|
+
|
135
145
|
|
136
146
|
class _ProcessingThread(ProcessingThread, SuperviseProcess):
|
137
147
|
"""
|
tomwer/tests/datasets.py
CHANGED
tomwer/utils.py
CHANGED
@@ -81,10 +81,7 @@ class LauncherCommand(_LauncherCommand):
|
|
81
81
|
"""Description of a command"""
|
82
82
|
|
83
83
|
def get_module(self):
|
84
|
-
"""Returns the python module to execute. If any.
|
85
|
-
|
86
|
-
:rtype: module
|
87
|
-
"""
|
84
|
+
"""Returns the python module to execute. If any."""
|
88
85
|
try:
|
89
86
|
module = importlib.import_module(self.module_name)
|
90
87
|
return module
|