38
38
from xarray .core .utils import (
39
39
FrozenMappingWarningOnValuesAccess ,
40
40
either_dict_or_kwargs ,
41
+ emit_user_level_warning ,
41
42
hashable ,
42
43
is_scalar ,
43
44
maybe_wrap_array ,
@@ -482,43 +483,66 @@ def _factorize(self, squeeze: bool) -> T_FactorizeOut:
482
483
483
484
484
485
@dataclass
485
- class ResolvedTimeResampleGrouper (ResolvedGrouper ):
486
- grouper : TimeResampleGrouper
486
+ class ResolvedTimeResampler (ResolvedGrouper ):
487
+ grouper : TimeResampler
487
488
index_grouper : CFTimeGrouper | pd .Grouper = field (init = False )
489
+ group_as_index : pd .Index = field (init = False )
490
+
491
+ def __post_init__ (self ):
492
+ if self .loffset is not None :
493
+ emit_user_level_warning (
494
+ "Following pandas, the `loffset` parameter to resample will be deprecated "
495
+ "in a future version of xarray. Switch to using time offset arithmetic." ,
496
+ FutureWarning ,
497
+ )
488
498
489
- def __post_init__ (self ) -> None :
490
- super ().__post_init__ ()
499
+ if self .base is not None :
500
+ emit_user_level_warning (
501
+ "Following pandas, the `base` parameter to resample will be deprecated in "
502
+ "a future version of xarray. Switch to using `origin` or `offset` instead." ,
503
+ FutureWarning ,
504
+ )
505
+
506
+ if self .base is not None and self .offset is not None :
507
+ raise ValueError ("base and offset cannot be present at the same time" )
491
508
509
+ def _init_properties (self , group ):
492
510
from xarray import CFTimeIndex
511
+ from xarray .core .pdcompat import _convert_base_to_offset
493
512
494
- group_as_index = safe_cast_to_index (self .group )
495
- self ._group_as_index = group_as_index
513
+ group_as_index = safe_cast_to_index (group )
514
+
515
+ if self .base is not None :
516
+ # grouper constructor verifies that grouper.offset is None at this point
517
+ offset = _convert_base_to_offset (self .base , self .freq , group_as_index )
518
+ else :
519
+ offset = self .offset
496
520
497
521
if not group_as_index .is_monotonic_increasing :
498
522
# TODO: sort instead of raising an error
499
523
raise ValueError ("index must be monotonic for resampling" )
500
524
501
- grouper = self .grouper
502
525
if isinstance (group_as_index , CFTimeIndex ):
503
526
from xarray .core .resample_cftime import CFTimeGrouper
504
527
505
528
index_grouper = CFTimeGrouper (
506
- freq = grouper .freq ,
507
- closed = grouper .closed ,
508
- label = grouper .label ,
509
- origin = grouper .origin ,
510
- offset = grouper . offset ,
511
- loffset = grouper .loffset ,
529
+ freq = self .freq ,
530
+ closed = self .closed ,
531
+ label = self .label ,
532
+ origin = self .origin ,
533
+ offset = offset ,
534
+ loffset = self .loffset ,
512
535
)
513
536
else :
514
537
index_grouper = pd .Grouper (
515
- freq = grouper .freq ,
516
- closed = grouper .closed ,
517
- label = grouper .label ,
518
- origin = grouper .origin ,
519
- offset = grouper . offset ,
538
+ freq = self .freq ,
539
+ closed = self .closed ,
540
+ label = self .label ,
541
+ origin = self .origin ,
542
+ offset = offset ,
520
543
)
521
544
self .index_grouper = index_grouper
545
+ self .group_as_index = group_as_index
522
546
523
547
def _get_index_and_items (self ) -> tuple [pd .Index , pd .Series , np .ndarray ]:
524
548
first_items , codes = self .first_items ()
@@ -543,22 +567,21 @@ def first_items(self) -> tuple[pd.Series, np.ndarray]:
543
567
# So for _flox_reduce we avoid one reindex and copy by avoiding
544
568
# _maybe_restore_empty_groups
545
569
codes = np .repeat (np .arange (len (first_items )), counts )
546
- if self .grouper . loffset is not None :
547
- _apply_loffset (self .grouper . loffset , first_items )
570
+ if self .loffset is not None :
571
+ _apply_loffset (self .loffset , first_items )
548
572
return first_items , codes
549
573
550
- def _factorize (self , squeeze : bool ) -> T_FactorizeOut :
574
+ def _factorize (self , group ) -> T_FactorizeOut :
575
+ self ._init_properties (group )
551
576
full_index , first_items , codes_ = self ._get_index_and_items ()
552
577
sbins = first_items .values .astype (np .int64 )
553
578
group_indices : T_GroupIndices = [
554
579
slice (i , j ) for i , j in zip (sbins [:- 1 ], sbins [1 :])
555
580
]
556
581
group_indices += [slice (sbins [- 1 ], None )]
557
582
558
- unique_coord = IndexVariable (
559
- self .group .name , first_items .index , self .group .attrs
560
- )
561
- codes = self .group .copy (data = codes_ )
583
+ unique_coord = IndexVariable (group .name , first_items .index , group .attrs )
584
+ codes = group .copy (data = codes_ )
562
585
563
586
return codes , group_indices , unique_coord , full_index
564
587
@@ -583,13 +606,32 @@ def __post_init__(self) -> None:
583
606
584
607
585
608
@dataclass
586
- class TimeResampleGrouper (Grouper ):
609
+ class TimeResampler (Grouper ):
587
610
freq : str
588
- closed : SideOptions | None
589
- label : SideOptions | None
590
- origin : str | DatetimeLike | None
591
- offset : pd .Timedelta | datetime .timedelta | str | None
592
- loffset : datetime .timedelta | str | None
611
+ closed : SideOptions | None = field (default = None )
612
+ label : SideOptions | None = field (default = None )
613
+ origin : str | DatetimeLike = field (default = "start_day" )
614
+ offset : pd .Timedelta | datetime .timedelta | str | None = field (default = None )
615
+ loffset : datetime .timedelta | str | None = field (default = None )
616
+ base : str | None = field (default = None )
617
+
618
+ def __post_init__ (self ):
619
+ if self .loffset is not None :
620
+ emit_user_level_warning (
621
+ "Following pandas, the `loffset` parameter to resample will be deprecated "
622
+ "in a future version of xarray. Switch to using time offset arithmetic." ,
623
+ FutureWarning ,
624
+ )
625
+
626
+ if self .base is not None :
627
+ emit_user_level_warning (
628
+ "Following pandas, the `base` parameter to resample will be deprecated in "
629
+ "a future version of xarray. Switch to using `origin` or `offset` instead." ,
630
+ FutureWarning ,
631
+ )
632
+
633
+ if self .base is not None and self .offset is not None :
634
+ raise ValueError ("base and offset cannot be present at the same time" )
593
635
594
636
595
637
def _validate_groupby_squeeze (squeeze : bool ) -> None :
@@ -936,7 +978,7 @@ def _maybe_restore_empty_groups(self, combined):
936
978
"""
937
979
(grouper ,) = self .groupers
938
980
if (
939
- isinstance (grouper , (ResolvedBinGrouper , ResolvedTimeResampleGrouper ))
981
+ isinstance (grouper , (ResolvedBinGrouper , ResolvedTimeResampler ))
940
982
and grouper .name in combined .dims
941
983
):
942
984
indexers = {grouper .name : grouper .full_index }
0 commit comments