Skip to content

Commit

Permalink
Merge pull request #729 from sunpy/numpy
Browse files Browse the repository at this point in the history
Add tests for numpy dev and update for numpy 2

(cherry picked from commit e7a0e20)
  • Loading branch information
Cadair authored and nabobalis committed Jun 18, 2024
1 parent 46386d5 commit 8d58fdc
Show file tree
Hide file tree
Showing 9 changed files with 41 additions and 57 deletions.
1 change: 1 addition & 0 deletions changelog/729.trivial.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added explicit support for numpy 2.0.
4 changes: 1 addition & 3 deletions docs/explaining_ndcube/coordinates.rst
Original file line number Diff line number Diff line change
Expand Up @@ -312,9 +312,7 @@ The values of dropped coordinates at the position where the `~ndcube.NDCube` was
>>> my_2d_cube = my_cube[:, :, 0]
>>> my_2d_cube.array_axis_physical_types # Note the wavelength axis is now gone.
[('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon', 'time'),
('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon')]
[('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon', 'time'), ('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon')]
>>> # The wavelength value at the slicing location is now in the GLobalCoords object.
>>> list(my_2d_cube.global_coords.keys())
['distance', 'em.wl']
Expand Down
16 changes: 4 additions & 12 deletions docs/explaining_ndcube/data_classes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,7 @@ Dimensions and Physical Types
>>> my_cube.dimensions
<Quantity [4., 4., 5.] pix>
>>> my_cube.array_axis_physical_types
[('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'),
('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'),
('em.wl',)]
[('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'), ('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'), ('em.wl',)]
`~ndcube.NDCube.dimensions` returns a `~astropy.units.Quantity` in pixel units giving the length of each dimension in the `~ndcube.NDCube`.
`~ndcube.NDCube.array_axis_physical_types` returns tuples of strings denoting the types of physical properties represented by each array axis.
Expand Down Expand Up @@ -154,9 +152,7 @@ This returns an `~ndcube.NDCubeSequence` where the sequence axis acts as the wav
>>> exploded.dimensions
(<Quantity 5. pix>, <Quantity 4. pix>, <Quantity 4. pix>)
>>> exploded.array_axis_physical_types
[('meta.obs.sequence',),
('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'),
('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon')]
[('meta.obs.sequence',), ('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'), ('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon')]
To learn more about this object, read the :ref:`ndcubesequence` section below.

Expand Down Expand Up @@ -294,18 +290,14 @@ To call, simply do:
.. code-block:: python
>>> my_sequence.array_axis_physical_types
[('meta.obs.sequence',),
('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'), ('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'),
('em.wl',)]
[('meta.obs.sequence',), ('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'), ('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'), ('em.wl',)]
Once again, we can see the physical types associated with each axis in the cube-like paradigm be calling `ndcube.NDCubeSequence.cube_like_array_axis_physical_types`.

.. code-block:: python
>>> my_sequence.cube_like_array_axis_physical_types
[('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'),
('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'),
('em.wl',)]
[('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'), ('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'), ('em.wl',)]
.. _explode_sequence:

Expand Down
20 changes: 5 additions & 15 deletions docs/explaining_ndcube/slicing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,7 @@ If we want our region of interest to only apply to a single sub-cube, and we ind
>>> single_cube_roi.dimensions
<Quantity [2., 3.] pix>
>>> single_cube_roi.array_axis_physical_types
[('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'),
('em.wl',)]
[('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'), ('em.wl',)]
However, as with numpy slicing, we can induce the slicing operation to return an `~ndcube.NDCubeSequence` by supplying a length-1 `slice` to the sequence axis, rather than an `int`.
This sequence will still represent the same region of interest from the same single sub-cube, but the sequence axis will have a length of 1, rather than be removed.
Expand All @@ -237,9 +236,7 @@ This sequence will still represent the same region of interest from the same sin
>>> roi_length1_sequence.dimensions
(<Quantity 1. pix>, <Quantity 2. pix>, <Quantity 3. pix>)
>>> roi_length1_sequence.array_axis_physical_types
[('meta.obs.sequence',),
('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'),
('em.wl',)]
[('meta.obs.sequence',), ('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'), ('em.wl',)]
Cube-like Slicing
-----------------
Expand Down Expand Up @@ -269,8 +266,7 @@ This can be achieved by entering:
>>> single_cube_roi.dimensions
<Quantity [2., 3.] pix>
>>> single_cube_roi.array_axis_physical_types
[('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'),
('em.wl',)]
[('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'), ('em.wl',)]
This returns the same `~ndcube.NDCube` as above.
However, also as above, we can induce the return type to be an `~ndcube.NDCubeSequence` by supplying a length-1 `slice`.
Expand All @@ -282,10 +278,7 @@ As before, the same region of interest from the same sub-cube is represented, ju
>>> roi_length1_sequence.dimensions
(<Quantity 1. pix>, <Quantity 1. pix>, <Quantity 2. pix>, <Quantity 3. pix>)
>>> roi_length1_sequence.array_axis_physical_types
[('meta.obs.sequence',),
('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'),
('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'),
('em.wl',)]
[('meta.obs.sequence',), ('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'), ('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'), ('em.wl',)]
In the case the entire region came from a single sub-cube.
However, `~ndcube.NDCubeSequence.index_as_cube` also works when the region of interest spans multiple sub-cubes in the sequence.
Expand All @@ -301,10 +294,7 @@ In cube-like indexing this corresponds to slices 3 to 9 along to their 1st cube
<Quantity 2. pix>,
<Quantity 3. pix>)
>>> roi_across_cubes.array_axis_physical_types
[('meta.obs.sequence',),
('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'),
('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'),
('em.wl',)]
[('meta.obs.sequence',), ('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'), ('custom:pos.helioprojective.lat', 'custom:pos.helioprojective.lon'), ('em.wl',)]
Notice that since the sub-cubes are now of different lengths along the common axis, the corresponding `~astropy.units.Quantity` gives the
lengths of each cube individually.
Expand Down
2 changes: 1 addition & 1 deletion ndcube/ndcube.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ def array_axis_physical_types(self):
wcs = self.combined_wcs
world_axis_physical_types = np.array(wcs.world_axis_physical_types)
axis_correlation_matrix = wcs.axis_correlation_matrix
return [tuple(world_axis_physical_types[axis_correlation_matrix[:, i]])
return [tuple(world_axis_physical_types[axis_correlation_matrix[:, i]].tolist())
for i in range(axis_correlation_matrix.shape[1])][::-1]

def _generate_world_coords(self, pixel_corners, wcs):
Expand Down
3 changes: 2 additions & 1 deletion ndcube/utils/cube.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,8 @@ def propagate_rebin_uncertainties(uncertainty, data, mask, operation, operation_
if not propagation_operation:
if operation in {np.sum, np.nansum, np.mean, np.nanmean}:
propagation_operation = np.add
elif operation in {np.prod, np.nanprod, np.product}:
# TODO: product was renamed to prod for numpy 2.0
elif operation in {np.prod, np.nanprod, np.product if hasattr(np, "product") else np.prod}:
propagation_operation = np.multiply
else:
raise ValueError("propagation_operation not recognized.")
Expand Down
26 changes: 24 additions & 2 deletions ndcube/wcs/wrappers/tests/test_resampled_wcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,29 @@ def celestial_wcs(request):
return request.getfixturevalue(request.param)


EXPECTED_2D_REPR = """
EXPECTED_2D_REPR_NUMPY2 = """
ResampledLowLevelWCS Transformation
This transformation has 2 pixel and 2 world dimensions
Array shape (Numpy order): (np.float64(2.3333333333333335), np.float64(15.0))
Pixel Dim Axis Name Data size Bounds
0 None 15 (np.float64(-2.5), np.float64(12.5))
1 None 2.33333 (np.float64(0.3333333333333333), np.float64(2.3333333333333335))
World Dim Axis Name Physical Type Units
0 Right Ascension pos.eq.ra deg
1 Declination pos.eq.dec deg
Correlation between pixel and world axes:
Pixel Dim
World Dim 0 1
0 yes yes
1 yes yes
""".strip()
EXPECTED_2D_REPR_NUMPY1 = """
ResampledLowLevelWCS Transformation
This transformation has 2 pixel and 2 world dimensions
Expand All @@ -39,7 +61,6 @@ def celestial_wcs(request):
1 yes yes
""".strip()


@pytest.mark.parametrize('celestial_wcs',
['celestial_2d_ape14_wcs', 'celestial_2d_fitswcs'],
indirect=True)
Expand Down Expand Up @@ -93,6 +114,7 @@ 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)

Expand Down
2 changes: 2 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ filterwarnings =
ignore:distutils Version classes are deprecated
ignore:The default kernel will change from 'Hann' to 'Gaussian' in a future release. To suppress this warning, explicitly select a kernel with the 'kernel' argument.:FutureWarning
ignore:The default boundary mode will change from 'ignore' to 'strict' in a future release. To suppress this warning, explicitly select a mode with the 'boundary_mode' argument.:FutureWarning
doctest_subpackage_requires =
docs/explaining_ndcube/* = numpy>=2.0.0

[flake8]
exclude = extern,sphinx,*parsetab.py,conftest.py,docs/conf.py,setup.py
Expand Down
24 changes: 1 addition & 23 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ deps =
devdeps: git+https://github.com/sunpy/sunpy
devdeps: git+https://github.com/sunpy/mpl-animators
devdeps: git+https://github.com/spacetelescope/gwcs
devdeps: numpy>=0.0.dev0
# These are specific online extras we use to run the online tests.
online: pytest-rerunfailures
online: pytest-timeout
Expand Down Expand Up @@ -89,26 +90,3 @@ deps =
commands =
pre-commit install-hooks
pre-commit run --color always --all-files --show-diff-on-failure

# This env requires tox-conda.
[testenv:py{39,310,311}-conda]
pypi_filter =
extras =
deps =
conda_deps =
numpy
astropy
matplotlib
gwcs
sunpy
pytest
pytest-mpl
pytest-astropy
reproject
mpl_animators
conda_channels = conda-forge
allowlist_externals = conda
install_command = pip install --no-deps --no-build-isolation {opts} {packages}
commands =
conda list
{env:PYTEST_COMMAND} {posargs}

0 comments on commit 8d58fdc

Please sign in to comment.