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

Add a data setter #795

Merged
merged 5 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/795.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
It is now possible to set the ``NDCube.data`` property of a cube with an array of the same shape and unit as the current cube.
36 changes: 36 additions & 0 deletions ndcube/ndcube.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,42 @@
global_coords = deepcopy(global_coords)
self._global_coords = global_coords

@property
def data(self):
"""
`~numpy.ndarray`-like : The stored dataset.

Notes
-----
It is possible to set the ``.data`` attribute on a `NDCube` with an
array-like object of the same shape. However, this is really only
intended for replacing the data with a different object representing
the same physical data as no other properties of the cube will be
changed, such as uncertainty or unit.
"""
return super().data

@data.setter
def data(self, value):
# In an array-agnostic way check the shape is the same
if not hasattr(value, "shape") or value.shape != self.data.shape:
raise TypeError(f"Can only set data with an array-like object of the same shape ({self.data.shape})")

Check warning on line 421 in ndcube/ndcube.py

View check run for this annotation

Codecov / codecov/patch

ndcube/ndcube.py#L420-L421

Added lines #L420 - L421 were not covered by tests

# Other masked arrays are hard to detect reliably
Cadair marked this conversation as resolved.
Show resolved Hide resolved
if isinstance(value, np.ma.MaskedArray):
Cadair marked this conversation as resolved.
Show resolved Hide resolved
raise TypeError("Can not set the .data attribute with a numpy masked array, please set .data and .mask separately.")

Check warning on line 425 in ndcube/ndcube.py

View check run for this annotation

Codecov / codecov/patch

ndcube/ndcube.py#L424-L425

Added lines #L424 - L425 were not covered by tests

if isinstance(value, u.Quantity):
unit_error = f"Unable to set data with unit {value.unit} as it incompatible with the current unit of {self.unit}"
if self.unit is None:
raise u.UnitsError(unit_error)
try:
value = value.to_value(self.unit)
except u.UnitsError as exc:
raise u.UnitsError(unit_error) from exc

Check warning on line 434 in ndcube/ndcube.py

View check run for this annotation

Codecov / codecov/patch

ndcube/ndcube.py#L427-L434

Added lines #L427 - L434 were not covered by tests

self._data = value

Check warning on line 436 in ndcube/ndcube.py

View check run for this annotation

Codecov / codecov/patch

ndcube/ndcube.py#L436

Added line #L436 was not covered by tests

@property
def extra_coords(self):
# Docstring in NDCubeABC.
Expand Down
61 changes: 61 additions & 0 deletions ndcube/tests/test_ndcube.py
Original file line number Diff line number Diff line change
Expand Up @@ -1238,3 +1238,64 @@
cube = ndcube_2d_ln_lt_units
expected = u.Quantity(cube.data, cube.unit)
np.testing.assert_array_equal(cube.quantity, expected)


def test_data_setter(ndcube_4d_ln_l_t_lt):
cube = ndcube_4d_ln_l_t_lt
assert isinstance(cube.data, np.ndarray)

Check warning on line 1245 in ndcube/tests/test_ndcube.py

View check run for this annotation

Codecov / codecov/patch

ndcube/tests/test_ndcube.py#L1244-L1245

Added lines #L1244 - L1245 were not covered by tests

new_data = np.zeros_like(cube.data)
cube.data = new_data
assert cube.data is new_data

Check warning on line 1249 in ndcube/tests/test_ndcube.py

View check run for this annotation

Codecov / codecov/patch

ndcube/tests/test_ndcube.py#L1247-L1249

Added lines #L1247 - L1249 were not covered by tests

dask_array = dask.array.zeros_like(cube.data)
cube.data = dask_array
assert cube.data is dask_array

Check warning on line 1253 in ndcube/tests/test_ndcube.py

View check run for this annotation

Codecov / codecov/patch

ndcube/tests/test_ndcube.py#L1251-L1253

Added lines #L1251 - L1253 were not covered by tests


def test_invalid_data_setter(ndcube_4d_ln_l_t_lt):
cube = ndcube_4d_ln_l_t_lt

Check warning on line 1257 in ndcube/tests/test_ndcube.py

View check run for this annotation

Codecov / codecov/patch

ndcube/tests/test_ndcube.py#L1257

Added line #L1257 was not covered by tests

with pytest.raises(TypeError, match="set data with an array-like"):
cube.data = None

Check warning on line 1260 in ndcube/tests/test_ndcube.py

