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 support for astropy 7 #772

Merged
merged 2 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all 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/772.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix support for astropy 7.0, this involved a change to ``CompoundLowLevelWCS`` so that in handles ``pixel_bounds`` if only one component WCS sets a pixel bound.
2 changes: 1 addition & 1 deletion ndcube/extra_coords/tests/test_lookup_table_coord.py
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ def test_mtc_dropped_table_skycoord_join(lut_1d_time, lut_2d_skycoord_mesh):
assert all(isinstance(u, str) for u in dwd["world_axis_units"])
assert dwd["world_axis_units"] == ["deg", "deg"]
assert dwd["world_axis_physical_types"] == ["pos.eq.ra", "pos.eq.dec"]
assert dwd["world_axis_object_components"] == [("celestial", 0, "spherical.lon"), ("celestial", 1, "spherical.lat")]
assert [c[:2] for c in dwd["world_axis_object_components"]] == [("celestial", 0), ("celestial", 1)]
assert wao_classes["celestial"][0] is SkyCoord
assert dwd["value"] == [0*u.deg, 0*u.deg]

Expand Down
11 changes: 6 additions & 5 deletions ndcube/wcs/wrappers/compound_wcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,12 @@ def pixel_to_world_values(self, *pixel_arrays):
world_arrays = []
for w in self._wcs:
pixel_arrays_sub = pixel_arrays[:w.pixel_n_dim]
pixel_arrays = pixel_arrays[w.pixel_n_dim:]
world_arrays_sub = w.pixel_to_world_values(*pixel_arrays_sub)
if w.world_n_dim > 1:
world_arrays.extend(world_arrays_sub)
else:
world_arrays.append(world_arrays_sub)
pixel_arrays = pixel_arrays[w.pixel_n_dim:]
return tuple(world_arrays)

def world_to_pixel_values(self, *world_arrays):
Expand Down Expand Up @@ -174,14 +174,15 @@ def pixel_shape(self):

@property
def pixel_bounds(self):
if not any(w.pixel_bounds is None for w in self._wcs):
pixel_bounds = tuplesum(w.pixel_bounds for w in self._wcs)
if any(w.pixel_bounds is not None for w in self._wcs):
pixel_bounds = tuplesum(w.pixel_bounds or [tuple() for _ in range(w.pixel_n_dim)] for w in self._wcs)
out_bounds = self.mapping.inverse(*pixel_bounds)
for i, ix in enumerate(self.mapping.mapping):
if out_bounds[ix] != pixel_bounds[i]:
if pixel_bounds[i] and (out_bounds[ix] != pixel_bounds[i]):
raise ValueError(
"The pixel bounds of the supplied WCSes do not match for the dimensions shared by the supplied mapping.")
return out_bounds
iint = np.iinfo(int)
return tuple(o or (iint.min, iint.max) for o in out_bounds)

@property
def pixel_axis_names(self):
Expand Down
21 changes: 21 additions & 0 deletions ndcube/wcs/wrappers/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1 +1,22 @@
import pytest

from astropy.wcs.wcsapi.conftest import Celestial2DLowLevelWCS as ApyCelestial2DLowLevelWCS
from astropy.wcs.wcsapi.conftest import * # NOQA


class Celestial2DLowLevelWCS(ApyCelestial2DLowLevelWCS):
def __init__(self):
self._pixel_bounds = (-1, 5), (1, 7)

@property
def pixel_bounds(self):
return self._pixel_bounds

@pixel_bounds.setter
def pixel_bounds(self, val):
self._pixel_bounds = val


@pytest.fixture
def celestial_2d_ape14_wcs():
return Celestial2DLowLevelWCS()
34 changes: 22 additions & 12 deletions ndcube/wcs/wrappers/tests/test_compound_wcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
import pytest
from numpy.testing import assert_allclose, assert_equal

from astropy import units as u
import astropy
import astropy.units as u
from astropy.coordinates import SkyCoord
from astropy.tests.helper import assert_quantity_allclose
from astropy.units import Quantity
Expand All @@ -31,7 +32,7 @@
Array shape (Numpy order): (7, 6, 3)

Pixel Dim Axis Name Data size Bounds
0 None 3 (1, 2)
0 None 3 (1, 3)
1 None 6 (-1, 5)
2 None 7 (1, 7)

Expand Down Expand Up @@ -73,20 +74,28 @@
# If any of the individual shapes are None, return None overall
assert wcs.pixel_shape is None
assert wcs.array_shape is None
assert wcs.pixel_bounds is None
assert wcs.pixel_bounds == ((np.iinfo(int).min, np.iinfo(int).max), (-1, 5), (1, 7))

# Set the shape and bounds on the spectrum and test again
spectral_wcs.pixel_shape = (3,)
spectral_wcs.pixel_bounds = [(1, 2)]
spectral_wcs.pixel_bounds = [(1, 3)]
assert wcs.pixel_shape == (3, 6, 7)
assert wcs.array_shape == (7, 6, 3)
assert wcs.pixel_bounds == ((1, 2), (-1, 5), (1, 7))
assert wcs.pixel_bounds == ((1, 3), (-1, 5), (1, 7))

pixel_scalar = (2.3, 4.3, 1.3)
world_scalar = (-1.91e10, 5.4, -9.4)
assert_allclose(wcs.pixel_to_world_values(*pixel_scalar), world_scalar)
assert_allclose(wcs.array_index_to_world_values(*pixel_scalar[::-1]), world_scalar)
assert_allclose(wcs.world_to_pixel_values(*world_scalar), pixel_scalar)
assert_allclose(wcs.world_to_pixel_values(*world_scalar), pixel_scalar, equal_nan=True)

