Skip to content

Commit

Permalink
Merge branch 'main' into fix_axis_world_coords
Browse files Browse the repository at this point in the history
  • Loading branch information
nabobalis authored Oct 23, 2024
2 parents 67e4ec0 + da6007e commit 63af46f
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 25 deletions.
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 @@ def celestial_wcs(request):
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 @@ def test_celestial_spectral_ape14(spectral_wcs, celestial_wcs):
# 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 @@ def test_celestial_spectral_ape14(spectral_wcs, celestial_wcs):
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 @@ def test_shared_pixel_axis_compound_3d(spectral_cube_3d_fitswcs, time_1d_fitswcs
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))
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

0 comments on commit 63af46f

Please sign in to comment.