View check run for this annotation

Codecov / codecov/patch

ndcube/tests/test_ndcube.py#L1259-L1260

Added lines #L1259 - L1260 were not covered by tests

with pytest.raises(TypeError, match="set data with an array-like"):
cube.data = np.zeros((100,100))

Check warning on line 1263 in ndcube/tests/test_ndcube.py

View check run for this annotation

Codecov / codecov/patch

ndcube/tests/test_ndcube.py#L1262-L1263

Added lines #L1262 - L1263 were not covered by tests

with pytest.raises(TypeError, match="set data with an array-like"):
cube.data = 10

Check warning on line 1266 in ndcube/tests/test_ndcube.py

View check run for this annotation

Codecov / codecov/patch

ndcube/tests/test_ndcube.py#L1265-L1266

Added lines #L1265 - L1266 were not covered by tests


def test_quantity_data_setter(ndcube_2d_ln_lt_units):
cube = ndcube_2d_ln_lt_units
assert cube.unit

Check warning on line 1271 in ndcube/tests/test_ndcube.py

View check run for this annotation

Codecov / codecov/patch

ndcube/tests/test_ndcube.py#L1270-L1271

Added lines #L1270 - L1271 were not covered by tests

new_data = np.zeros_like(cube.data) * cube.unit
cube.data = new_data

Check warning on line 1274 in ndcube/tests/test_ndcube.py

View check run for this annotation

Codecov / codecov/patch

ndcube/tests/test_ndcube.py#L1273-L1274

Added lines #L1273 - L1274 were not covered by tests

assert isinstance(cube.data, np.ndarray)

Check warning on line 1276 in ndcube/tests/test_ndcube.py

View check run for this annotation

Codecov / codecov/patch

ndcube/tests/test_ndcube.py#L1276

Added line #L1276 was not covered by tests
Cadair marked this conversation as resolved.
Show resolved Hide resolved

new_data = np.zeros_like(cube.data) * u.Jy
with pytest.raises(u.UnitsError, match=f"Unable to set data with unit {u.Jy}"):
cube.data = new_data

Check warning on line 1280 in ndcube/tests/test_ndcube.py

View check run for this annotation

Codecov / codecov/patch

ndcube/tests/test_ndcube.py#L1278-L1280

Added lines #L1278 - L1280 were not covered by tests


def test_quantity_no_unit_data_setter(ndcube_4d_ln_l_t_lt):
cube = ndcube_4d_ln_l_t_lt

Check warning on line 1284 in ndcube/tests/test_ndcube.py

View check run for this annotation

Codecov / codecov/patch

ndcube/tests/test_ndcube.py#L1284

Added line #L1284 was not covered by tests

new_data = np.zeros_like(cube.data) * u.Jy
with pytest.raises(u.UnitsError, match=f"Unable to set data with unit {u.Jy}.* current unit of None"):
cube.data = new_data

Check warning on line 1288 in ndcube/tests/test_ndcube.py

View check run for this annotation

Codecov / codecov/patch

ndcube/tests/test_ndcube.py#L1286-L1288

Added lines #L1286 - L1288 were not covered by tests


def test_set_data_mask(ndcube_4d_mask):
cube = ndcube_4d_mask

Check warning on line 1292 in ndcube/tests/test_ndcube.py

View check run for this annotation

Codecov / codecov/patch

ndcube/tests/test_ndcube.py#L1292

Added line #L1292 was not covered by tests

assert isinstance(cube.mask, np.ndarray)

Check warning on line 1294 in ndcube/tests/test_ndcube.py

View check run for this annotation

Codecov / codecov/patch

ndcube/tests/test_ndcube.py#L1294

Added line #L1294 was not covered by tests

new_data = np.ones_like(cube.data)
new_mask = np.zeros_like(cube.mask)
masked_array = np.ma.MaskedArray(new_data, new_mask)

Check warning on line 1298 in ndcube/tests/test_ndcube.py

View check run for this annotation

Codecov / codecov/patch

ndcube/tests/test_ndcube.py#L1296-L1298

Added lines #L1296 - L1298 were not covered by tests

with pytest.raises(TypeError, match="Can not set the .data .* with a numpy masked array"):
cube.data = masked_array

Check warning on line 1301 in ndcube/tests/test_ndcube.py

View check run for this annotation

Codecov / codecov/patch

ndcube/tests/test_ndcube.py#L1300-L1301

Added lines #L1300 - L1301 were not covered by tests
Loading