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.
Files changed (144) hide show
  1. darfix/core/data_selection.py +11 -2
  2. darfix/core/dataset.py +72 -157
  3. darfix/core/grainplot.py +44 -56
  4. darfix/core/{imageStack.py → image_stack.py} +9 -15
  5. darfix/core/moment_types.py +6 -0
  6. darfix/core/{noiseremoval.py → noise_removal.py} +25 -24
  7. darfix/core/noise_removal_type.py +14 -0
  8. darfix/core/positioners.py +6 -0
  9. darfix/core/rocking_curves.py +6 -3
  10. darfix/core/rocking_curves_map.py +1 -1
  11. darfix/core/{shiftcorrection.py → shift_correction.py} +1 -2
  12. darfix/core/state_of_operation.py +7 -46
  13. darfix/core/utils.py +0 -39
  14. darfix/dtypes.py +1 -9
  15. darfix/gui/{binningWidget.py → binning_widget.py} +2 -29
  16. darfix/gui/{blindSourceSeparationWidget.py → blind_source_separation_widget.py} +4 -16
  17. darfix/gui/{chooseDimensions.py → choose_dimensions.py} +1 -1
  18. darfix/gui/concatenate_scans.py +4 -4
  19. darfix/gui/data_selection/{hdf5_data_selection_widgets.py → hdf5_dataset_selection_widget.py} +3 -56
  20. darfix/gui/data_selection/line_edits.py +54 -8
  21. darfix/gui/data_selection/scan_selection_widgets.py +24 -11
  22. darfix/gui/data_selection/utils.py +11 -0
  23. darfix/gui/data_selection/{WorkingDirSelectionWidget.py → working_dir_selection_widget.py} +15 -14
  24. darfix/gui/{dimensionsWidget.py → dimensions_widget.py} +1 -1
  25. darfix/gui/{displayComponentsWidget.py → display_components_widget.py} +1 -1
  26. darfix/gui/{filterByDimension.py → filter_by_dimension.py} +1 -1
  27. darfix/gui/{grainplot/dimensionRangeSlider2D.py → grain_plot/dimension_range_slider_2d.py} +2 -2
  28. darfix/gui/{grainplot/grainPlotWidget.py → grain_plot/grain_plot_widget.py} +1 -1
  29. darfix/gui/{grainplot/mosaicityWidget.py → grain_plot/mosaicity_widget.py} +21 -23
  30. darfix/gui/{magnificationWidget.py → magnification_widget.py} +1 -1
  31. darfix/gui/{noiseremoval → noise_removal}/noise_removal_widget.py +12 -16
  32. darfix/gui/{noiseremoval → noise_removal}/operation_list_widget.py +2 -2
  33. darfix/gui/{noiseremoval → noise_removal}/parameters_widget.py +6 -6
  34. darfix/gui/{PCAWidget.py → pca_widget.py} +2 -4
  35. darfix/gui/{projectionWidget.py → projection_widget.py} +1 -1
  36. darfix/gui/rocking_curves/{rockingCurvesPlot.py → rocking_curves_plot.py} +13 -13
  37. darfix/gui/rocking_curves/{rockingCurvesWidget.py → rocking_curves_widget.py} +10 -18
  38. darfix/gui/{roiSelectionWidget.py → roi_selection_widget.py} +9 -101
  39. darfix/gui/{shiftcorrection/shiftCorrectionWidget.py → shift_correction/shift_correction_widget.py} +4 -7
  40. darfix/gui/utils/data_path_completer.py +7 -7
  41. darfix/gui/utils/data_path_selection.py +4 -4
  42. darfix/gui/utils/{rangeSlider.py → range_slider.py} +1 -1
  43. darfix/gui/{weakBeamWidget.py → weak_beam_widget.py} +13 -28
  44. darfix/gui/{zSumWidget.py → zsum_widget.py} +1 -2
  45. darfix/main.py +19 -3
  46. darfix/processing/rocking_curves.py +12 -13
  47. darfix/tasks/binning.py +6 -17
  48. darfix/tasks/blind_source_separation.py +121 -0
  49. darfix/tasks/blindsourceseparation.py +8 -131
  50. darfix/tasks/copy.py +0 -2
  51. darfix/tasks/data_partition.py +39 -0
  52. darfix/tasks/datapartition.py +8 -50
  53. darfix/tasks/dimension_definition.py +197 -0
  54. darfix/tasks/dimensiondefinition.py +8 -197
  55. darfix/tasks/grain_plot.py +93 -0
  56. darfix/tasks/grainplot.py +8 -103
  57. darfix/tasks/hdf5_data_selection.py +5 -11
  58. darfix/tasks/hdf5_scans_concatenation.py +4 -4
  59. darfix/tasks/noise_removal.py +88 -0
  60. darfix/tasks/noiseremoval.py +8 -86
  61. darfix/tasks/pca.py +1 -3
  62. darfix/tasks/projection.py +1 -6
  63. darfix/tasks/rocking_curves.py +10 -5
  64. darfix/tasks/roi.py +0 -2
  65. darfix/tasks/shift_correction.py +45 -0
  66. darfix/tasks/shiftcorrection.py +8 -43
  67. darfix/tasks/transformation.py +0 -2
  68. darfix/tasks/weak_beam.py +71 -0
  69. darfix/tasks/weakbeam.py +8 -67
  70. darfix/tasks/zsum.py +1 -1
  71. darfix/tests/conftest.py +1 -1
  72. darfix/tests/gui/test_data_path_completer.py +4 -4
  73. darfix/tests/gui/test_dimension_range_slider_2d.py +2 -2
  74. darfix/tests/gui/test_range_slider_with_spinboxes.py +1 -1
  75. darfix/tests/orange/test_ewoks.py +13 -9
  76. darfix/tests/orange/widgets/test_hdf5_data_selection.py +93 -0
  77. darfix/tests/tasks/test_data_copy.py +0 -2
  78. darfix/tests/tasks/{test_dimensiondefinition.py → test_dimension_definition.py} +1 -1
  79. darfix/tests/tasks/test_weak_beam.py +9 -0
  80. darfix/tests/test_components_matching.py +2 -2
  81. darfix/tests/test_dataset.py +2 -28
  82. darfix/tests/test_dimension.py +1 -1
  83. darfix/tests/test_generate_grain_maps_nxdict.py +4 -5
  84. darfix/tests/test_image_operations.py +4 -4
  85. darfix/tests/test_image_registration.py +17 -17
  86. darfix/tests/test_image_stack.py +2 -13
  87. darfix/tests/test_mask.py +1 -1
  88. darfix/tests/test_moments.py +2 -2
  89. darfix/tests/test_rocking_curves.py +1 -3
  90. darfix/tests/test_shift.py +7 -7
  91. darfix/tests/test_workflow.py +4 -4
  92. darfix/tests/test_zsum.py +3 -6
  93. {darfix-4.2.0.dist-info → darfix-4.3.0.dist-info}/METADATA +5 -3
  94. {darfix-4.2.0.dist-info → darfix-4.3.0.dist-info}/RECORD +141 -135
  95. orangecontrib/darfix/widgets/__init__.py +10 -1
  96. orangecontrib/darfix/widgets/binning.py +3 -3
  97. orangecontrib/darfix/widgets/blindsourceseparation.py +4 -6
  98. orangecontrib/darfix/widgets/concatenateHDF5.py +1 -1
  99. orangecontrib/darfix/widgets/datacopy.py +1 -1
  100. orangecontrib/darfix/widgets/datapartition.py +7 -102
  101. orangecontrib/darfix/widgets/{datasetWidgetBase.py → dataset_widget_base.py} +17 -5
  102. orangecontrib/darfix/widgets/dimensions.py +6 -6
  103. orangecontrib/darfix/widgets/grainplot.py +3 -3
  104. orangecontrib/darfix/widgets/hdf5dataselection.py +34 -14
  105. orangecontrib/darfix/widgets/metadata.py +2 -2
  106. orangecontrib/darfix/widgets/noiseremoval.py +4 -4
  107. orangecontrib/darfix/widgets/{operationWidgetBase.py → operation_widget_base.py} +2 -2
  108. orangecontrib/darfix/widgets/pca.py +2 -2
  109. orangecontrib/darfix/widgets/projection.py +2 -2
  110. orangecontrib/darfix/widgets/rockingcurves.py +5 -2
  111. orangecontrib/darfix/widgets/roiselection.py +24 -106
  112. orangecontrib/darfix/widgets/rsmhistogram.py +2 -2
  113. orangecontrib/darfix/widgets/shiftcorrection.py +3 -3
  114. orangecontrib/darfix/widgets/transformation.py +4 -4
  115. orangecontrib/darfix/widgets/weakbeam.py +20 -103
  116. orangecontrib/darfix/widgets/zsum.py +3 -5
  117. darfix/gui/dataPartitionWidget.py +0 -167
  118. darfix/gui/data_selection/DataSelectionBase.py +0 -59
  119. darfix/tests/tasks/test_datapartition.py +0 -52
  120. /darfix/core/{componentsMatching.py → components_matching.py} +0 -0
  121. /darfix/core/{datapathfinder.py → data_path_finder.py} +0 -0
  122. /darfix/core/{imageRegistration.py → image_registration.py} +0 -0
  123. /darfix/gui/{grainplot → grain_plot}/__init__.py +0 -0
  124. /darfix/gui/{grainplot → grain_plot}/_oridist_toolbar_buttons.py +0 -0
  125. /darfix/gui/{grainplot → grain_plot}/flashlight.py +0 -0
  126. /darfix/gui/{grainplot → grain_plot}/flashlight_mode_action.py +0 -0
  127. /darfix/gui/{grainplot → grain_plot}/oridist_toolbar.py +0 -0
  128. /darfix/gui/{grainplot → grain_plot}/utils.py +0 -0
  129. /darfix/gui/{metadataWidget.py → metadata_widget.py} +0 -0
  130. /darfix/gui/{operationProcess.py → parallel/operation_process.py} +0 -0
  131. /darfix/gui/{operationThread.py → parallel/operation_thread.py} +0 -0
  132. /darfix/gui/rocking_curves/{fitComboBox.py → fit_combobox.py} +0 -0
  133. /darfix/gui/{roiLimitsToolbar.py → roi_limits_toolbar.py} +0 -0
  134. /darfix/gui/{rsmHistogramWidget.py → rsm_histogram_widget.py} +0 -0
  135. /darfix/gui/{rsmWidget.py → rsm_widget.py} +0 -0
  136. /darfix/gui/{shiftcorrection → shift_correction}/__init__.py +0 -0
  137. /darfix/gui/{shiftcorrection/shiftInput.py → shift_correction/shift_input.py} +0 -0
  138. /darfix/gui/utils/{standardButtonBox.py → standard_buttonbox.py} +0 -0
  139. /darfix/processing/{imageOperations.py → image_operations.py} +0 -0
  140. /darfix/tests/{test_datapathfinder.py → test_data_path_finder.py} +0 -0
  141. {darfix-4.2.0.dist-info → darfix-4.3.0.dist-info}/WHEEL +0 -0
  142. {darfix-4.2.0.dist-info → darfix-4.3.0.dist-info}/entry_points.txt +0 -0
  143. {darfix-4.2.0.dist-info → darfix-4.3.0.dist-info}/licenses/LICENSE +0 -0
  144. {darfix-4.2.0.dist-info → darfix-4.3.0.dist-info}/top_level.txt +0 -0
