-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Fix in vectorized item assignment #1746
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
9eafe36
2aff4ce
22c1295
dc135cd
b1dd0f0
c74c828
8e6e2e0
aef3d56
f10ecf4
d482f80
c2b5ac3
84e5e6f
2011140
6906eeb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -484,7 +484,9 @@ def __setitem__(self, key, value): | |
if isinstance(key, basestring): | ||
self.coords[key] = value | ||
else: | ||
# xarray-style array indexing | ||
# DataArray key -> Variable key | ||
key = {k: v.variable if isinstance(v, DataArray) else v | ||
for k, v in self._item_key_to_dict(key).items()} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to check that coordinates are consistent on the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is done a few lines above, But I am wondering this unnecessary indexing, though I think this implementation is the simplest. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm. This could indeed be a significant performance hit. That said, I'm OK leaving this for now, with a TODO note to optimize it later. |
||
self.variable[key] = value | ||
|
||
def __delitem__(self, key): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -637,17 +637,22 @@ def __setitem__(self, key, value): | |
""" | ||
dims, index_tuple, new_order = self._broadcast_indexes(key) | ||
|
||
if isinstance(value, Variable): | ||
value = value.set_dims(dims).data | ||
|
||
if new_order: | ||
value = duck_array_ops.asarray(value) | ||
if not isinstance(value, Variable): | ||
value = as_compatible_data(value) | ||
if value.ndim > len(dims): | ||
raise ValueError( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we still need this special case error message now that we call set_dims below? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think |
||
'shape mismatch: value array of shape %s could not be' | ||
'broadcast to indexing result with %s dimensions' | ||
% (value.shape, len(dims))) | ||
if value.ndim == 0: | ||
value = Variable((), value) | ||
else: | ||
value = Variable(dims[-value.ndim:], value) | ||
# broadcast to become assignable | ||
value = value.set_dims(dims).data | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I decided to revert |
||
|
||
if new_order: | ||
value = duck_array_ops.asarray(value) | ||
value = value[(len(dims) - value.ndim) * (np.newaxis,) + | ||
(Ellipsis,)] | ||
value = np.moveaxis(value, new_order, range(len(new_order))) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -526,6 +526,36 @@ def test_setitem(self): | |
expected[t] = 1 | ||
self.assertArrayEqual(orig.values, expected) | ||
|
||
def test_setitem_fancy(self): | ||
# vectorized indexing | ||
da = DataArray(np.ones((3, 2)), dims=['x', 'y']) | ||
ind = Variable(['a'], [0, 1]) | ||
da[dict(x=ind, y=ind)] = 0 | ||
expected = DataArray([[0, 1], [1, 0], [1, 1]], dims=['x', 'y']) | ||
self.assertDataArrayIdentical(expected, da) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the future (no need to change this time), you can use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I always forget this, maybe because I usually make tests based on the existing ones... |
||
# assign another 0d-variable | ||
da[dict(x=ind, y=ind)] = Variable((), 0) | ||
expected = DataArray([[0, 1], [1, 0], [1, 1]], dims=['x', 'y']) | ||
self.assertDataArrayIdentical(expected, da) | ||
# assign another 1d-variable | ||
da[dict(x=ind, y=ind)] = Variable(['a'], [2, 3]) | ||
expected = DataArray([[2, 1], [1, 3], [1, 1]], dims=['x', 'y']) | ||
self.assertVariableIdentical(expected, da) | ||
|
||
# 2d-vectorized indexing | ||
da = DataArray(np.ones((3, 2)), dims=['x', 'y']) | ||
ind_x = DataArray([[0, 1]], dims=['a', 'b']) | ||
ind_y = DataArray([[1, 0]], dims=['a', 'b']) | ||
da[dict(x=ind_x, y=ind_y)] = 0 | ||
expected = DataArray([[1, 0], [0, 1], [1, 1]], dims=['x', 'y']) | ||
self.assertVariableIdentical(expected, da) | ||
|
||
da = DataArray(np.ones((3, 2)), dims=['x', 'y']) | ||
ind = Variable(['a'], [0, 1]) | ||
da[ind] = 0 | ||
expected = DataArray([[0, 0], [0, 0], [1, 1]], dims=['x', 'y']) | ||
self.assertVariableIdentical(expected, da) | ||
|
||
def test_contains(self): | ||
data_array = DataArray(1, coords={'x': 2}) | ||
with pytest.warns(FutureWarning): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to enforce consistency for coordinates here? My inclination would be that we should support exactly the same keys in setitem as are valid in getitem. Ideally we should also reuse the same code. That means we should raise errors if there are multiple indexers with inconsistent alignment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reasonable. I will add a validation.