darfix 4.2.0__py3-none-any.whl → 4.3.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.
- darfix/core/data_selection.py +11 -2
- darfix/core/dataset.py +72 -157
- darfix/core/grainplot.py +44 -56
- darfix/core/{imageStack.py → image_stack.py} +9 -15
- darfix/core/moment_types.py +6 -0
- darfix/core/{noiseremoval.py → noise_removal.py} +25 -24
- darfix/core/noise_removal_type.py +14 -0
- darfix/core/positioners.py +6 -0
- darfix/core/rocking_curves.py +6 -3
- darfix/core/rocking_curves_map.py +1 -1
- darfix/core/{shiftcorrection.py → shift_correction.py} +1 -2
- darfix/core/state_of_operation.py +7 -46
- darfix/core/utils.py +0 -39
- darfix/dtypes.py +1 -9
- darfix/gui/{binningWidget.py → binning_widget.py} +2 -29
- darfix/gui/{blindSourceSeparationWidget.py → blind_source_separation_widget.py} +4 -16
- darfix/gui/{chooseDimensions.py → choose_dimensions.py} +1 -1
- darfix/gui/concatenate_scans.py +4 -4
- darfix/gui/data_selection/{hdf5_data_selection_widgets.py → hdf5_dataset_selection_widget.py} +3 -56
- darfix/gui/data_selection/line_edits.py +54 -8
- darfix/gui/data_selection/scan_selection_widgets.py +24 -11
- darfix/gui/data_selection/utils.py +11 -0
- darfix/gui/data_selection/{WorkingDirSelectionWidget.py → working_dir_selection_widget.py} +15 -14
- darfix/gui/{dimensionsWidget.py → dimensions_widget.py} +1 -1
- darfix/gui/{displayComponentsWidget.py → display_components_widget.py} +1 -1
- darfix/gui/{filterByDimension.py → filter_by_dimension.py} +1 -1
- darfix/gui/{grainplot/dimensionRangeSlider2D.py → grain_plot/dimension_range_slider_2d.py} +2 -2
- darfix/gui/{grainplot/grainPlotWidget.py → grain_plot/grain_plot_widget.py} +1 -1
- darfix/gui/{grainplot/mosaicityWidget.py → grain_plot/mosaicity_widget.py} +21 -23
- darfix/gui/{magnificationWidget.py → magnification_widget.py} +1 -1
- darfix/gui/{noiseremoval → noise_removal}/noise_removal_widget.py +12 -16
- darfix/gui/{noiseremoval → noise_removal}/operation_list_widget.py +2 -2
- darfix/gui/{noiseremoval → noise_removal}/parameters_widget.py +6 -6
- darfix/gui/{PCAWidget.py → pca_widget.py} +2 -4
- darfix/gui/{projectionWidget.py → projection_widget.py} +1 -1
- darfix/gui/rocking_curves/{rockingCurvesPlot.py → rocking_curves_plot.py} +13 -13
- darfix/gui/rocking_curves/{rockingCurvesWidget.py → rocking_curves_widget.py} +10 -18
- darfix/gui/{roiSelectionWidget.py → roi_selection_widget.py} +9 -101
- darfix/gui/{shiftcorrection/shiftCorrectionWidget.py → shift_correction/shift_correction_widget.py} +4 -7
- darfix/gui/utils/data_path_completer.py +7 -7
- darfix/gui/utils/data_path_selection.py +4 -4
- darfix/gui/utils/{rangeSlider.py → range_slider.py} +1 -1
- darfix/gui/{weakBeamWidget.py → weak_beam_widget.py} +13 -28
- darfix/gui/{zSumWidget.py → zsum_widget.py} +1 -2
- darfix/main.py +19 -3
- darfix/processing/rocking_curves.py +12 -13
- darfix/tasks/binning.py +6 -17
- darfix/tasks/blind_source_separation.py +121 -0
- darfix/tasks/blindsourceseparation.py +8 -131
- darfix/tasks/copy.py +0 -2
- darfix/tasks/data_partition.py +39 -0
- darfix/tasks/datapartition.py +8 -50
- darfix/tasks/dimension_definition.py +197 -0
- darfix/tasks/dimensiondefinition.py +8 -197
- darfix/tasks/grain_plot.py +93 -0
- darfix/tasks/grainplot.py +8 -103
- darfix/tasks/hdf5_data_selection.py +5 -11
- darfix/tasks/hdf5_scans_concatenation.py +4 -4
- darfix/tasks/noise_removal.py +88 -0
- darfix/tasks/noiseremoval.py +8 -86
- darfix/tasks/pca.py +1 -3
- darfix/tasks/projection.py +1 -6
- darfix/tasks/rocking_curves.py +10 -5
- darfix/tasks/roi.py +0 -2
- darfix/tasks/shift_correction.py +45 -0
- darfix/tasks/shiftcorrection.py +8 -43
- darfix/tasks/transformation.py +0 -2
- darfix/tasks/weak_beam.py +71 -0
- darfix/tasks/weakbeam.py +8 -67
- darfix/tasks/zsum.py +1 -1
- darfix/tests/conftest.py +1 -1
- darfix/tests/gui/test_data_path_completer.py +4 -4
- darfix/tests/gui/test_dimension_range_slider_2d.py +2 -2
- darfix/tests/gui/test_range_slider_with_spinboxes.py +1 -1
- darfix/tests/orange/test_ewoks.py +13 -9
- darfix/tests/orange/widgets/test_hdf5_data_selection.py +93 -0
- darfix/tests/tasks/test_data_copy.py +0 -2
- darfix/tests/tasks/{test_dimensiondefinition.py → test_dimension_definition.py} +1 -1
- darfix/tests/tasks/test_weak_beam.py +9 -0
- darfix/tests/test_components_matching.py +2 -2
- darfix/tests/test_dataset.py +2 -28
- darfix/tests/test_dimension.py +1 -1
- darfix/tests/test_generate_grain_maps_nxdict.py +4 -5
- darfix/tests/test_image_operations.py +4 -4
- darfix/tests/test_image_registration.py +17 -17
- darfix/tests/test_image_stack.py +2 -13
- darfix/tests/test_mask.py +1 -1
- darfix/tests/test_moments.py +2 -2
- darfix/tests/test_rocking_curves.py +1 -3
- darfix/tests/test_shift.py +7 -7
- darfix/tests/test_workflow.py +4 -4
- darfix/tests/test_zsum.py +3 -6
- {darfix-4.2.0.dist-info → darfix-4.3.0.dist-info}/METADATA +5 -3
- {darfix-4.2.0.dist-info → darfix-4.3.0.dist-info}/RECORD +141 -135
- orangecontrib/darfix/widgets/__init__.py +10 -1
- orangecontrib/darfix/widgets/binning.py +3 -3
- orangecontrib/darfix/widgets/blindsourceseparation.py +4 -6
- orangecontrib/darfix/widgets/concatenateHDF5.py +1 -1
- orangecontrib/darfix/widgets/datacopy.py +1 -1
- orangecontrib/darfix/widgets/datapartition.py +7 -102
- orangecontrib/darfix/widgets/{datasetWidgetBase.py → dataset_widget_base.py} +17 -5
- orangecontrib/darfix/widgets/dimensions.py +6 -6
- orangecontrib/darfix/widgets/grainplot.py +3 -3
- orangecontrib/darfix/widgets/hdf5dataselection.py +34 -14
- orangecontrib/darfix/widgets/metadata.py +2 -2
- orangecontrib/darfix/widgets/noiseremoval.py +4 -4
- orangecontrib/darfix/widgets/{operationWidgetBase.py → operation_widget_base.py} +2 -2
- orangecontrib/darfix/widgets/pca.py +2 -2
- orangecontrib/darfix/widgets/projection.py +2 -2
- orangecontrib/darfix/widgets/rockingcurves.py +5 -2
- orangecontrib/darfix/widgets/roiselection.py +24 -106
- orangecontrib/darfix/widgets/rsmhistogram.py +2 -2
- orangecontrib/darfix/widgets/shiftcorrection.py +3 -3
- orangecontrib/darfix/widgets/transformation.py +4 -4
- orangecontrib/darfix/widgets/weakbeam.py +20 -103
- orangecontrib/darfix/widgets/zsum.py +3 -5
- darfix/gui/dataPartitionWidget.py +0 -167
- darfix/gui/data_selection/DataSelectionBase.py +0 -59
- darfix/tests/tasks/test_datapartition.py +0 -52
- /darfix/core/{componentsMatching.py → components_matching.py} +0 -0
- /darfix/core/{datapathfinder.py → data_path_finder.py} +0 -0
- /darfix/core/{imageRegistration.py → image_registration.py} +0 -0
- /darfix/gui/{grainplot → grain_plot}/__init__.py +0 -0
- /darfix/gui/{grainplot → grain_plot}/_oridist_toolbar_buttons.py +0 -0
- /darfix/gui/{grainplot → grain_plot}/flashlight.py +0 -0
- /darfix/gui/{grainplot → grain_plot}/flashlight_mode_action.py +0 -0
- /darfix/gui/{grainplot → grain_plot}/oridist_toolbar.py +0 -0
- /darfix/gui/{grainplot → grain_plot}/utils.py +0 -0
- /darfix/gui/{metadataWidget.py → metadata_widget.py} +0 -0
- /darfix/gui/{operationProcess.py → parallel/operation_process.py} +0 -0
- /darfix/gui/{operationThread.py → parallel/operation_thread.py} +0 -0
- /darfix/gui/rocking_curves/{fitComboBox.py → fit_combobox.py} +0 -0
- /darfix/gui/{roiLimitsToolbar.py → roi_limits_toolbar.py} +0 -0
- /darfix/gui/{rsmHistogramWidget.py → rsm_histogram_widget.py} +0 -0
- /darfix/gui/{rsmWidget.py → rsm_widget.py} +0 -0
- /darfix/gui/{shiftcorrection → shift_correction}/__init__.py +0 -0
- /darfix/gui/{shiftcorrection/shiftInput.py → shift_correction/shift_input.py} +0 -0
- /darfix/gui/utils/{standardButtonBox.py → standard_buttonbox.py} +0 -0
- /darfix/processing/{imageOperations.py → image_operations.py} +0 -0
- /darfix/tests/{test_datapathfinder.py → test_data_path_finder.py} +0 -0
- {darfix-4.2.0.dist-info → darfix-4.3.0.dist-info}/WHEEL +0 -0
- {darfix-4.2.0.dist-info → darfix-4.3.0.dist-info}/entry_points.txt +0 -0
- {darfix-4.2.0.dist-info → darfix-4.3.0.dist-info}/licenses/LICENSE +0 -0
- {darfix-4.2.0.dist-info → darfix-4.3.0.dist-info}/top_level.txt +0 -0
|
@@ -6,12 +6,11 @@ from silx.gui.colors import Colormap
|
|
|
6
6
|
from silx.gui.plot.items import ImageBase
|
|
7
7
|
from silx.image.marchingsquares import find_contours
|
|
8
8
|
|
|
9
|
-
from darfix.gui.
|
|
9
|
+
from darfix.gui.grain_plot.dimension_range_slider_2d import DimensionRangeSlider2D
|
|
10
10
|
|
|
11
|
+
from ...core.grainplot import GrainPlotData
|
|
11
12
|
from ...core.grainplot import GrainPlotMaps
|
|
12
13
|
from ...core.grainplot import MultiDimMomentType
|
|
13
|
-
from ...core.grainplot import OrientationDistData
|
|
14
|
-
from ...core.grainplot import compute_mosaicity
|
|
15
14
|
from ...core.moment_types import MomentType
|
|
16
15
|
from .flashlight import PlotWithFlashlight
|
|
17
16
|
from .oridist_toolbar import OriDistButtonIds
|
|
@@ -27,8 +26,7 @@ class MosaicityWidget(qt.QWidget):
|
|
|
27
26
|
super().__init__(parent)
|
|
28
27
|
|
|
29
28
|
self._grainPlotMaps: GrainPlotMaps | None = None
|
|
30
|
-
self._orientation_dist_data:
|
|
31
|
-
self._mosaicity: numpy.ndarray | None = None
|
|
29
|
+
self._orientation_dist_data: GrainPlotData | None = None
|
|
32
30
|
self.contours = {}
|
|
33
31
|
|
|
34
32
|
layout = qt.QGridLayout()
|
|
@@ -86,7 +84,7 @@ class MosaicityWidget(qt.QWidget):
|
|
|
86
84
|
layout.addWidget(separator, 2, 0, 1, 2)
|
|
87
85
|
|
|
88
86
|
#
|
|
89
|
-
# zsum threshold
|
|
87
|
+
# zsum threshold and colormap selection
|
|
90
88
|
# Row 3
|
|
91
89
|
#
|
|
92
90
|
|
|
@@ -98,8 +96,15 @@ class MosaicityWidget(qt.QWidget):
|
|
|
98
96
|
""" Discard mosa values below this threshold """
|
|
99
97
|
self._thresholdSB.setButtonSymbols(qt.QAbstractSpinBox.ButtonSymbols.NoButtons)
|
|
100
98
|
self._thresholdSB.editingFinished.connect(self._computeMosaicityAndOriDist)
|
|
101
|
-
|
|
99
|
+
self._colormapCB = qt.QComboBox()
|
|
100
|
+
""" Combo box to select one of the colormap of `colorstamps` package. """
|
|
101
|
+
self._colormapCB.addItems(["hsv", "cut", "orangeBlue", "flat"])
|
|
102
|
+
self._colormapCB.currentTextChanged.connect(self._computeMosaicityAndOriDist)
|
|
103
|
+
thresholdLayout.addWidget(qt.QLabel("ZSum Threshold"))
|
|
102
104
|
thresholdLayout.addWidget(self._thresholdSB)
|
|
105
|
+
thresholdLayout.addSpacing(20)
|
|
106
|
+
thresholdLayout.addWidget(qt.QLabel("Colormap"))
|
|
107
|
+
thresholdLayout.addWidget(self._colormapCB)
|
|
103
108
|
thresholdLayout.addStretch(1)
|
|
104
109
|
layout.addLayout(thresholdLayout, 3, 0)
|
|
105
110
|
|
|
@@ -123,7 +128,7 @@ class MosaicityWidget(qt.QWidget):
|
|
|
123
128
|
return self._sliders.indexDimY()
|
|
124
129
|
|
|
125
130
|
def getMosaicity(self):
|
|
126
|
-
return self.
|
|
131
|
+
return self._orientation_dist_data.mosaicity
|
|
127
132
|
|
|
128
133
|
def getContoursImage(self):
|
|
129
134
|
return self._oriDistPlot.getImage()
|
|
@@ -147,13 +152,14 @@ class MosaicityWidget(qt.QWidget):
|
|
|
147
152
|
self._computeMosaicityAndOriDist()
|
|
148
153
|
|
|
149
154
|
def _plotMosaicity(self):
|
|
150
|
-
if self._grainPlotMaps is None:
|
|
155
|
+
if self._grainPlotMaps is None or self._orientation_dist_data is None:
|
|
151
156
|
return
|
|
152
157
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
158
|
+
add_image_with_transformation(
|
|
159
|
+
self._mosaicityPlot,
|
|
160
|
+
self._orientation_dist_data.mosaicity,
|
|
161
|
+
self._grainPlotMaps.transformation,
|
|
162
|
+
)
|
|
157
163
|
|
|
158
164
|
def _plotOrientationData(self, state=None):
|
|
159
165
|
if self._grainPlotMaps is None or self._orientation_dist_data is None:
|
|
@@ -360,22 +366,14 @@ class MosaicityWidget(qt.QWidget):
|
|
|
360
366
|
zsum = self._grainPlotMaps.zsum.copy()
|
|
361
367
|
zsum[maskZsum] = 0
|
|
362
368
|
|
|
363
|
-
self.
|
|
364
|
-
self._grainPlotMaps.moments_dims,
|
|
365
|
-
x_dimension=self.dimension1,
|
|
366
|
-
y_dimension=self.dimension2,
|
|
367
|
-
x_dimension_range=self._sliders.rangeDimX(),
|
|
368
|
-
y_dimension_range=self._sliders.rangeDimY(),
|
|
369
|
-
)
|
|
370
|
-
self._mosaicity[maskZsum] = 0, 0, 0 # Black
|
|
371
|
-
|
|
372
|
-
self._orientation_dist_data = OrientationDistData(
|
|
369
|
+
self._orientation_dist_data = GrainPlotData(
|
|
373
370
|
self._grainPlotMaps,
|
|
374
371
|
x_dimension=self.dimension1,
|
|
375
372
|
y_dimension=self.dimension2,
|
|
376
373
|
x_dimension_range=self._sliders.rangeDimX(),
|
|
377
374
|
y_dimension_range=self._sliders.rangeDimY(),
|
|
378
375
|
zsum=zsum,
|
|
376
|
+
colormap_name=self._colormapCB.currentText(),
|
|
379
377
|
)
|
|
380
378
|
self._plotMosaicity()
|
|
381
379
|
self._plotOrientationData()
|
|
@@ -11,13 +11,13 @@ from silx.gui.widgets.FrameBrowser import HorizontalSliderWithBrowser
|
|
|
11
11
|
|
|
12
12
|
from darfix import config
|
|
13
13
|
from darfix import dtypes
|
|
14
|
-
from darfix.core.
|
|
15
|
-
from darfix.core.
|
|
16
|
-
from darfix.core.
|
|
17
|
-
from darfix.core.
|
|
18
|
-
from darfix.core.
|
|
19
|
-
from darfix.core.
|
|
20
|
-
from darfix.gui.
|
|
14
|
+
from darfix.core.noise_removal import BackgroundType
|
|
15
|
+
from darfix.core.noise_removal import NoiseRemovalOperation
|
|
16
|
+
from darfix.core.noise_removal import add_background_data_into_operation
|
|
17
|
+
from darfix.core.noise_removal import apply_noise_removal_operation
|
|
18
|
+
from darfix.core.noise_removal import operation_to_str
|
|
19
|
+
from darfix.core.noise_removal_type import NoiseRemovalType
|
|
20
|
+
from darfix.gui.parallel.operation_thread import OperationThread
|
|
21
21
|
|
|
22
22
|
from .operation_list_widget import OperationListWidget
|
|
23
23
|
from .parameters_widget import ParametersWidget
|
|
@@ -158,10 +158,6 @@ class NoiseRemovalWidget(qt.QWidget):
|
|
|
158
158
|
self._parametersWidget.bsBackgroundCB.addItem(
|
|
159
159
|
BackgroundType.DARK_DATA.value
|
|
160
160
|
)
|
|
161
|
-
if dataset.bg_indices is not None:
|
|
162
|
-
self._parametersWidget.bsBackgroundCB.addItem(
|
|
163
|
-
BackgroundType.UNUSED_DATA.value
|
|
164
|
-
)
|
|
165
161
|
self._parametersWidget.bsBackgroundCB.addItem(BackgroundType.DATA.value)
|
|
166
162
|
|
|
167
163
|
opersations = self._operationList.getOperations()
|
|
@@ -177,14 +173,14 @@ class NoiseRemovalWidget(qt.QWidget):
|
|
|
177
173
|
== qt.QMessageBox.StandardButton.Yes
|
|
178
174
|
):
|
|
179
175
|
for operation in opersations:
|
|
180
|
-
if operation["type"] is
|
|
176
|
+
if operation["type"] is NoiseRemovalType.BS:
|
|
181
177
|
self._computeBackgroundAsync(operation)
|
|
182
178
|
else:
|
|
183
179
|
self._operationList.clear()
|
|
184
180
|
|
|
185
181
|
def _launchBackgroundSubtraction(self):
|
|
186
182
|
operation = NoiseRemovalOperation(
|
|
187
|
-
type=
|
|
183
|
+
type=NoiseRemovalType.BS,
|
|
188
184
|
parameters={
|
|
189
185
|
"method": self._parametersWidget.bsMethodsCB.currentText(),
|
|
190
186
|
"background_type": self._parametersWidget.bsBackgroundCB.currentText(),
|
|
@@ -226,7 +222,7 @@ class NoiseRemovalWidget(qt.QWidget):
|
|
|
226
222
|
size = self._parametersWidget.hpSizeCB.currentText()
|
|
227
223
|
|
|
228
224
|
operation = NoiseRemovalOperation(
|
|
229
|
-
type=
|
|
225
|
+
type=NoiseRemovalType.HP,
|
|
230
226
|
parameters={
|
|
231
227
|
"kernel_size": int(size),
|
|
232
228
|
},
|
|
@@ -247,7 +243,7 @@ class NoiseRemovalWidget(qt.QWidget):
|
|
|
247
243
|
top_threshold = None
|
|
248
244
|
|
|
249
245
|
operation = NoiseRemovalOperation(
|
|
250
|
-
type=
|
|
246
|
+
type=NoiseRemovalType.THRESHOLD,
|
|
251
247
|
parameters={
|
|
252
248
|
"bottom": bottom_threshold,
|
|
253
249
|
"top": top_threshold,
|
|
@@ -261,7 +257,7 @@ class NoiseRemovalWidget(qt.QWidget):
|
|
|
261
257
|
if mask is None:
|
|
262
258
|
return
|
|
263
259
|
operation = NoiseRemovalOperation(
|
|
264
|
-
type=
|
|
260
|
+
type=NoiseRemovalType.MASK,
|
|
265
261
|
parameters={"mask": mask},
|
|
266
262
|
)
|
|
267
263
|
self._operationList.append(operation)
|
|
@@ -2,8 +2,8 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from silx.gui import qt
|
|
4
4
|
|
|
5
|
-
from ...core.
|
|
6
|
-
from ...core.
|
|
5
|
+
from ...core.noise_removal import NoiseRemovalOperation
|
|
6
|
+
from ...core.noise_removal import operation_to_str
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class OperationListWidget(qt.QWidget):
|
|
@@ -5,9 +5,9 @@ from typing import Optional
|
|
|
5
5
|
from silx.gui import qt
|
|
6
6
|
from silx.gui.widgets.WaitingPushButton import WaitingPushButton
|
|
7
7
|
|
|
8
|
-
from darfix.core.
|
|
9
|
-
from darfix.core.
|
|
10
|
-
from darfix.processing.
|
|
8
|
+
from darfix.core.noise_removal import NoiseRemovalOperation
|
|
9
|
+
from darfix.core.noise_removal import NoiseRemovalType
|
|
10
|
+
from darfix.processing.image_operations import Method
|
|
11
11
|
|
|
12
12
|
_logger = logging.getLogger(__file__)
|
|
13
13
|
|
|
@@ -98,19 +98,19 @@ class ParametersWidget(qt.QWidget):
|
|
|
98
98
|
# follow history to obtain last values set by the user
|
|
99
99
|
for operation in history:
|
|
100
100
|
try:
|
|
101
|
-
if operation["type"] is
|
|
101
|
+
if operation["type"] is NoiseRemovalType.BS:
|
|
102
102
|
index = self.bsMethodsCB.findText(
|
|
103
103
|
str(operation["parameters"]["method"])
|
|
104
104
|
)
|
|
105
105
|
if index > 0:
|
|
106
106
|
self.bsMethodsCB.setCurrentIndex(index)
|
|
107
|
-
elif operation["type"] is
|
|
107
|
+
elif operation["type"] is NoiseRemovalType.HP:
|
|
108
108
|
index = self.hpSizeCB.findText(
|
|
109
109
|
str(operation["parameters"]["kernel_size"])
|
|
110
110
|
)
|
|
111
111
|
if index > 0:
|
|
112
112
|
self.hpSizeCB.setCurrentIndex(index)
|
|
113
|
-
elif operation["type"] is
|
|
113
|
+
elif operation["type"] is NoiseRemovalType.THRESHOLD:
|
|
114
114
|
if operation["parameters"]["bottom"] is not None:
|
|
115
115
|
self.bottomLE.setText(str(operation["parameters"]["bottom"]))
|
|
116
116
|
if operation["parameters"]["top"] is not None:
|
|
@@ -6,7 +6,7 @@ from silx.gui.plot import Plot1D
|
|
|
6
6
|
|
|
7
7
|
from darfix import dtypes
|
|
8
8
|
|
|
9
|
-
from .
|
|
9
|
+
from .parallel.operation_thread import OperationThread
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class PCAPlot(Plot1D):
|
|
@@ -43,7 +43,7 @@ class PCAWidget(qt.QMainWindow):
|
|
|
43
43
|
def _computePCA(self):
|
|
44
44
|
try:
|
|
45
45
|
self._thread = OperationThread(self, self._dataset.pca)
|
|
46
|
-
self._thread.setArgs(return_vals=True
|
|
46
|
+
self._thread.setArgs(return_vals=True)
|
|
47
47
|
self._thread.finished.connect(self._updateData)
|
|
48
48
|
self._thread.start()
|
|
49
49
|
except Exception as e:
|
|
@@ -51,8 +51,6 @@ class PCAWidget(qt.QMainWindow):
|
|
|
51
51
|
|
|
52
52
|
def setDataset(self, dataset: dtypes.Dataset):
|
|
53
53
|
self._dataset = dataset.dataset
|
|
54
|
-
self.indices = dataset.indices
|
|
55
|
-
self.bg_indices = dataset.bg_indices
|
|
56
54
|
self.bg_dataset = dataset.bg_dataset
|
|
57
55
|
self._computePCA()
|
|
58
56
|
|
|
@@ -4,7 +4,7 @@ from silx.gui.plot.StackView import StackViewMainWindow
|
|
|
4
4
|
|
|
5
5
|
from .. import config
|
|
6
6
|
from ..dtypes import ImageDataset
|
|
7
|
-
from .
|
|
7
|
+
from .choose_dimensions import ChooseDimensionWidget
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class ProjectionWidget(qt.QWidget):
|
|
@@ -10,6 +10,8 @@ from silx.gui.plot import StackView
|
|
|
10
10
|
from silx.gui.plot.items.image import ImageStack
|
|
11
11
|
|
|
12
12
|
import darfix
|
|
13
|
+
from darfix.math import bivariate_gaussian
|
|
14
|
+
from darfix.math import gaussian
|
|
13
15
|
|
|
14
16
|
from ...core.dataset import ImageDataset
|
|
15
17
|
from ...core.dimension import Dimension
|
|
@@ -65,11 +67,9 @@ class RockingCurvesPlot(qt.QWidget):
|
|
|
65
67
|
layout.addWidget(self._fitPlotGroup)
|
|
66
68
|
|
|
67
69
|
self._dataset: ImageDataset | None = None
|
|
68
|
-
self._indices = None
|
|
69
70
|
|
|
70
71
|
def setDataset(self, dataset: Dataset):
|
|
71
72
|
self._dataset = dataset.dataset
|
|
72
|
-
self._indices = dataset.indices
|
|
73
73
|
|
|
74
74
|
if self._dataset.dims.ndim == 3:
|
|
75
75
|
# fitplot would be a 3D plot ? Not implemented for now.
|
|
@@ -87,7 +87,7 @@ class RockingCurvesPlot(qt.QWidget):
|
|
|
87
87
|
if self._dataset is None:
|
|
88
88
|
stack = None
|
|
89
89
|
else:
|
|
90
|
-
stack = self._dataset.as_array3d(
|
|
90
|
+
stack = self._dataset.as_array3d()
|
|
91
91
|
|
|
92
92
|
self._sv.setStack(stack)
|
|
93
93
|
self._sv.setFrameNumber(nframe)
|
|
@@ -206,7 +206,7 @@ class RockingCurvesPlot(qt.QWidget):
|
|
|
206
206
|
return
|
|
207
207
|
|
|
208
208
|
try:
|
|
209
|
-
data = self._dataset.as_array3d(
|
|
209
|
+
data = self._dataset.as_array3d()
|
|
210
210
|
if isinstance(data, numpy.ndarray):
|
|
211
211
|
rocking_curve = data[:, int(py), int(px)]
|
|
212
212
|
else:
|
|
@@ -224,8 +224,6 @@ class RockingCurvesPlot(qt.QWidget):
|
|
|
224
224
|
raise TooManyDimensionsForRockingCurvesError()
|
|
225
225
|
|
|
226
226
|
def _plot2DRockingCurve(self, dataset: ImageDataset, rocking_curve: numpy.ndarray):
|
|
227
|
-
y_values = numpy.zeros(dataset.nframes)
|
|
228
|
-
y_values[self._indices] = rocking_curve
|
|
229
227
|
dim1 = dataset.dims.get(1)
|
|
230
228
|
dim0 = dataset.dims.get(0)
|
|
231
229
|
assert dim1 is not None
|
|
@@ -242,7 +240,9 @@ class RockingCurvesPlot(qt.QWidget):
|
|
|
242
240
|
)
|
|
243
241
|
|
|
244
242
|
try:
|
|
245
|
-
|
|
243
|
+
_, pars = fit_2d_rocking_curve(rocking_curve, x_values)
|
|
244
|
+
# Recompute fitted y without any masking (Better vizualisation of the gaussian contours)
|
|
245
|
+
y_gauss = bivariate_gaussian(x_values, *pars)
|
|
246
246
|
|
|
247
247
|
except (TypeError, RuntimeError):
|
|
248
248
|
_logger.warning("Cannot fit", exc_info=True)
|
|
@@ -272,7 +272,7 @@ class RockingCurvesPlot(qt.QWidget):
|
|
|
272
272
|
def _plot1DRockingCurve(self, dataset: ImageDataset, rocking_curve: numpy.ndarray):
|
|
273
273
|
dim = dataset.dims.get(0)
|
|
274
274
|
assert dim is not None
|
|
275
|
-
motor_values = dataset.get_metadata_values(key=dim.name
|
|
275
|
+
motor_values = dataset.get_metadata_values(key=dim.name)
|
|
276
276
|
if self._axisTypeComboBox.getCurrentAxisType() == "dims":
|
|
277
277
|
self._fitPlot.setGraphXLabel(dim.name)
|
|
278
278
|
x = motor_values
|
|
@@ -288,7 +288,9 @@ class RockingCurvesPlot(qt.QWidget):
|
|
|
288
288
|
self._fitPlot.setGraphYLabel("Intensity")
|
|
289
289
|
i = self._sv.getFrameNumber()
|
|
290
290
|
try:
|
|
291
|
-
|
|
291
|
+
_, pars = fit_1d_rocking_curve(rocking_curve, x)
|
|
292
|
+
# Recompute fitted y without any masking (Better vizualisation of the gaussian contours)
|
|
293
|
+
y_gauss = gaussian(x, *pars)
|
|
292
294
|
self._lastFitParamsLabel.setText(
|
|
293
295
|
"AMP:{:.3f} PEAK:{:.3f} FWHM:{:.3f} BG:{:.3f}".format(*pars)
|
|
294
296
|
)
|
|
@@ -296,9 +298,7 @@ class RockingCurvesPlot(qt.QWidget):
|
|
|
296
298
|
_logger.warning("Cannot fit", exc_info=True)
|
|
297
299
|
y_gauss = numpy.full_like(rocking_curve, numpy.nan)
|
|
298
300
|
else:
|
|
299
|
-
|
|
300
|
-
self.
|
|
301
|
-
i_gauss = i * int((len(y_gauss) - 1) / (len(x) - 1))
|
|
302
|
-
self._addFitMarker(x_gauss[i_gauss], y_gauss[i_gauss])
|
|
301
|
+
self._fitPlot.addCurve(x, y_gauss, legend="fit", color="r")
|
|
302
|
+
self._addFitMarker(x[i], y_gauss[i])
|
|
303
303
|
|
|
304
304
|
self._addDataMarker(x[i], rocking_curve[i])
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import numpy
|
|
4
|
-
from ewoksorange.gui.
|
|
4
|
+
from ewoksorange.gui.widgets.parameter_form import block_signals
|
|
5
5
|
from silx.gui import qt
|
|
6
6
|
from silx.gui.colors import Colormap
|
|
7
7
|
from silx.gui.plot import Plot2D
|
|
8
8
|
from silx.io.dictdump import dicttonx
|
|
9
9
|
|
|
10
10
|
from ... import dtypes
|
|
11
|
-
from ...core.
|
|
11
|
+
from ...core.rocking_curves import compute_residuals
|
|
12
12
|
from ...core.rocking_curves import generate_rocking_curves_nxdict
|
|
13
13
|
from ...core.rocking_curves_map import MAPS_1D
|
|
14
14
|
from ...core.rocking_curves_map import MAPS_2D
|
|
@@ -17,8 +17,8 @@ from ...core.utils import NoDimensionsError
|
|
|
17
17
|
from ...core.utils import TooManyDimensionsForRockingCurvesError
|
|
18
18
|
from ..utils.message import missing_dataset_msg
|
|
19
19
|
from ..utils.utils import select_output_hdf5_file_with_dialog
|
|
20
|
-
from .
|
|
21
|
-
from .
|
|
20
|
+
from .fit_combobox import FitComboBox
|
|
21
|
+
from .rocking_curves_plot import RockingCurvesPlot
|
|
22
22
|
|
|
23
23
|
# "Residuals" are not given by the fit but computed by the widget.
|
|
24
24
|
# It needs to be handled separately of other `MAPS` values
|
|
@@ -43,12 +43,12 @@ class RockingCurvesWidget(qt.QWidget):
|
|
|
43
43
|
"""
|
|
44
44
|
|
|
45
45
|
sigFitClicked = qt.Signal()
|
|
46
|
+
sigAbortClicked = qt.Signal()
|
|
46
47
|
|
|
47
48
|
def __init__(self, parent=None):
|
|
48
49
|
qt.QWidget.__init__(self, parent)
|
|
49
50
|
|
|
50
51
|
self.dataset = None
|
|
51
|
-
self.indices = None
|
|
52
52
|
self._update_dataset = None
|
|
53
53
|
self._residuals_cache = None
|
|
54
54
|
self.maps = None
|
|
@@ -77,7 +77,8 @@ class RockingCurvesWidget(qt.QWidget):
|
|
|
77
77
|
self._abortFitBtn = qt.QPushButton("Abort")
|
|
78
78
|
self._abortFitBtn.hide()
|
|
79
79
|
self._abortFitBtn.clicked.connect(self.__abort)
|
|
80
|
-
|
|
80
|
+
self._abortFitBtn.clicked.connect(self.sigAbortClicked)
|
|
81
|
+
fitLayout.addWidget(self._abortFitBtn)
|
|
81
82
|
|
|
82
83
|
self._mapsCB = qt.QComboBox(self)
|
|
83
84
|
self._mapsCB.hide()
|
|
@@ -102,7 +103,6 @@ class RockingCurvesWidget(qt.QWidget):
|
|
|
102
103
|
if not dataset.dataset.dims.ndim:
|
|
103
104
|
raise NoDimensionsError("RockingCurvesWidget")
|
|
104
105
|
self.dataset = dataset.dataset
|
|
105
|
-
self.indices = dataset.indices
|
|
106
106
|
self._update_dataset = dataset.dataset
|
|
107
107
|
self._residuals_cache = None
|
|
108
108
|
|
|
@@ -133,8 +133,7 @@ class RockingCurvesWidget(qt.QWidget):
|
|
|
133
133
|
|
|
134
134
|
self._launchFitBtn.hide()
|
|
135
135
|
self.sigFitClicked.emit()
|
|
136
|
-
|
|
137
|
-
# self._abortFit.show()
|
|
136
|
+
self._abortFitBtn.show()
|
|
138
137
|
|
|
139
138
|
def _computeResiduals(self) -> numpy.ndarray | None:
|
|
140
139
|
"""Note: The computation is cached as long as the dataset is loaded."""
|
|
@@ -145,12 +144,7 @@ class RockingCurvesWidget(qt.QWidget):
|
|
|
145
144
|
if self._residuals_cache is not None:
|
|
146
145
|
return self._residuals_cache
|
|
147
146
|
|
|
148
|
-
self._residuals_cache =
|
|
149
|
-
numpy.subtract(
|
|
150
|
-
self._update_dataset.zsum(self.indices), self.dataset.zsum(self.indices)
|
|
151
|
-
)
|
|
152
|
-
** 2
|
|
153
|
-
)
|
|
147
|
+
self._residuals_cache = compute_residuals(self._update_dataset, self.dataset)
|
|
154
148
|
return self._residuals_cache
|
|
155
149
|
|
|
156
150
|
def _displayMap(self, map_name: str):
|
|
@@ -178,9 +172,7 @@ class RockingCurvesWidget(qt.QWidget):
|
|
|
178
172
|
self._addImage(self.maps[self._mapsCB.currentIndex()])
|
|
179
173
|
|
|
180
174
|
def __abort(self):
|
|
181
|
-
self._abortFitBtn.
|
|
182
|
-
if self.dataset is not None:
|
|
183
|
-
self.dataset.stop_operation(Operation.FIT)
|
|
175
|
+
self._abortFitBtn.hide()
|
|
184
176
|
|
|
185
177
|
def onFitFinished(self):
|
|
186
178
|
self._abortFitBtn.hide()
|
|
@@ -4,8 +4,6 @@ __date__ = "26/04/2021"
|
|
|
4
4
|
|
|
5
5
|
import logging
|
|
6
6
|
|
|
7
|
-
import silx
|
|
8
|
-
from packaging.version import Version
|
|
9
7
|
from silx.gui import qt
|
|
10
8
|
from silx.gui.colors import Colormap
|
|
11
9
|
from silx.gui.plot.items.roi import RectangleROI
|
|
@@ -16,7 +14,7 @@ import darfix
|
|
|
16
14
|
from darfix import dtypes
|
|
17
15
|
from darfix.core.roi import clampROI
|
|
18
16
|
|
|
19
|
-
from .
|
|
17
|
+
from .roi_limits_toolbar import RoiLimitsToolBar
|
|
20
18
|
|
|
21
19
|
_logger = logging.getLogger(__file__)
|
|
22
20
|
|
|
@@ -26,29 +24,11 @@ class ROISelectionWidget(qt.QWidget):
|
|
|
26
24
|
Widget that allows the user to pick a ROI in any image of the dataset.
|
|
27
25
|
"""
|
|
28
26
|
|
|
29
|
-
sigValidate = qt.Signal()
|
|
30
|
-
"""Emit when user wants to keep the current resized dataset and move to next widget"""
|
|
31
|
-
|
|
32
|
-
sigApply = qt.Signal()
|
|
33
|
-
"""Emit when user wants to Apply a ROI. Then we wait for a refinement or a validation"""
|
|
34
|
-
|
|
35
|
-
sigReset = qt.Signal()
|
|
36
|
-
"""Emit when user wants to come back to the initial dataset"""
|
|
37
|
-
|
|
38
|
-
sigROIChanged = qt.Signal()
|
|
39
|
-
"""Emit when the roi is changed"""
|
|
40
|
-
|
|
41
27
|
def __init__(self, parent=None):
|
|
42
28
|
super().__init__(parent)
|
|
43
29
|
|
|
44
30
|
self.setLayout(qt.QVBoxLayout())
|
|
45
31
|
self._sv = StackViewMainWindow()
|
|
46
|
-
_buttons = qt.QDialogButtonBox(parent=self)
|
|
47
|
-
|
|
48
|
-
self._okB = _buttons.addButton(_buttons.Ok)
|
|
49
|
-
self._applyB = _buttons.addButton(_buttons.Apply)
|
|
50
|
-
self._resetB = _buttons.addButton(_buttons.Reset)
|
|
51
|
-
self._okB.setDefault(False)
|
|
52
32
|
|
|
53
33
|
self._sv.setColormap(
|
|
54
34
|
Colormap(
|
|
@@ -58,20 +38,13 @@ class ROISelectionWidget(qt.QWidget):
|
|
|
58
38
|
)
|
|
59
39
|
self._sv.setKeepDataAspectRatio(True)
|
|
60
40
|
self.layout().addWidget(self._sv)
|
|
61
|
-
self.layout().addWidget(_buttons)
|
|
62
41
|
|
|
63
|
-
|
|
64
|
-
plot = self._sv.getPlot()
|
|
65
|
-
else:
|
|
66
|
-
plot = self._sv.getPlotWidget()
|
|
42
|
+
plot = self._sv.getPlotWidget()
|
|
67
43
|
|
|
68
44
|
self._roiManager = RegionOfInterestManager(plot)
|
|
69
45
|
|
|
70
46
|
self._roi = RectangleROI()
|
|
71
|
-
|
|
72
|
-
self._roi.setLabel("ROI")
|
|
73
|
-
else:
|
|
74
|
-
self._roi.setText("ROI")
|
|
47
|
+
self._roi.setText("ROI")
|
|
75
48
|
self._roi.setGeometry(origin=(0, 0), size=(10, 10))
|
|
76
49
|
self._roi.setEditable(True)
|
|
77
50
|
self._roiManager.addRoi(self._roi)
|
|
@@ -79,20 +52,15 @@ class ROISelectionWidget(qt.QWidget):
|
|
|
79
52
|
self._roiToolBar = RoiLimitsToolBar(roiManager=self._roiManager)
|
|
80
53
|
self._sv.addToolBar(qt.Qt.BottomToolBarArea, self._roiToolBar)
|
|
81
54
|
|
|
82
|
-
|
|
83
|
-
self._applyB.clicked.connect(self.applyRoi)
|
|
84
|
-
self._okB.clicked.connect(self.sigValidate)
|
|
85
|
-
self._resetB.clicked.connect(self.sigReset)
|
|
86
|
-
# self._roiManager.sigRoiChanged.connect(self.sigROIChanged)
|
|
87
|
-
self._roi.sigRegionChanged.connect(self.sigROIChanged)
|
|
88
|
-
|
|
89
|
-
def setDataset(self, dataset: dtypes.Dataset):
|
|
55
|
+
def setDataset(self, dataset: dtypes.Dataset, roiEnabled: bool = True):
|
|
90
56
|
"""Saves the dataset and updates the stack with the dataset data."""
|
|
91
57
|
if dataset.dataset.title != "":
|
|
92
58
|
self._sv.setGraphTitle(dataset.dataset.title)
|
|
93
|
-
self.
|
|
59
|
+
self._roi.setVisible(roiEnabled)
|
|
60
|
+
self._roiToolBar.setEnabled(roiEnabled)
|
|
61
|
+
self._setStack(dataset=dataset.dataset)
|
|
94
62
|
|
|
95
|
-
def
|
|
63
|
+
def setROIForNewDataset(self, dataset: dtypes.ImageDataset):
|
|
96
64
|
if not isinstance(dataset, dtypes.ImageDataset):
|
|
97
65
|
raise dtypes.DatasetTypeError(dataset)
|
|
98
66
|
first_frame_shape = dataset.frame_shape
|
|
@@ -100,7 +68,7 @@ class ROISelectionWidget(qt.QWidget):
|
|
|
100
68
|
size = first_frame_shape[1] // 5, first_frame_shape[0] // 5
|
|
101
69
|
self.setRoi(center=center, size=size)
|
|
102
70
|
|
|
103
|
-
def
|
|
71
|
+
def _setStack(self, dataset: dtypes.ImageDataset):
|
|
104
72
|
"""
|
|
105
73
|
Sets new data to the stack.
|
|
106
74
|
Maintains the current frame showed in the view.
|
|
@@ -145,63 +113,6 @@ class ROISelectionWidget(qt.QWidget):
|
|
|
145
113
|
"""
|
|
146
114
|
return self._roi
|
|
147
115
|
|
|
148
|
-
def applyRoi(self):
|
|
149
|
-
"""
|
|
150
|
-
Function to apply the region of interest at the data of the dataset
|
|
151
|
-
and show the new data in the stack. Dataset data is not yet replaced.
|
|
152
|
-
A new roi is created in the middle of the new stack.
|
|
153
|
-
"""
|
|
154
|
-
if self._sv.getPlotWidget().getActiveImage() is None:
|
|
155
|
-
return
|
|
156
|
-
|
|
157
|
-
self.enableApplyingROI(False)
|
|
158
|
-
self.sigApply.emit()
|
|
159
|
-
|
|
160
|
-
def enableApplyingROI(self, enable: bool) -> None:
|
|
161
|
-
self._applyB.setEnabled(enable)
|
|
162
|
-
|
|
163
|
-
def _fitROIToDataset(self, dataset: dtypes.ImageDataset):
|
|
164
|
-
"""
|
|
165
|
-
This function is called when the ROI is applied to the dataset.
|
|
166
|
-
The ROI must be updated to match the contour of the new shape.
|
|
167
|
-
"""
|
|
168
|
-
dataset_shape = dataset.frame_shape
|
|
169
|
-
self._roi.setGeometry(
|
|
170
|
-
size=dataset_shape[::-1],
|
|
171
|
-
center=(dataset_shape[1] / 2.0, dataset_shape[0] / 2.0),
|
|
172
|
-
)
|
|
173
|
-
|
|
174
|
-
def setVisible(self, visible):
|
|
175
|
-
super().setVisible(visible) # sets okB as default
|
|
176
|
-
self._okB.setDefault(False)
|
|
177
|
-
|
|
178
|
-
def getDataset(self) -> dtypes.Dataset:
|
|
179
|
-
return self._update_dataset
|
|
180
|
-
|
|
181
|
-
def getStackViewColormap(self):
|
|
182
|
-
"""
|
|
183
|
-
Returns the colormap from the stackView
|
|
184
|
-
|
|
185
|
-
:rtype: silx.gui.colors.Colormap
|
|
186
|
-
"""
|
|
187
|
-
return self._sv.getColormap()
|
|
188
|
-
|
|
189
|
-
def setStackViewColormap(self, colormap):
|
|
190
|
-
"""
|
|
191
|
-
Sets the stackView colormap
|
|
192
|
-
|
|
193
|
-
:param colormap: Colormap to set
|
|
194
|
-
:type colormap: silx.gui.colors.Colormap
|
|
195
|
-
"""
|
|
196
|
-
self._sv.setColormap(colormap)
|
|
197
|
-
|
|
198
|
-
def clearStack(self):
|
|
199
|
-
"""
|
|
200
|
-
Clears stack.
|
|
201
|
-
"""
|
|
202
|
-
self._sv.setStack(None)
|
|
203
|
-
self._roi.setGeometry(origin=(0, 0), size=(10, 10))
|
|
204
|
-
|
|
205
116
|
def clampRoiToDataset(self, dataset: dtypes.ImageDataset):
|
|
206
117
|
frame_height, frame_width = dataset.frame_shape
|
|
207
118
|
# warning: we need to invert the order of the frame shape (frame_height, frame_width) vs (frame_width, frame_height)
|
|
@@ -215,6 +126,3 @@ class ROISelectionWidget(qt.QWidget):
|
|
|
215
126
|
origin=new_origin,
|
|
216
127
|
size=new_size,
|
|
217
128
|
)
|
|
218
|
-
|
|
219
|
-
def enableValidation(self, isAllowed: bool) -> None:
|
|
220
|
-
self._okB.setEnabled(isAllowed)
|
darfix/gui/{shiftcorrection/shiftCorrectionWidget.py → shift_correction/shift_correction_widget.py}
RENAMED
|
@@ -13,10 +13,10 @@ import darfix
|
|
|
13
13
|
|
|
14
14
|
from ... import dtypes
|
|
15
15
|
from ...core.dataset import ImageDataset
|
|
16
|
-
from ..
|
|
17
|
-
from ..
|
|
16
|
+
from ..filter_by_dimension import FilterByDimensionWidget
|
|
17
|
+
from ..parallel.operation_process import OperationProcess
|
|
18
18
|
from ..utils.message import missing_dataset_msg
|
|
19
|
-
from .
|
|
19
|
+
from .shift_input import ShiftInput
|
|
20
20
|
|
|
21
21
|
_logger = logging.getLogger(__file__)
|
|
22
22
|
|
|
@@ -30,8 +30,6 @@ class ShiftCorrectionWidget(qt.QMainWindow):
|
|
|
30
30
|
super().__init__(parent=parent)
|
|
31
31
|
self.setWindowFlags(qt.Qt.WindowType.Widget)
|
|
32
32
|
self._input_dataset: ImageDataset | None = None
|
|
33
|
-
self.indices = None
|
|
34
|
-
self.bg_indices = None
|
|
35
33
|
self.bg_dataset = None
|
|
36
34
|
self._axis = None
|
|
37
35
|
|
|
@@ -100,7 +98,6 @@ class ShiftCorrectionWidget(qt.QMainWindow):
|
|
|
100
98
|
self,
|
|
101
99
|
dataset.find_shift,
|
|
102
100
|
self._axis,
|
|
103
|
-
indices=self.indices,
|
|
104
101
|
)
|
|
105
102
|
self.thread_detection.finished.connect(self._updateShift)
|
|
106
103
|
self.thread_detection.start()
|
|
@@ -160,6 +157,6 @@ class ShiftCorrectionWidget(qt.QMainWindow):
|
|
|
160
157
|
def refreshPlot(self) -> None:
|
|
161
158
|
# TODO is there another way to refresh plot ?
|
|
162
159
|
if self._axis is None:
|
|
163
|
-
self._sv.setStack(self._input_dataset.as_array3d(
|
|
160
|
+
self._sv.setStack(self._input_dataset.as_array3d())
|
|
164
161
|
else:
|
|
165
162
|
self._sv.setStack(self._input_dataset.z_sum_along_axis(self._axis))
|