darfix/core/grainplot.py CHANGED
@@ -1,13 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import warnings
3
4
  from dataclasses import dataclass
4
5
  from enum import Enum
5
6
  from typing import Any
6
- from typing import Dict
7
7
  from typing import Tuple
8
8
 
9
+ import colorstamps
9
10
  import numpy
10
- from matplotlib.colors import hsv_to_rgb
11
11
  from silx.math.medianfilter import medfilt2d
12
12
 
13
13
  from darfix.core.dimension import AcquisitionDims
@@ -16,19 +16,16 @@ from darfix.io.utils import create_nxdata_dict
16
16
 
17
17
  from ..dtypes import AxisType
18
18
  from ..dtypes import Dataset
19
+ from .moment_types import MomentsPerDimension
19
20
  from .moment_types import MomentType
20
- from .utils import compute_hsv
21
21
 
22
22
  DimensionRange = Tuple[float, float]
23
23
 
24
24
 
25
- DimensionMoments = Dict[MomentType, numpy.ndarray]
26
-
27
-
28
25
  @dataclass
29
26
  class GrainPlotMaps:
30
27
  dims: AcquisitionDims
31
- moments_dims: list[DimensionMoments]
28
+ moments_dims: MomentsPerDimension
32
29
  zsum: numpy.ndarray