assert str(wcs) == EXPECTED_CELESTIAL_SPECTRAL_APE14_REPR
assert EXPECTED_CELESTIAL_SPECTRAL_APE14_REPR in repr(wcs)

# Not going to test too many things with out of bounds inputs
spectral_wcs.pixel_bounds = None
celestial_wcs.pixel_bounds = None
assert wcs.pixel_bounds is None
assert_allclose(wcs.world_to_array_index_values(*world_scalar), [1, 4, 2])

pixel_array = (np.array([2.3, 2.4]),
Expand Down Expand Up @@ -117,9 +126,6 @@
assert_quantity_allclose(celestial.ra, world_array[1] * u.deg)
assert_quantity_allclose(celestial.dec, world_array[2] * u.deg)

assert str(wcs) == EXPECTED_CELESTIAL_SPECTRAL_APE14_REPR
assert EXPECTED_CELESTIAL_SPECTRAL_APE14_REPR in repr(wcs)


def test_shared_pixel_axis_compound_1d(spectral_1d_fitswcs, time_1d_fitswcs):

Expand Down Expand Up @@ -158,16 +164,20 @@
assert wcs.pixel_n_dim == 3
np.testing.assert_allclose(wcs.pixel_shape, (10, 20, 30))
assert wcs.pixel_axis_names == ('', '', '')
assert wcs.pixel_bounds is None
assert wcs.pixel_bounds == ((-1, 5), (1, 7), (1, 2.5))

np.testing.assert_allclose(wcs.axis_correlation_matrix, [[True, True, False],
[True, True, False],
[False, False, True],
[False, True, False]])

world = wcs.pixel_to_world_values(0, 0, 0)
np.testing.assert_allclose(world, (14, -12, -2.6e+10, -7.0))
np.testing.assert_allclose(wcs.world_to_pixel_values(*world), (0, 0, 0))
if astropy.__version__ >= "7.0.0.dev":
np.testing.assert_allclose(world, (14, np.nan, np.nan, -7.0))
np.testing.assert_allclose(wcs.world_to_pixel_values(*world), (0, np.nan, np.nan))

Check warning on line 177 in ndcube/wcs/wrappers/tests/test_compound_wcs.py

View check run for this annotation

Codecov / codecov/patch

ndcube/wcs/wrappers/tests/test_compound_wcs.py#L176-L177

Added lines #L176 - L177 were not covered by tests
else:
np.testing.assert_allclose(world, (14, -12, -2.6e+10, -7.0))
np.testing.assert_allclose(wcs.world_to_pixel_values(*world), (0, 0, 0))

with pytest.raises(ValueError):
wcs.world_to_pixel_values((14, -12, -2.6e+10, -6.0))
Expand Down
17 changes: 10 additions & 7 deletions ndcube/wcs/wrappers/tests/test_resampled_wcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,18 @@ def test_2d(celestial_wcs):
assert_allclose(wcs.array_shape, (7/3, 15))
assert_allclose(wcs.pixel_bounds, ((-2.5, 12.5), (1/3, 7/3)))

pixel_scalar = (2.3, 4.3)
world_scalar = (12.16, 13.8)
pixel_scalar = (2.3, 1.2)
world_scalar = (12.16, -4.8)
assert_allclose(wcs.pixel_to_world_values(*pixel_scalar), world_scalar)
assert_allclose(wcs.array_index_to_world_values(*pixel_scalar[::-1]), world_scalar)
assert_allclose(wcs.world_to_pixel_values(*world_scalar), pixel_scalar)
assert_allclose(wcs.world_to_array_index_values(*world_scalar), [4, 2])
assert_allclose(wcs.world_to_array_index_values(*world_scalar), [1, 2])

EXPECTED_2D_REPR = EXPECTED_2D_REPR_NUMPY2 if np.__version__ >= '2.0.0' else EXPECTED_2D_REPR_NUMPY1
assert str(wcs) == EXPECTED_2D_REPR
assert EXPECTED_2D_REPR in repr(wcs)

celestial_wcs.pixel_bounds = None
pixel_array = (np.array([2.3, 2.4]),
np.array([4.3, 4.4]))
world_array = (np.array([12.16, 12.08]),
Expand All @@ -115,16 +120,13 @@ def test_2d(celestial_wcs):
assert_quantity_allclose(celestial.ra, world_array[0] * u.deg)
assert_quantity_allclose(celestial.dec, world_array[1] * u.deg)

EXPECTED_2D_REPR = EXPECTED_2D_REPR_NUMPY2 if np.__version__ >= '2.0.0' else EXPECTED_2D_REPR_NUMPY1
assert str(wcs) == EXPECTED_2D_REPR
assert EXPECTED_2D_REPR in repr(wcs)


@pytest.mark.parametrize('celestial_wcs',
['celestial_2d_ape14_wcs', 'celestial_2d_fitswcs'],
indirect=True)
def test_scalar_factor(celestial_wcs):

celestial_wcs.pixel_bounds = None
wcs = ResampledLowLevelWCS(celestial_wcs, 2)

pixel_scalar = (2.3, 4.3)
Expand All @@ -139,6 +141,7 @@ def test_scalar_factor(celestial_wcs):
['celestial_2d_ape14_wcs', 'celestial_2d_fitswcs'],
indirect=True)
def test_offset(celestial_wcs):
celestial_wcs.pixel_bounds = None
offset = 1
factor = 2
wcs = ResampledLowLevelWCS(celestial_wcs, factor, offset=offset)
Expand Down