5
5
import pandas as pd
6
6
7
7
from .pycompat import basestring , suppress , dask_array_type , OrderedDict
8
+ from . import dtypes
8
9
from . import formatting
10
+ from . import ops
9
11
from .utils import SortedKeysDict , not_implemented , Frozen
10
12
11
13
@@ -557,64 +559,74 @@ def resample(self, freq, dim, how='mean', skipna=None, closed=None,
557
559
result = result .rename ({RESAMPLE_DIM : dim .name })
558
560
return result
559
561
560
- def where (self , cond , other = None , drop = False ):
561
- """Return an object of the same shape with all entries where cond is
562
- True and all other entries masked.
562
+ def where (self , cond , other = dtypes .NA , drop = False ):
563
+ """Filter elements from this object according to a condition.
563
564
564
565
This operation follows the normal broadcasting and alignment rules that
565
566
xarray uses for binary arithmetic.
566
567
567
568
Parameters
568
569
----------
569
- cond : boolean DataArray or Dataset
570
- other : unimplemented, optional
571
- Unimplemented placeholder for compatibility with future
572
- numpy / pandas versions
570
+ cond : DataArray or Dataset with boolean dtype
571
+ Locations at which to preserve this object's values.
572
+ other : scalar, DataArray or Dataset, optional
573
+ Value to use for locations in this object where ``cond`` is False.
574
+ By default, these locations filled with NA.
573
575
drop : boolean, optional
574
- Coordinate labels that only correspond to NA values should be
575
- dropped
576
+ If True, coordinate labels that only correspond to False values of
577
+ the condition are dropped from the result. Mutually exclusive with
578
+ ``other``.
576
579
577
580
Returns
578
581
-------
579
- same type as caller or if drop=True same type as caller with dimensions
580
- reduced for dim element where mask is True
582
+ Same type as caller.
581
583
582
584
Examples
583
585
--------
584
586
585
587
>>> import numpy as np
586
588
>>> a = xr.DataArray(np.arange(25).reshape(5, 5), dims=('x', 'y'))
587
- >>> a.where((a > 6) & (a < 18) )
589
+ >>> a.where(a.x + a.y < 4 )
588
590
<xarray.DataArray (x: 5, y: 5)>
589
- array([[ nan , nan , nan , nan , nan],
590
- [ nan, nan , 7 ., 8 ., 9. ],
591
- [ 10., 11., 12. , 13. , 14. ],
592
- [ 15., 16. , 17. , nan, nan],
591
+ array([[ 0. , 1. , 2. , 3. , nan],
592
+ [ 5. , 6 ., 7 ., nan, nan ],
593
+ [ 10., 11., nan , nan , nan ],
594
+ [ 15., nan , nan , nan, nan],
593
595
[ nan, nan, nan, nan, nan]])
594
- Coordinates:
595
- * y (y) int64 0 1 2 3 4
596
- * x (x) int64 0 1 2 3 4
597
- >>> a.where((a > 6) & (a < 18), drop=True)
596
+ Dimensions without coordinates: x, y
597
+ >>> a.where(a.x + a.y < 5, -1)
598
598
<xarray.DataArray (x: 5, y: 5)>
599
- array([[ nan, nan, 7., 8., 9.],
600
- [ 10., 11., 12., 13., 14.],
601
- [ 15., 16., 17., nan, nan],
602
- Coordinates:
603
- * x (x) int64 1 2 3
604
- * y (y) int64 0 1 2 3 4
599
+ array([[ 0, 1, 2, 3, 4],
600
+ [ 5, 6, 7, 8, -1],
601
+ [10, 11, 12, -1, -1],
602
+ [15, 16, -1, -1, -1],
603
+ [20, -1, -1, -1, -1]])
604
+ Dimensions without coordinates: x, y
605
+ >>> a.where(a.x + a.y < 4, drop=True)
606
+ <xarray.DataArray (x: 4, y: 4)>
607
+ array([[ 0., 1., 2., 3.],
608
+ [ 5., 6., 7., nan],
609
+ [ 10., 11., nan, nan],
610
+ [ 15., nan, nan, nan]])
611
+ Dimensions without coordinates: x, y
612
+
613
+ See also
614
+ --------
615
+ numpy.where : corresponding numpy function
616
+ where : equivalent function
605
617
"""
606
- if other is not None :
607
- raise NotImplementedError ( "The optional argument 'other' has not "
608
- "yet been implemented" )
618
+ from . alignment import align
619
+ from . dataarray import DataArray
620
+ from . dataset import Dataset
609
621
610
622
if drop :
611
- from .dataarray import DataArray
612
- from .dataset import Dataset
613
- from .alignment import align
623
+ if other is not dtypes .NA :
624
+ raise ValueError ('cannot set `other` if drop=True' )
614
625
615
626
if not isinstance (cond , (Dataset , DataArray )):
616
- raise TypeError ("Cond argument is %r but must be a %r or %r" %
627
+ raise TypeError ("cond argument is %r but must be a %r or %r" %
617
628
(cond , Dataset , DataArray ))
629
+
618
630
# align so we can use integer indexing
619
631
self , cond = align (self , cond )
620
632
@@ -627,16 +639,11 @@ def where(self, cond, other=None, drop=False):
627
639
# clip the data corresponding to coordinate dims that are not used
628
640
nonzeros = zip (clipcond .dims , np .nonzero (clipcond .values ))
629
641
indexers = {k : np .unique (v ) for k , v in nonzeros }
630
- outobj = self .isel (** indexers )
631
- outcond = cond .isel (** indexers )
632
- else :
633
- outobj = self
634
- outcond = cond
635
642
636
- # preserve attributes
637
- out = outobj . _where ( outcond )
638
- out . _copy_attrs_from ( self )
639
- return out
643
+ self = self . isel ( ** indexers )
644
+ cond = cond . isel ( ** indexers )
645
+
646
+ return ops . where_method ( self , cond , other )
640
647
641
648
def close (self ):
642
649
"""Close any files linked to this object
@@ -658,42 +665,6 @@ def __exit__(self, exc_type, exc_value, traceback):
658
665
__or__ = __div__ = __eq__ = __ne__ = not_implemented
659
666
660
667
661
- def _maybe_promote (dtype ):
662
- """Simpler equivalent of pandas.core.common._maybe_promote"""
663
- # N.B. these casting rules should match pandas
664
- if np .issubdtype (dtype , float ):
665
- fill_value = np .nan
666
- elif np .issubdtype (dtype , int ):
667
- # convert to floating point so NaN is valid
668
- dtype = float
669
- fill_value = np .nan
670
- elif np .issubdtype (dtype , complex ):
671
- fill_value = np .nan + np .nan * 1j
672
- elif np .issubdtype (dtype , np .datetime64 ):
673
- fill_value = np .datetime64 ('NaT' )
674
- elif np .issubdtype (dtype , np .timedelta64 ):
675
- fill_value = np .timedelta64 ('NaT' )
676
- else :
677
- dtype = object
678
- fill_value = np .nan
679
- return np .dtype (dtype ), fill_value
680
-
681
-
682
- def _possibly_convert_objects (values ):
683
- """Convert arrays of datetime.datetime and datetime.timedelta objects into
684
- datetime64 and timedelta64, according to the pandas convention.
685
- """
686
- return np .asarray (pd .Series (values .ravel ())).reshape (values .shape )
687
-
688
-
689
- def _get_fill_value (dtype ):
690
- """Return a fill value that appropriately promotes types when used with
691
- np.concatenate
692
- """
693
- _ , fill_value = _maybe_promote (dtype )
694
- return fill_value
695
-
696
-
697
668
def full_like (other , fill_value , dtype = None ):
698
669
"""Return a new object with the same shape and type as a given object.
699
670
@@ -761,10 +732,3 @@ def ones_like(other, dtype=None):
761
732
"""Shorthand for full_like(other, 1, dtype)
762
733
"""
763
734
return full_like (other , 1 , dtype )
764
-
765
-
766
- def is_datetime_like (dtype ):
767
- """Check if a dtype is a subclass of the numpy datetime types
768
- """
769
- return (np .issubdtype (dtype , np .datetime64 ) or
770
- np .issubdtype (dtype , np .timedelta64 ))
0 commit comments