33
30
  transformation: numpy.ndarray
34
31
  title: str
@@ -50,7 +47,7 @@ class GrainPlotMaps:
50
47
  )
51
48
 
52
49
 
53
- class OrientationDistData:
50
+ class GrainPlotData:
54
51
  KEY_IMAGE_SIZE = 1000
55
52
 
56
53
  def __init__(
@@ -61,27 +58,30 @@ class OrientationDistData:
61
58
  x_dimension_range: DimensionRange,
62
59
  y_dimension_range: DimensionRange,
63
60
  zsum: numpy.ndarray | None = None,
61
+ colormap_name: str = "hsv",
62
+ sat: int = 40,
64
63
  ) -> None:
65
64
  """
66
65
  Store data for orientation distribution RGB layer (the HSV colormap) and data (Histogram 2D)
67
66
 
68
67
  :param zsum: Precomputed dataset.zsum() used as the weight of the histogram 2D . If None dataset.zsum() is called.
68
+
69
+ :param colormap_name: See https://colorstamps.readthedocs.io/en/latest/index.html#quick-reference
70
+
71
+ :param sat: See https://colorstamps.readthedocs.io/en/latest/stamps.html#colorstamps.stamps.get_cmap
69
72
  """
70
73
 
71
74
  if len(grain_plot_maps.moments_dims) == 0:
72
75
  raise ValueError("Moments should be computed before.")
73
76
 
74
- com_x = grain_plot_maps.moments_dims[x_dimension][MomentType.COM].ravel()
75
- com_y = grain_plot_maps.moments_dims[y_dimension][MomentType.COM].ravel()
77
+ com_x = grain_plot_maps.moments_dims[x_dimension][MomentType.COM]
78
+ com_y = grain_plot_maps.moments_dims[y_dimension][MomentType.COM]
76
79
 
