Skip to content
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

Better docs and errors about expand_dims() view #3114

Merged
merged 12 commits into from
Jul 14, 2019
3 changes: 3 additions & 0 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ Enhancements
Bug fixes
~~~~~~~~~

- Improved error handling and documentation for `.expand_dims()`
read-only view.

.. _whats-new.0.12.3:

v0.12.3 (10 July 2019)
Expand Down
4 changes: 3 additions & 1 deletion xarray/core/dataarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -1272,7 +1272,9 @@ def expand_dims(self, dim: Union[None, Hashable, Sequence[Hashable],
Mapping[Hashable, Any]] = None,
axis=None, **dim_kwargs: Any) -> 'DataArray':
"""Return a new object with an additional axis (or axes) inserted at
the corresponding position in the array shape.
the corresponding position in the array shape. The new object is a
view into the underlying array, not a copy.


If dim is already a scalar coordinate, it will be promoted to a 1D
coordinate consisting of a single value.
Expand Down
3 changes: 2 additions & 1 deletion xarray/core/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -2516,7 +2516,8 @@ def swap_dims(self, dims_dict, inplace=None):

def expand_dims(self, dim=None, axis=None, **dim_kwargs):
"""Return a new object with an additional axis (or axes) inserted at
the corresponding position in the array shape.
the corresponding position in the array shape. The new object is a
view into the underlying array, not a copy.

If dim is already a scalar coordinate, it will be promoted to a 1D
coordinate consisting of a single value.
Expand Down
10 changes: 9 additions & 1 deletion xarray/core/indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1177,7 +1177,15 @@ def __getitem__(self, key):

def __setitem__(self, key, value):
array, key = self._indexing_array_and_key(key)
array[key] = value
try:
array[key] = value
except ValueError:
# More informative exception if read-only view
if not array.flags.writeable and not array.flags.owndata:
raise ValueError("Assignment destination is a view. "
"Do you want to .copy() array first?")
else:
raise


class DaskIndexingAdapter(ExplicitlyIndexedNDArrayMixin):
Expand Down
10 changes: 10 additions & 0 deletions xarray/tests/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,16 @@ def test_indexer(data, x, expected_pos, expected_idx=None):
[True, True, True, True, False, False, False, False],
pd.MultiIndex.from_product([[1, 2], [-1, -2]]))

def test_read_only_view(self):
from collections import OrderedDict
arr = DataArray(np.random.rand(3, 3),
coords={'x': np.arange(3), 'y': np.arange(3)},
dims=('x', 'y')) # Create a 2D DataArray
arr = arr.expand_dims(OrderedDict([('z', 3)]), -1) # New dimension 'z'
arr['z'] = np.arange(3) # New coords to dimension 'z'
with pytest.raises(ValueError, match='Do you want to .copy()'):
arr.loc[0, 0, 0] = 999
DavidMertz marked this conversation as resolved.
Show resolved Hide resolved


class TestLazyArray:
def test_slice_slice(self):
Expand Down