@@ -1745,8 +1745,8 @@ def maybe_chunk(name, var, chunks):
1745
1745
return self ._replace (variables )
1746
1746
1747
1747
def _validate_indexers (
1748
- self , indexers : Mapping
1749
- ) -> List [Tuple [Any , Union [slice , Variable ]]]:
1748
+ self , indexers : Mapping [ Hashable , Any ]
1749
+ ) -> Iterator [Tuple [Hashable , Union [int , slice , np . ndarray , Variable ]]]:
1750
1750
""" Here we make sure
1751
1751
+ indexer has a valid keys
1752
1752
+ indexer is in a valid data type
@@ -1755,50 +1755,61 @@ def _validate_indexers(
1755
1755
"""
1756
1756
from .dataarray import DataArray
1757
1757
1758
- invalid = [ k for k in indexers if k not in self .dims ]
1758
+ invalid = indexers . keys () - self .dims . keys ()
1759
1759
if invalid :
1760
1760
raise ValueError ("dimensions %r do not exist" % invalid )
1761
1761
1762
1762
# all indexers should be int, slice, np.ndarrays, or Variable
1763
- indexers_list : List [Tuple [Any , Union [slice , Variable ]]] = []
1764
1763
for k , v in indexers .items ():
1765
- if isinstance (v , slice ):
1766
- indexers_list .append ((k , v ))
1767
- continue
1768
-
1769
- if isinstance (v , Variable ):
1770
- pass
1764
+ if isinstance (v , (int , slice , Variable )):
1765
+ yield k , v
1771
1766
elif isinstance (v , DataArray ):
1772
- v = v .variable
1767
+ yield k , v .variable
1773
1768
elif isinstance (v , tuple ):
1774
- v = as_variable (v )
1769
+ yield k , as_variable (v )
1775
1770
elif isinstance (v , Dataset ):
1776
1771
raise TypeError ("cannot use a Dataset as an indexer" )
1777
1772
elif isinstance (v , Sequence ) and len (v ) == 0 :
1778
- v = Variable (( k ,), np .zeros ((0 ,), dtype = "int64" ) )
1773
+ yield k , np .empty ((0 ,), dtype = "int64" )
1779
1774
else :
1780
1775
v = np .asarray (v )
1781
1776
1782
- if v .dtype .kind == "U" or v . dtype . kind == "S " :
1777
+ if v .dtype .kind in "US " :
1783
1778
index = self .indexes [k ]
1784
1779
if isinstance (index , pd .DatetimeIndex ):
1785
1780
v = v .astype ("datetime64[ns]" )
1786
1781
elif isinstance (index , xr .CFTimeIndex ):
1787
1782
v = _parse_array_of_cftime_strings (v , index .date_type )
1788
1783
1789
- if v .ndim == 0 :
1790
- v = Variable ((), v )
1791
- elif v .ndim == 1 :
1792
- v = Variable ((k ,), v )
1793
- else :
1784
+ if v .ndim > 1 :
1794
1785
raise IndexError (
1795
1786
"Unlabeled multi-dimensional array cannot be "
1796
1787
"used for indexing: {}" .format (k )
1797
1788
)
1789
+ yield k , v
1798
1790
1799
- indexers_list .append ((k , v ))
1800
-
1801
- return indexers_list
1791
+ def _validate_interp_indexers (
1792
+ self , indexers : Mapping [Hashable , Any ]
1793
+ ) -> Iterator [Tuple [Hashable , Variable ]]:
1794
+ """Variant of _validate_indexers to be used for interpolation
1795
+ """
1796
+ for k , v in self ._validate_indexers (indexers ):
1797
+ if isinstance (v , Variable ):
1798
+ if v .ndim == 1 :
1799
+ yield k , v .to_index_variable ()
1800
+ else :
1801
+ yield k , v
1802
+ elif isinstance (v , int ):
1803
+ yield k , Variable ((), v )
1804
+ elif isinstance (v , np .ndarray ):
1805
+ if v .ndim == 0 :
1806
+ yield k , Variable ((), v )
1807
+ elif v .ndim == 1 :
1808
+ yield k , IndexVariable ((k ,), v )
1809
+ else :
1810
+ raise AssertionError () # Already tested by _validate_indexers
1811
+ else :
1812
+ raise TypeError (type (v ))
1802
1813
1803
1814
def _get_indexers_coords_and_indexes (self , indexers ):
1804
1815
"""Extract coordinates and indexes from indexers.
@@ -1885,10 +1896,10 @@ def isel(
1885
1896
Dataset.sel
1886
1897
DataArray.isel
1887
1898
"""
1888
-
1889
1899
indexers = either_dict_or_kwargs (indexers , indexers_kwargs , "isel" )
1890
-
1891
- indexers_list = self ._validate_indexers (indexers )
1900
+ # Note: we need to preserve the original indexers variable in order to merge the
1901
+ # coords below
1902
+ indexers_list = list (self ._validate_indexers (indexers ))
1892
1903
1893
1904
variables = OrderedDict () # type: OrderedDict[Hashable, Variable]
1894
1905
indexes = OrderedDict () # type: OrderedDict[Hashable, pd.Index]
@@ -1904,19 +1915,21 @@ def isel(
1904
1915
)
1905
1916
if new_index is not None :
1906
1917
indexes [name ] = new_index
1907
- else :
1918
+ elif var_indexers :
1908
1919
new_var = var .isel (indexers = var_indexers )
1920
+ else :
1921
+ new_var = var .copy (deep = False )
1909
1922
1910
1923
variables [name ] = new_var
1911
1924
1912
- coord_names = set ( variables ). intersection ( self ._coord_names )
1925
+ coord_names = self ._coord_names & variables . keys ( )
1913
1926
selected = self ._replace_with_new_dims (variables , coord_names , indexes )
1914
1927
1915
1928
# Extract coordinates from indexers
1916
1929
coord_vars , new_indexes = selected ._get_indexers_coords_and_indexes (indexers )
1917
1930
variables .update (coord_vars )
1918
1931
indexes .update (new_indexes )
1919
- coord_names = set ( variables ). intersection ( self ._coord_names ). union ( coord_vars )
1932
+ coord_names = self ._coord_names & variables . keys () | coord_vars . keys ( )
1920
1933
return self ._replace_with_new_dims (variables , coord_names , indexes = indexes )
1921
1934
1922
1935
def sel (
@@ -2478,11 +2491,9 @@ def interp(
2478
2491
2479
2492
if kwargs is None :
2480
2493
kwargs = {}
2494
+
2481
2495
coords = either_dict_or_kwargs (coords , coords_kwargs , "interp" )
2482
- indexers = OrderedDict (
2483
- (k , v .to_index_variable () if isinstance (v , Variable ) and v .ndim == 1 else v )
2484
- for k , v in self ._validate_indexers (coords )
2485
- )
2496
+ indexers = OrderedDict (self ._validate_interp_indexers (coords ))
2486
2497
2487
2498
obj = self if assume_sorted else self .sortby ([k for k in coords ])
2488
2499
@@ -2507,26 +2518,25 @@ def _validate_interp_indexer(x, new_x):
2507
2518
"strings or datetimes. "
2508
2519
"Instead got\n {}" .format (new_x )
2509
2520
)
2510
- else :
2511
- return (x , new_x )
2521
+ return x , new_x
2512
2522
2513
2523
variables = OrderedDict () # type: OrderedDict[Hashable, Variable]
2514
2524
for name , var in obj ._variables .items ():
2515
- if name not in indexers :
2516
- if var . dtype . kind in "uifc" :
2517
- var_indexers = {
2518
- k : _validate_interp_indexer ( maybe_variable ( obj , k ), v )
2519
- for k , v in indexers . items ()
2520
- if k in var . dims
2521
- }
2522
- variables [ name ] = missing . interp (
2523
- var , var_indexers , method , ** kwargs
2524
- )
2525
- elif all (d not in indexers for d in var .dims ):
2526
- # keep unrelated object array
2527
- variables [name ] = var
2525
+ if name in indexers :
2526
+ continue
2527
+
2528
+ if var . dtype . kind in "uifc" :
2529
+ var_indexers = {
2530
+ k : _validate_interp_indexer ( maybe_variable ( obj , k ), v )
2531
+ for k , v in indexers . items ()
2532
+ if k in var . dims
2533
+ }
2534
+ variables [ name ] = missing . interp ( var , var_indexers , method , ** kwargs )
2535
+ elif all (d not in indexers for d in var .dims ):
2536
+ # keep unrelated object array
2537
+ variables [name ] = var
2528
2538
2529
- coord_names = set ( variables ). intersection ( obj ._coord_names )
2539
+ coord_names = obj ._coord_names & variables . keys ( )
2530
2540
indexes = OrderedDict (
2531
2541
(k , v ) for k , v in obj .indexes .items () if k not in indexers
2532
2542
)
@@ -2546,7 +2556,7 @@ def _validate_interp_indexer(x, new_x):
2546
2556
variables .update (coord_vars )
2547
2557
indexes .update (new_indexes )
2548
2558
2549
- coord_names = set ( variables ). intersection ( obj ._coord_names ). union ( coord_vars )
2559
+ coord_names = obj ._coord_names & variables . keys () | coord_vars . keys ( )
2550
2560
return self ._replace_with_new_dims (variables , coord_names , indexes = indexes )
2551
2561
2552
2562
def interp_like (
0 commit comments