77
80
  self.x_range = x_dimension_range
78
81
  self.y_range = y_dimension_range
79
82
 
80
83
  if zsum is None:
81
84
  zsum = grain_plot_maps.zsum
82
- zsum = zsum.ravel()
83
- else:
84
- zsum = zsum.ravel()
85
85
 
86
86
  # automatic bins
87
87
  # In darfix<=3.x orientation distribution shape was the size of the dimension
@@ -92,16 +92,11 @@ class OrientationDistData:
92
92
  self.x_label = grain_plot_maps.dims.get(x_dimension).name
93
93
  self.y_label = grain_plot_maps.dims.get(y_dimension).name
94
94
 
95
- x_data = numpy.linspace(-1, 1, self.KEY_IMAGE_SIZE)
96
- y_data = numpy.linspace(-1, 1, self.KEY_IMAGE_SIZE)
97
- x_mesh, y_mesh = numpy.meshgrid(x_data, y_data)
98
- self.rgb_key = hsv_to_rgb(compute_hsv(x_mesh, y_mesh))
99
-
100
95
  # Histogram in 2D
101
96
  histogram, _, _ = numpy.histogram2d(
102
- com_y,
103
- com_x, # note: y first is in purpose : see numpy.histogram2d documentation
104
- weights=zsum, # We need to take into account pixel intensity
97
+ com_y.ravel(),
98
+ com_x.ravel(), # note: y first is in purpose : see numpy.histogram2d documentation
99
+ weights=zsum.ravel(), # We need to take into account pixel intensity
105
100
  bins=[self.y_bins, self.x_bins],
106
101
  range=[self.y_range, self.x_range],
107
102
  )
@@ -109,6 +104,28 @@ class OrientationDistData:
109
104
  """Orientation distribution data as an histogram 2D of the center of mass in two dimensions"""
110
105
  self.smooth_data = medfilt2d(numpy.ascontiguousarray(self.data))
111
106
  """ `self.data` filtered with a median filter 2D"""
107
+ with warnings.catch_warnings():
108
+ warnings.simplefilter("ignore", RuntimeWarning) # Ignore nan values warning
109
+ self.mosaicity, stamp = colorstamps.apply_stamp(
110
+ com_y,
111
+ com_x,
112
+ colormap_name,
113
+ vmin_0=self.y_range[0],
114
+ vmax_0=self.y_range[1],
115
+ vmin_1=self.x_range[0],
116
+ vmax_1=self.x_range[1],
117
+ sat=sat,
118
+ clip="none",
119
+ l=self.KEY_IMAGE_SIZE,
120
+ )
121
+
122
+ # Display pixel with null intensity as black
123
+ self.mosaicity[zsum == 0] = 0, 0, 0
124
+
125
+ # Display out of range pixel as grey
126
+ self.mosaicity[numpy.isnan(self.mosaicity)] = 0.2
127
+
128
+ self.rgb_key = stamp.cmap
112
129
 
113
130
  def x_data_values(self) -> numpy.ndarray:
