99from sasdata .data_util .binning import DirectionalAverage
1010from sasdata .data_util .interval import IntervalType
1111from sasdata .data_util .roi import CartesianROI , PolarROI
12- from sasdata .dataloader . data_info import Data1D
12+ from sasdata .dataset_types import one_dim
1313from sasdata .quantities .constants import Pi , TwoPi
14+ from sasdata .quantities .quantity import Quantity
1415
1516
1617def get_dq_data (data2d : SasData ) -> npt .NDArray [np .floating ]:
@@ -140,7 +141,7 @@ class SlabX(CartesianROI):
140141 Average I(Q_x, Q_y) along the y direction (within a ROI), giving I(Q_x).
141142
142143 This class is initialised by specifying the boundaries of the ROI and is
143- called by supplying a SasData object. It returns a Data1D object.
144+ called by supplying a SasData object. It returns a SasData object.
144145 The averaging process can also be thought of as projecting 2D -> 1D.
145146
146147 There also exists the option to "fold" the ROI, where Q data on opposite
@@ -170,12 +171,12 @@ def __init__(
170171 self .fold : bool = fold
171172 self .base : float | None = base
172173
173- def __call__ (self , data2d : SasData = None ) -> Data1D :
174+ def __call__ (self , data2d : SasData = None ) -> SasData :
174175 """
175176 Compute the 1D average of 2D data, projecting along the Q_x axis.
176177
177178 :param data2d: The SasData object for which the average is computed.
178- :return: Data1D object for plotting.
179+ :return: SasData object for plotting.
179180 """
180181 self .validate_and_assign_data (data2d )
181182
@@ -201,15 +202,19 @@ def __call__(self, data2d: SasData = None) -> Data1D:
201202
202203 qx_data , intensity , error = directional_average (data = self .data , err_data = self .err_data )
203204
204- return Data1D (x = qx_data , y = intensity , dy = error )
205+ data_contents = {
206+ "Q" : Quantity (qx_data , data2d ._data_contents ["Qx" ].units , None ),
207+ "I" : Quantity (intensity , data2d ._data_contents ["I" ].units , error ),
208+ }
209+ return SasData (f"{ data2d .name } : Slab X Average" , data_contents , one_dim , data2d .metadata )
205210
206211
207212class SlabY (CartesianROI ):
208213 """
209214 Average I(Q_x, Q_y) along the x direction (within a ROI), giving I(Q_y).
210215
211216 This class is initialised by specifying the boundaries of the ROI and is
212- called by supplying a SasData object. It returns a Data1D object.
217+ called by supplying a SasData object. It returns a SasData object.
213218 The averaging process can also be thought of as projecting 2D -> 1D.
214219
215220 There also exists the option to "fold" the ROI, where Q data on opposite
@@ -240,12 +245,12 @@ def __init__(
240245 self .fold : bool = fold
241246 self .base : float | None = base
242247
243- def __call__ (self , data2d : SasData = None ) -> Data1D :
248+ def __call__ (self , data2d : SasData = None ) -> SasData :
244249 """
245250 Compute the 1D average of 2D data, projecting along the Q_y axis.
246251
247252 :param data2d: The SasData object for which the average is computed.
248- :return: Data1D object for plotting.
253+ :return: SasData object for plotting.
249254 """
250255 self .validate_and_assign_data (data2d )
251256
@@ -270,7 +275,11 @@ def __call__(self, data2d: SasData = None) -> Data1D:
270275 )
271276 qy_data , intensity , error = directional_average (data = self .data , err_data = self .err_data )
272277
273- return Data1D (x = qy_data , y = intensity , dy = error )
278+ data_contents = {
279+ "Q" : Quantity (qy_data , data2d ._data_contents ["Qy" ].units , None ),
280+ "I" : Quantity (intensity , data2d ._data_contents ["I" ].units , error ),
281+ }
282+ return SasData (f"{ data2d .name } : Slab Y Average" , data_contents , one_dim , data2d .metadata )
274283
275284
276285class CircularAverage (PolarROI ):
@@ -280,7 +289,7 @@ class CircularAverage(PolarROI):
280289 This class is initialised by specifying lower and upper limits on the
281290 magnitude of Q values to consider during the averaging, though currently
282291 SasView always calls this class using the full range of data. When called,
283- this class is supplied with a SasData object. It returns a Data1D object
292+ this class is supplied with a SasData object. It returns a SasData object
284293 where intensity is given as a function of Q only.
285294 """
286295
@@ -302,15 +311,15 @@ def __init__(
302311 self .nbins : int = nbins
303312 self .base : float | None = base
304313
305- def __call__ (self , data2D : SasData , ismask : bool = False ) -> Data1D :
314+ def __call__ (self , data2D : SasData , ismask : bool = False ) -> SasData :
306315 """
307316 Perform circular averaging on the data. Uses DirectionalAverage for
308317 bin construction and weights, and computes dx (d_q) using get_dq_data
309318 averaged with those weights so behavior matches the legacy implementation.
310319
311320 :param data2D: SasData object
312321 :param ismask: If True, respect data2D.mask (skip masked points). If False, ignore mask.
313- :return: Data1D object with x (bin centers), y (intensity), dy and dx (if available)
322+ :return: SasData object with x (bin centers), y (intensity), dy and dx (if available)
314323 """
315324 # Work on unmasked finite arrays first (matches legacy filtering)
316325 finite_mask = np .isfinite (data2D ._data_contents ["I" ].value )
@@ -369,11 +378,16 @@ def __call__(self, data2D: SasData, ismask: bool = False) -> Data1D:
369378 counts = np .sum (weights , axis = 1 )
370379 with np .errstate (divide = "ignore" , invalid = "ignore" ):
371380 dx_full = dq_weighted / counts
372- dx = dx_full [populated ]
381+ dQ = dx_full [populated ]
373382 else :
374- dx = None
383+ dQ = None
384+
385+ data_contents = {
386+ "Q" : Quantity (x , data2D ._data_contents ["Qx" ].units , dQ ),
387+ "I" : Quantity (intensity , data2D ._data_contents ["I" ].units , error ),
388+ }
389+ return SasData (f"{ data2D .name } : Circular Average" , data_contents , one_dim , data2D .metadata )
375390
376- return Data1D (x = x , y = intensity , dy = error , dx = dx )
377391
378392
379393class Ring (PolarROI ):
@@ -382,9 +396,8 @@ class Ring(PolarROI):
382396
383397 This class is initialised by specifying lower and upper limits on the
384398 magnitude of Q values to consider during the averaging. When called,
385- this class is supplied with a SasData object. It returns a Data1D object.
386- This Data1D object gives intensity as a function of the angle from the
387- positive x-axis, φ, only.
399+ this class is supplied with a SasData object. It returns a SasData object
400+ which gives intensity as a function of the angle from the positive x-axis, φ, only.
388401 """
389402
390403 def __init__ (
@@ -408,14 +421,14 @@ def __init__(
408421 self .nbins : int = nbins
409422 self .base : float | None = base
410423
411- def __call__ (self , data2D : SasData ) -> Data1D :
424+ def __call__ (self , data2D : SasData ) -> SasData :
412425 """
413426 Apply the ring to the data set.
414427 Returns the angular distribution for a given q range
415428
416429 :param data2D: SasData object
417430
418- :return: Data1D object
431+ :return: SasData object
419432 """
420433 if not isinstance (data2D , SasData ):
421434 msg = "Data supplied for ring averaging must be of type SasData."
@@ -489,7 +502,11 @@ def __call__(self, data2D: SasData) -> Data1D:
489502 msg = "Average Error: No points inside ROI to average..."
490503 raise ValueError (msg )
491504
492- return Data1D (x = phi_values [idx ], y = phi_bins [idx ], dy = phi_err [idx ])
505+ data_contents = {
506+ "Q" : Quantity (phi_values [idx ], data2D ._data_contents ["Qx" ].units , None ),
507+ "I" : Quantity (phi_bins [idx ], data2D ._data_contents ["I" ].units , phi_err [idx ]),
508+ }
509+ return SasData (f"{ data2D .name } : Ring Average" , data_contents , one_dim , data2D .metadata )
493510
494511
495512class SectorQ (PolarROI ):
@@ -511,7 +528,7 @@ class SectorQ(PolarROI):
511528 ROI data labelled using negative Q values.
512529
513530 When called, this class is supplied with a SasData object. It returns a
514- Data1D object where intensity is given as a function of Q only.
531+ SasData object where intensity is given as a function of Q only.
515532 """
516533
517534 def __init__ (
@@ -539,12 +556,12 @@ def __init__(
539556 self .fold : bool = fold
540557 self .base : float | None = base
541558
542- def __call__ (self , data2d : SasData = None ) -> Data1D :
559+ def __call__ (self , data2d : SasData = None ) -> SasData :
543560 """
544561 Compute the 1D average of 2D data, projecting along the Q_y axis.
545562
546563 :param data2d: The SasData object for which the average is computed.
547- :return: Data1D object for plotting.
564+ :return: SasData object for plotting.
548565 """
549566 self .validate_and_assign_data (data2d )
550567
@@ -621,15 +638,22 @@ def __call__(self, data2d: SasData = None) -> Data1D:
621638
622639 finite = np .isfinite (average_intensity )
623640
624- data1d = Data1D (x = combined_q [finite ], y = average_intensity [finite ], dy = combined_err [finite ])
641+ data_contents = {
642+ "Q" : Quantity (combined_q [finite ], data2d ._data_contents ["Qx" ].units , None ),
643+ "I" : Quantity (average_intensity [finite ], data2d ._data_contents ["I" ].units , combined_err [finite ]),
644+ }
625645 else :
626646 # The secondary ROI is labelled with negative Q values.
627647 combined_q = np .append (np .flip (- 1 * secondary_q ), primary_q )
628648 combined_intensity = np .append (np .flip (secondary_I ), primary_I )
629649 combined_error = np .append (np .flip (secondary_err ), primary_err )
630- data1d = Data1D (x = combined_q , y = combined_intensity , dy = combined_error )
631650
632- return data1d
651+ data_contents = {
652+ "Q" : Quantity (combined_q , data2d ._data_contents ["Qx" ].units , None ),
653+ "I" : Quantity (combined_intensity , data2d ._data_contents ["I" ].units , combined_error ),
654+ }
655+
656+ return SasData (f"{ data2d .name } :SectorQ Average" , data_contents , one_dim , data2d .metadata )
633657
634658
635659class WedgeQ (PolarROI ):
@@ -643,7 +667,7 @@ class WedgeQ(PolarROI):
643667 This class is initialised by specifying lower and upper limits on both the
644668 magnitude of Q and the angle φ.
645669 When called, this class is supplied with a SasData object. It returns a
646- Data1D object where intensity is given as a function of Q only.
670+ sasData object where intensity is given as a function of Q only.
647671 """
648672
649673 def __init__ (
@@ -666,12 +690,12 @@ def __init__(
666690 self .nbins : int = nbins
667691 self .base : float | None = base
668692
669- def __call__ (self , data2d : SasData = None ) -> Data1D :
693+ def __call__ (self , data2d : SasData = None ) -> SasData :
670694 """
671695 Compute the 1D average of 2D data, projecting along the Q_y axis.
672696
673697 :param data2d: The SasData object for which the average is computed.
674- :return: Data1D object for plotting.
698+ :return: SasData object for plotting.
675699 """
676700 self .validate_and_assign_data (data2d )
677701
@@ -711,7 +735,11 @@ def __call__(self, data2d: SasData = None) -> Data1D:
711735
712736 q_data , intensity , error = directional_average (data = self .data , err_data = self .err_data )
713737
714- return Data1D (x = q_data , y = intensity , dy = error )
738+ data_contents = {
739+ "Q" : Quantity (q_data , data2d ._data_contents ["Qx" ].units , None ),
740+ "I" : Quantity (intensity , data2d ._data_contents ["I" ].units , error ),
741+ }
742+ return SasData (f"{ data2d .name } : Wedge Q Average" , data_contents , one_dim , data2d .metadata )
715743
716744
717745class WedgePhi (PolarROI ):
@@ -724,7 +752,7 @@ class WedgePhi(PolarROI):
724752 This class is initialised by specifying lower and upper limits on both the
725753 magnitude of Q and the angle φ, measured anticlockwise from the positive
726754 x-axis. When called, this class is supplied with a SasData object. It returns
727- a Data1D object where intensity is given as a function of Q only.
755+ a SasData object where intensity is given as a function of Q only.
728756 """
729757
730758 def __init__ (
@@ -748,12 +776,12 @@ def __init__(
748776 self .nbins : int = nbins
749777 self .base : float | None = base
750778
751- def __call__ (self , data2d : SasData = None ) -> Data1D :
779+ def __call__ (self , data2d : SasData = None ) -> SasData :
752780 """
753781 Compute the 1D average of 2D data, projecting along the Q_y axis.
754782
755783 :param data2d: The SasData object for which the average is computed.
756- :return: Data1D object for plotting.
784+ :return: SasData object for plotting.
757785 """
758786 self .validate_and_assign_data (data2d )
759787
@@ -815,21 +843,11 @@ def __call__(self, data2d: SasData = None) -> Data1D:
815843 phi_centers = full_phi [populated ] + directional_average .bin_widths [populated ] / 2.0
816844
817845 # intensity and error returned by DirectionalAverage are already filtered to the populated/finite bins
818- return Data1D (x = phi_centers , y = intensity , dy = error )
819-
820- """
821- # Convert angular data back to the original phi range
822- phi_data += phi_offset
823- # In the old manipulations.py, we also had this shift to plot the data
824- # at the centre of the bins. I'm not sure why it's only angular binning
825- # which gets this treatment.
826- # TODO: Update this once non-linear binning options are implemented
827- weights = directional_average.compute_weights()
828- populated = np.sum(weights, axis=1) > 0
829- phi_data += directional_average.bin_widths[populated] / 2
830-
831- return Data1D(x=phi_data, y=intensity, dy=error)
832- """
846+ data_contents = {
847+ "Q" : Quantity (phi_centers , data2d ._data_contents ["Qx" ].units , None ),
848+ "I" : Quantity (intensity , data2d ._data_contents ["I" ].units , error ),
849+ }
850+ return SasData (f"{ data2d .name } : Wedge Phi Average" , data_contents , one_dim , data2d .metadata )
833851
834852
835853class SectorPhi (WedgePhi ):
0 commit comments