6
6
Hashable ,
7
7
Iterator ,
8
8
Mapping ,
9
- Sequence ,
10
9
Set ,
10
+ Sequence ,
11
11
Tuple ,
12
12
Union ,
13
13
cast ,
17
17
18
18
from . import formatting , indexing
19
19
from .indexes import Indexes
20
- from .merge import (
21
- expand_and_merge_variables ,
22
- merge_coords ,
23
- merge_coords_for_inplace_math ,
24
- )
20
+ from .merge import merge_coords , merge_coordinates_without_align
25
21
from .utils import Frozen , ReprObject , either_dict_or_kwargs
26
22
from .variable import Variable
27
23
34
30
_THIS_ARRAY = ReprObject ("<this-array>" )
35
31
36
32
37
- class AbstractCoordinates (Mapping [Hashable , "DataArray" ]):
33
+ class Coordinates (Mapping [Hashable , "DataArray" ]):
38
34
__slots__ = ()
39
35
40
36
def __getitem__ (self , key : Hashable ) -> "DataArray" :
@@ -57,10 +53,10 @@ def indexes(self) -> Indexes:
57
53
58
54
@property
59
55
def variables (self ):
60
- raise NotImplementedError ()
56
+ raise NotImplementedError
61
57
62
- def _update_coords (self , coords ):
63
- raise NotImplementedError ()
58
+ def _update_coords (self , coords , indexes ):
59
+ raise NotImplementedError
64
60
65
61
def __iter__ (self ) -> Iterator ["Hashable" ]:
66
62
# needs to be in the same order as the dataset variables
@@ -116,38 +112,38 @@ def to_index(self, ordered_dims: Sequence[Hashable] = None) -> pd.Index:
116
112
117
113
def update (self , other : Mapping [Hashable , Any ]) -> None :
118
114
other_vars = getattr (other , "variables" , other )
119
- coords = merge_coords (
115
+ coords , indexes = merge_coords (
120
116
[self .variables , other_vars ], priority_arg = 1 , indexes = self .indexes
121
117
)
122
- self ._update_coords (coords )
118
+ self ._update_coords (coords , indexes )
123
119
124
120
def _merge_raw (self , other ):
125
121
"""For use with binary arithmetic."""
126
122
if other is None :
127
123
variables = OrderedDict (self .variables )
124
+ indexes = OrderedDict (self .indexes )
128
125
else :
129
- # don't align because we already called xarray.align
130
- variables = expand_and_merge_variables ([self .variables , other .variables ])
131
- return variables
126
+ variables , indexes = merge_coordinates_without_align ([self , other ])
127
+ return variables , indexes
132
128
133
129
@contextmanager
134
130
def _merge_inplace (self , other ):
135
131
"""For use with in-place binary arithmetic."""
136
132
if other is None :
137
133
yield
138
134
else :
139
- # don't include indexes in priority_vars , because we didn't align
140
- # first
141
- priority_vars = OrderedDict (
142
- kv for kv in self .variables .items () if kv [ 0 ] not in self .dims
143
- )
144
- variables = merge_coords_for_inplace_math (
145
- [self . variables , other . variables ], priority_vars = priority_vars
135
+ # don't include indexes in prioritized , because we didn't align
136
+ # first and we want indexes to be checked
137
+ prioritized = {
138
+ k : ( v , None ) for k , v in self .variables .items () if k not in self .indexes
139
+ }
140
+ variables , indexes = merge_coordinates_without_align (
141
+ [self , other ], prioritized
146
142
)
147
143
yield
148
- self ._update_coords (variables )
144
+ self ._update_coords (variables , indexes )
149
145
150
- def merge (self , other : "AbstractCoordinates " ) -> "Dataset" :
146
+ def merge (self , other : "Coordinates " ) -> "Dataset" :
151
147
"""Merge two sets of coordinates to create a new Dataset
152
148
153
149
The method implements the logic used for joining coordinates in the
@@ -173,13 +169,19 @@ def merge(self, other: "AbstractCoordinates") -> "Dataset":
173
169
174
170
if other is None :
175
171
return self .to_dataset ()
176
- else :
177
- other_vars = getattr (other , "variables" , other )
178
- coords = expand_and_merge_variables ([self .variables , other_vars ])
179
- return Dataset ._from_vars_and_coord_names (coords , set (coords ))
172
+
173
+ if not isinstance (other , Coordinates ):
174
+ other = Dataset (coords = other ).coords
175
+
176
+ coords , indexes = merge_coordinates_without_align ([self , other ])
177
+ coord_names = set (coords )
178
+ merged = Dataset ._construct_direct (
179
+ variables = coords , coord_names = coord_names , indexes = indexes
180
+ )
181
+ return merged
180
182
181
183
182
- class DatasetCoordinates (AbstractCoordinates ):
184
+ class DatasetCoordinates (Coordinates ):
183
185
"""Dictionary like container for Dataset coordinates.
184
186
185
187
Essentially an immutable OrderedDict with keys given by the array's
@@ -218,7 +220,11 @@ def to_dataset(self) -> "Dataset":
218
220
"""
219
221
return self ._data ._copy_listed (self ._names )
220
222
221
- def _update_coords (self , coords : Mapping [Hashable , Any ]) -> None :
223
+ def _update_coords (
224
+ self ,
225
+ coords : "OrderedDict[Hashable, Variable]" ,
226
+ indexes : Mapping [Hashable , pd .Index ],
227
+ ) -> None :
222
228
from .dataset import calculate_dimensions
223
229
224
230
variables = self ._data ._variables .copy ()
@@ -234,7 +240,12 @@ def _update_coords(self, coords: Mapping[Hashable, Any]) -> None:
234
240
self ._data ._variables = variables
235
241
self ._data ._coord_names .update (new_coord_names )
236
242
self ._data ._dims = dims
237
- self ._data ._indexes = None
243
+
244
+ # TODO(shoyer): once ._indexes is always populated by a dict, modify
245
+ # it to update inplace instead.
246
+ original_indexes = OrderedDict (self ._data .indexes )
247
+ original_indexes .update (indexes )
248
+ self ._data ._indexes = original_indexes
238
249
239
250
def __delitem__ (self , key : Hashable ) -> None :
240
251
if key in self :
@@ -251,7 +262,7 @@ def _ipython_key_completions_(self):
251
262
]
252
263
253
264
254
- class DataArrayCoordinates (AbstractCoordinates ):
265
+ class DataArrayCoordinates (Coordinates ):
255
266
"""Dictionary like container for DataArray coordinates.
256
267
257
268
Essentially an OrderedDict with keys given by the array's
@@ -274,7 +285,11 @@ def _names(self) -> Set[Hashable]:
274
285
def __getitem__ (self , key : Hashable ) -> "DataArray" :
275
286
return self ._data ._getitem_coord (key )
276
287
277
- def _update_coords (self , coords ) -> None :
288
+ def _update_coords (
289
+ self ,
290
+ coords : "OrderedDict[Hashable, Variable]" ,
291
+ indexes : Mapping [Hashable , pd .Index ],
292
+ ) -> None :
278
293
from .dataset import calculate_dimensions
279
294
280
295
coords_plus_data = coords .copy ()
@@ -285,7 +300,12 @@ def _update_coords(self, coords) -> None:
285
300
"cannot add coordinates with new dimensions to " "a DataArray"
286
301
)
287
302
self ._data ._coords = coords
288
- self ._data ._indexes = None
303
+
304
+ # TODO(shoyer): once ._indexes is always populated by a dict, modify
305
+ # it to update inplace instead.
306
+ original_indexes = OrderedDict (self ._data .indexes )
307
+ original_indexes .update (indexes )
308
+ self ._data ._indexes = original_indexes
289
309
290
310
@property
291
311
def variables (self ):
0 commit comments