114
131
  return numpy.linspace(
@@ -194,34 +211,6 @@ def get_axes(transformation: Transformation | None) -> tuple[
194
211
  return axes, axes_names, axes_long_names
195
212
 
196
213
 
197
- def compute_normalized_component(
198
- component: numpy.ndarray, dimension_range: DimensionRange
199
- ):
200
-
201
- min_component = dimension_range[0]
202
- max_component = dimension_range[1]
203
-
204
- return 2 * (component - min_component) / (max_component - min_component) - 1
205
-
206
-
207
- def compute_mosaicity(
208
- moments: dict[int, numpy.ndarray],
209
- x_dimension: int,
210
- y_dimension: int,
211
- x_dimension_range: DimensionRange,
212
- y_dimension_range: DimensionRange,
213
- ):
214
- norm_center_of_mass_x = compute_normalized_component(
215
- moments[x_dimension][MomentType.COM],
216
- dimension_range=x_dimension_range,
217
- )
218
- norm_center_of_mass_y = compute_normalized_component(
219
- moments[y_dimension][MomentType.COM],
220
- dimension_range=y_dimension_range,
221
- )
222
- return hsv_to_rgb(compute_hsv(norm_center_of_mass_x, norm_center_of_mass_y))
223
-
224
-
225
214
  def create_moment_nxdata_groups(
226
215
  parent: dict[str, Any],
227
216
  moment_data: numpy.ndarray,
@@ -243,8 +232,7 @@ def create_moment_nxdata_groups(
243
232
 
244
233
  def generate_grain_maps_nxdict(
245
234
  grainPlotMaps: GrainPlotMaps,
246
- mosaicity: numpy.ndarray | None,
247
- orientation_dist_image: OrientationDistData | None,
235
+ orientation_dist_image: GrainPlotData | None,
248
236
  ) -> dict:
249
237
  moments = grainPlotMaps.moments_dims
250
238
  axes, axes_names, axes_long_names = get_axes(grainPlotMaps.transformation)
@@ -255,9 +243,10 @@ def generate_grain_maps_nxdict(
255
243
  "@default": "entry",
256
244
  }
257
245
 
258
- if mosaicity is not None:
246
+ if orientation_dist_image is not None:
247
+
259
248
  nx["entry"][MultiDimMomentType.MOSAICITY.value] = create_nxdata_dict(
260
- mosaicity,
249
+ orientation_dist_image.mosaicity,
261
250
  MultiDimMomentType.MOSAICITY.value,
262
251
  axes,
263
252
  axes_names,
@@ -265,10 +254,7 @@ def generate_grain_maps_nxdict(
265
254
  rgba=True,
266
255
  )
267
256
  nx["entry"]["@default"] = MultiDimMomentType.MOSAICITY.value
268
- else:
269
- nx["entry"]["@default"] = MomentType.COM.value
270
257
 
271
- if orientation_dist_image is not None:
272
258
  nx["entry"][MultiDimMomentType.ORIENTATION_DIST.value] = {
273
259
  "key": create_nxdata_dict(
274
260
  orientation_dist_image.rgb_key,
@@ -291,6 +277,8 @@ def generate_grain_maps_nxdict(
291
277
  ),
292
278
  "@default": "data",
293
279
  }
280
+ else:
281
+ nx["entry"]["@default"] = MomentType.COM.value
294
282
 
295
283
  if grainPlotMaps.dims.ndim <= 1:
296
284
  create_moment_nxdata_groups(
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import warnings
3
4
  from typing import NamedTuple
4
5
  from typing import Sequence
5
6
 
@@ -75,17 +76,11 @@ class ImageStack:
75
76
  def data(self) -> numpy.ndarray:
76
77
  return self._data
77
78
 
78
- def as_array3d(self, indices=None) -> numpy.ndarray:
79
- if indices is None:
80
- indices = Ellipsis
81
- return self._data.reshape((self.nframes,) + self.frame_shape)[indices]
79
+ def as_array3d(self) -> numpy.ndarray:
80
+ return self._data.reshape((-1,) + self.frame_shape)
82
81
 
83
- def as_array2d(self, indices=None) -> numpy.ndarray:
84
- if indices is None:
85
- indices = Ellipsis
86
- return self._data.reshape((self.nframes, self.data.size // self.nframes))[
87
- indices
88
- ]
82
+ def as_array2d(self) -> numpy.ndarray:
83
+ return self._data.reshape((self.nframes, -1))
89
84
 
90
85
  def filter_indices(
91
86
  self,
@@ -95,6 +90,8 @@ class ImageStack:
95
90
  """
96
91
  :return selected_indices: a list of indices filtered by input `indices` and optionally filtered with one fixed dimension `fixed_dimension`. If inputs are None return the full range of indices.
97
92
  """
93
+ warnings.warn("`filter_indices` method is deprecated", DeprecationWarning)
94
+
98
95
  if fixed_dimension is not None and not isinstance(
99
96
  fixed_dimension, FixedDimension
100
97
  ):
@@ -122,7 +119,6 @@ class ImageStack:
122
119
 
123
120
  def get_filtered_data(
124
121
  self,
125
- indices: numpy.ndarray | None = None,
126
122
  fixed_dimension: FixedDimension | None = None,
127
123
  ):
128
124
  """
@@ -131,8 +127,6 @@ class ImageStack:
131
127
  :warning: if `fixed_dimension` is not None, this method duplicate the fitered part of the dataset.
132
128
  """
133
129
  if fixed_dimension is None:
134
- return self.as_array3d(indices)
130
+ return self.as_array3d()
135
131
 
136
- return self.as_array3d()[
137
- self.filter_indices(indices=indices, fixed_dimension=fixed_dimension)
138
- ]
132
+ return self.as_array3d()[self.filter_indices(fixed_dimension=fixed_dimension)]
@@ -1,6 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from enum import Enum
4
+ from typing import Dict
5
+
6
+ import numpy
4
7
 
5
8
 
6
9
  class MomentType(Enum):
@@ -8,3 +11,6 @@ class MomentType(Enum):
8
11
  FWHM = "FWHM"
9
12
  SKEWNESS = "Skewness"
10
13
  KURTOSIS = "Kurtosis"
14
+
15
+
16
+ MomentsPerDimension = Dict[int, Dict[MomentType, numpy.ndarray]]
@@ -13,34 +13,33 @@ from tqdm import tqdm
13
13
  from darfix.core.utils import OperationAborted
14
14
 
15
15
  from ..dtypes import Dataset
16
- from ..processing import imageOperations
17
- from .state_of_operation import Operation
16
+ from ..processing import image_operations
17
+ from .noise_removal_type import NoiseRemovalType
18
18
 
19
19
 
20
20
  class BackgroundType(_Enum):
21
21
  DATA = "Data"
22
- UNUSED_DATA = "Unused data (after partition)"
23
22
  DARK_DATA = "Dark data"
24
23
 
25
24
 
26
25
  class NoiseRemovalOperation(TypedDict):
27
- type: Operation
26
+ type: NoiseRemovalType
28
27
  parameters: dict[str, Any]
29
28
 
30
29
 
31
30
  def operation_to_str(op: NoiseRemovalOperation) -> str:
32
31
  result = None
33
32
  op_type = op["type"]
34
- if op_type is Operation.BS:
33
+ if op_type is NoiseRemovalType.BS:
35
34
  result = f"Background subtraction {op['parameters']}"
36
35
 
37
- elif op_type is Operation.HP:
36
+ elif op_type is NoiseRemovalType.HP:
38
37
  result = f"Hot pixel removal: {op['parameters']}"
39
38
 
40
- elif op_type is Operation.THRESHOLD:
39
+ elif op_type is NoiseRemovalType.THRESHOLD:
41
40
  result = f"Threshold removal: {op['parameters']}"
42
41
 
43
- elif op_type is Operation.MASK:
42
+ elif op_type is NoiseRemovalType.MASK:
44
43
  result = "Mask removal"
45
44
  else:
46
45
  raise ValueError(f"Unknown operation type {op_type}")
@@ -48,7 +47,11 @@ def operation_to_str(op: NoiseRemovalOperation) -> str:
48
47
 
49
48
 
50
49
  def clean_operation_dict(op: NoiseRemovalOperation) -> dict:
51
- """Just keep `type` and `parameters` in the saved dict"""
50
+ """Just keep `type` and `parameters` in the saved dict. Transform numpy array into list."""
51
+ parameters = op["parameters"]
52
+ for key, value in parameters.items():
53
+ if isinstance(value, numpy.ndarray):
54
+ parameters[key] = value.tolist()
52
55
  return {
53
56
  "type": op["type"],
54
57
  "parameters": op["parameters"],
@@ -58,29 +61,29 @@ def clean_operation_dict(op: NoiseRemovalOperation) -> dict:
58
61
  def apply_noise_removal_operation(
59
62
  image: numpy.ndarray, operation: NoiseRemovalOperation
60
63
  ) -> None:
61
- if operation["type"] is Operation.BS:
64
+ if operation["type"] is NoiseRemovalType.BS:
62
65
  apply_background_substraction(image, operation["background"])
63
66
 
64
- if operation["type"] is Operation.HP:
67
+ if operation["type"] is NoiseRemovalType.HP:
65
68
  apply_hot_pixel_removal(image, **operation["parameters"])
66
69
 
67
- if operation["type"] is Operation.THRESHOLD:
70
+ if operation["type"] is NoiseRemovalType.THRESHOLD:
68
71
  apply_threshold_removal(image, **operation["parameters"])
69
72
 
70
- if operation["type"] is Operation.MASK:
73
+ if operation["type"] is NoiseRemovalType.MASK:
71
74
  apply_mask_removal(image, **operation["parameters"])
72
75
 
73
76
 
74
77
  def add_background_data_into_operation(
75
78
  dataset: Dataset,
76
79
  operation: NoiseRemovalOperation,
77
- ) -> NoiseRemovalOperation:
78
- """Compute a background image and return a NoiseRemovalOperation with a background parameter"""
80
+ ) -> None:
81
+ """Compute a background image and add it into `operation["background"]`"""
79
82
 
80
- if operation["type"] is not Operation.BS:
83
+ if operation["type"] is not NoiseRemovalType.BS:
81
84
  raise ValueError("Operation type should be `Operation.BS`")
82
85
 
83
- method = operation["parameters"].get("method", imageOperations.Method.MEDIAN)
86
+ method = operation["parameters"].get("method", image_operations.Method.MEDIAN)
84
87
 
85
88
  background_type = BackgroundType(
86
89
  operation["parameters"].get("background_type", BackgroundType.DATA.value)
@@ -88,8 +91,6 @@ def add_background_data_into_operation(
88
91
 
89
92
  if background_type is BackgroundType.DARK_DATA:
90
93
  bg = dataset.bg_dataset.as_array3d()
91
- elif background_type is BackgroundType.UNUSED_DATA:
92
- bg = dataset.dataset.as_array3d(dataset.bg_indices)
93
94
  elif background_type is BackgroundType.DATA:
94
95
  bg = dataset.dataset.as_array3d()
95
96
  else:
@@ -97,13 +98,13 @@ def add_background_data_into_operation(
97
98
  f"Background type {background_type!r} not implemented yet."
98
99
  )
99
100
 
100
- operation["background"] = imageOperations.compute_background(bg, method)
101
+ operation["background"] = image_operations.compute_background(bg, method)
101
102
 
102
103
 
103
104
  def apply_background_substraction(
104
105
  image: numpy.ndarray, background: numpy.ndarray
105
106
  ) -> None:
106
- imageOperations.background_subtraction(image, background)
107
+ image_operations.background_subtraction(image, background)
107
108
 
108
109
 
109
110
  def apply_hot_pixel_removal(
@@ -112,19 +113,19 @@ def apply_hot_pixel_removal(
112
113
  if kernel_size is None:
113
114
  kernel_size = 3
114
115
 
115
- imageOperations.hot_pixel_removal(image, ksize=kernel_size)
116
+ image_operations.hot_pixel_removal(image, ksize=kernel_size)
116
117
 
117
118
 
118
119
  def apply_threshold_removal(
119
120
  image: numpy.ndarray, bottom: int | None = None, top: int | None = None
120
121
  ) -> None:
121
- imageOperations.threshold_removal(image, bottom=bottom, top=top)
122
+ image_operations.threshold_removal(image, bottom=bottom, top=top)
122
123
 
123
124
 
124
125
  def apply_mask_removal(image: numpy.ndarray, mask: numpy.ndarray | None) -> None:
125
126
  if mask is None:
126
127
  return
127
- imageOperations.mask_removal(image, mask)
128
+ image_operations.mask_removal(image, numpy.asarray(mask, dtype=bool))
128
129
 
129
130
 
130
131
  def apply_noise_removal_operations(
@@ -0,0 +1,14 @@
1
+ from __future__ import annotations
2
+
3
+ from enum import Enum
4
+
5
+
6
+ class NoiseRemovalType(Enum):
7
+ """
8
+ Enumeration of existing Noise Removal Operations in Darfix
9
+ """
10
+
11
+ BS = 1
12
+ HP = 2
13
+ THRESHOLD = 3
14
+ MASK = 9
@@ -38,6 +38,12 @@ class Positioners:
38
38
  else:
39
39
  self.load()
40
40
 
41
+ def filter_by_indices(self, indices: numpy.ndarray) -> Positioners:
42
+ new_positioners = Positioners(self._url, dict(**self._data))
43
+ for positioner_name, positioner_data in self._data.items():
44
+ new_positioners._data[positioner_name] = positioner_data[indices]
45
+ return new_positioners
46
+
41
47
  def all(self):
42
48
  """
43
49
  Merge constants and data in the same dict
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from threading import Event
3
4
  from typing import Sequence
4
5
 
5
6
  import numpy
@@ -48,6 +49,7 @@ def fit_rocking_curve_parallel(
48
49
  motor_values: Sequence[numpy.ndarray] | numpy.ndarray,
49
50
  thresh: float | None,
50
51
  method: FitMethod | None,
52
+ abort_event: Event = Event(),
51
53
  ) -> tuple[numpy.ndarray, numpy.ndarray]:
52
54
  """
53
55
  Fit the rocking curves using multiprocessing.
@@ -95,6 +97,8 @@ def fit_rocking_curve_parallel(
95
97
  i = idx % data.shape[2]
96
98
  output_data[:, j, i] = y_gauss
97
99
  maps[:, j, i] = maps_ji
100
+ if abort_event.is_set():
101
+ break
98
102
 
99
103
  return output_data, maps
100
104
 
@@ -155,13 +159,12 @@ def generate_rocking_curves_nxdict(
155
159
  def compute_residuals(
156
160
  target_dataset, # ImageDataset. Cannot type due to circular import
157
161
  original_dataset, # ImageDataset. Cannot type due to circular import
158
- indices: numpy.ndarray | None,
159
162
  ):
160
163
  return numpy.sqrt(
161
164
  (
162
165
  numpy.subtract(
163
- target_dataset.as_array3d(indices),
164
- original_dataset.as_array3d(indices),
166
+ target_dataset.as_array3d(),
167
+ original_dataset.as_array3d(),
165
168
  )
166
169
  ** 2
167
170
  ).sum(axis=(0))
@@ -7,8 +7,8 @@ class Maps_1D(_Enum):
7
7
  """Names of the fitting parameters of the 1D fit result. Each result is a map of frame size."""
8
8
 
9
9
  AMPLITUDE = "Amplitude"
10
- FWHM = "FWHM"
11
10
  PEAK = "Peak position"
11
+ FWHM = "FWHM"
12
12
  BACKGROUND = "Background"
13
13
 
14
14
 
@@ -16,6 +16,5 @@ def apply_shift(
16
16
  shift = numpy.array(shift)
17
17
 
18
18
  dataset = input_dataset.dataset
19
- indices = input_dataset.indices
20
19
 
21
- dataset.apply_shift(shift, axis=selected_axis, indices=indices)
20
+ dataset.apply_shift(shift, axis=selected_axis)
@@ -1,48 +1,9 @@
1
- from __future__ import annotations
1
+ import warnings
2
2
 
3
- from contextlib import contextmanager
4
- from enum import IntEnum
5
- from typing import Optional
3
+ from darfix.core.noise_removal_type import NoiseRemovalType
6
4
 
7
-
8
- class Operation(IntEnum):
9
- """
10
- Flags for different operations in Dataset
11
- """
12
-
13
- PARTITION = 0
14
- BS = 1
15
- HP = 2
16
- THRESHOLD = 3
17
- SHIFT = 4
18
- ROI = 5
19
- MOMENTS = 6
20
- FIT = 7
21
- BINNING = 8
22
- MASK = 9
23
-
24
-
25
- class StateOfOperations:
26
- def __init__(self):
27
- self._is_running = [False] * len(Operation)
28
-
29
- def _start(self, operation: Optional[Operation]) -> None:
30
- if operation is None:
31
- return
32
- self._is_running[operation] = True
33
-
34
- def stop(self, operation: Optional[Operation]) -> None:
35
- if operation is None:
36
- return
37
- self._is_running[operation] = False
38
-
39
- @contextmanager
40
- def run_context(self, operation: Optional[Operation]):
41
- self._start(operation)
42
- try:
43
- yield
44
- finally:
45
- self.stop(operation)
46
-
47
- def is_running(self, operation: Operation) -> bool:
48
- return self._is_running[operation]
5
+ warnings.warn(
6
+ "Use of `Operation` class is deprecated and is only kept for backward compatibility with .ows file from Darfix < 4.3.",
7
+ DeprecationWarning,
8
+ )
9
+ Operation = NoiseRemovalType
darfix/core/utils.py CHANGED
@@ -29,42 +29,3 @@ class TooManyDimensionsForRockingCurvesError(ValueError):
29
29
  super().__init__(
30
30
  "Unsupported number of dimensions. Rocking curves only support 1D, 2D or 3D datasets."
31
31
  )
32
-
33
-
34
- def wrapTo2pi(x):
35
- """
36
- Python implementation of Matlab method `wrapTo2pi`.
37
- Wraps angles in x, in radians, to the interval [0, 2*pi] such that 0 maps
38
- to 0 and 2*pi maps to 2*pi. In general, positive multiples of 2*pi map to
39
- 2*pi and negative multiples of 2*pi map to 0.
40
- """
41
- xwrap = numpy.remainder(x - numpy.pi, TWO_PI)
42
- mask = numpy.abs(xwrap) > numpy.pi
43
- xwrap[mask] -= TWO_PI * numpy.sign(xwrap[mask])
44
- return xwrap + numpy.pi
45
-
46
-
47
- def compute_hsv(x_data: numpy.ndarray, y_data: numpy.ndarray):
48
- data = numpy.arctan2(-y_data, -x_data)
49
-
50
- hue = wrapTo2pi(data) / TWO_PI
51
- saturation = numpy.sqrt(numpy.power(x_data, 2) + numpy.power(y_data, 2)) / SQRT_2
52
- value = numpy.ones_like(x_data)
53
-
54
- # Display NaN values as black
55
- value[numpy.isnan(data)] = 0
56
- hue[numpy.isnan(data)] = 0
57
- saturation[numpy.isnan(data)] = 0
58
-
59
- # Display out of range as grey
60
- value[saturation > 1.0] = 0.2
61
- saturation[saturation > 1.0] = 1.0
62
-
63
- return numpy.stack(
64
- (
65
- hue,
66
- saturation,
67
- value,
68
- ),
69
- axis=2,
70
- )
darfix/dtypes.py CHANGED
@@ -7,8 +7,6 @@ from typing import Optional
7
7
  from typing import Tuple
8
8
  from typing import Union
9
9
 
10
- import numpy
11
-
12
10
  from darfix.core.dataset import ImageDataset
13
11
 
14
12
  AxisAndValueIndices = Tuple[List[int], List[int]]
@@ -20,20 +18,14 @@ class Dataset:
20
18
  def __init__(
21
19
  self,
22
20
  dataset: ImageDataset,
23
- indices: Optional[numpy.ndarray] = None,
24
- bg_indices: Optional[numpy.ndarray] = None,
25
21
  bg_dataset: Optional[ImageDataset] = None,
26
22
  ):
27
- """Darfix dataset with indices and background
23
+ """Darfix dataset and background
28
24
 
29
25
  :param dataset: Darfix dataset object that holds the image stack
30
- :param indices: Image stack indices to be taking into account. Usually set by the 'partition data' task. Defaults to None.
31
- :param bg_indices: Dark image stack indices to be taking into account. Usually set by the 'partition data' task. Defaults to None.
32
26
  :param bg_dataset: Darfix dataset object that holds the dark image stack. Defaults to None.
33
27
  """
34
28
  self.dataset = dataset
35
- self.indices = indices
36
- self.bg_indices = bg_indices
37
29
  self.bg_dataset = bg_dataset
38
30
 
39
31