Skip to content

SlicedLowLevelWCS does not handle negative indexing correctly #15557

Closed

Description

@DanRyanIrish

Description

SlicedLowLevelWCS is a WCS wrapper for slicing WCSs. It takes a WCS object and a sequence of slice items that can be applied to a data array, and returns a WCS object that ensures the same pixels correspond to the same world coordinates before and after slicing.

In slice items, negative indices are used to express indexing from the end of the array back towards the beginning. However, SlicedLowLevelWCS interprets negative indices in the standard WCS way, i.e. indices to the left of 0.

Expected behavior

Since the inputs are slice items for slicing the data array, SlicedLowLevelWCS should interpret negative indices along the same array slicing paradigm. If negative indices are supplied, it should therefore either:

  1. Error with a message saying negative indices are not supported, or;
  2. Convert the negative indices to their positive equivalent using the axis length information if available.

How to Reproduce

Set up

>>> from astropy.wcs import WCS
>>> from astropy.wcs.wcsapi import SlicedLowLevelWCS

>>> # Build initial WCS
>>> wcs = WCS(naxis=1)
>>> wcs.wcs.ctype = "WAVE",
>>> wcs.wcs.crval = 100,
>>> wcs.wcs.crpix = 0,
>>> wcs.wcs.cdelt = 0.2,
>>> wcs._naxis = [5]
>>> print(wcs.array_index_to_world_values([0, 1, 2, 3, 4])) # Confirm world values
[100.2 100.4 100.6 100.8 101. ]

>>> # Create sliced wcs
>>> sliced_wcs_pos = SlicedLowLevelWCS(wcs, slice(2, None))
>>> print(sliced_wcs_pos.array_index_to_world_values([0, 1, 2])) # Confirm world values
[100.6 100.8 101. ]

>>> # Create same sliced wcs using negative array indexing
>>> sliced_wcs_neg = SlicedLowLevelWCS(wcs, slice(-3, None))

Expected

ValueError("Negative indices not supported")

or

>>> print(sliced_wcs_neg.array_index_to_world_values([0, 1, 2]))
[100.6 100.8 101. ]

Actual

>>> print(sliced_wcs_neg.array_index_to_world_values([0, 1, 2]))
[ 99.6  99.8 100. ]

Versions

Linux-5.14.0-1048-oem-x86_64-with-glibc2.35
Python 3.11.0 | packaged by conda-forge | (main, Jan 14 2023, 12:27:40) [GCC 11.3.0]
astropy 5.3.4

Activity

  1. nabobalis commented on Sep 27, 2026

    @nabobalis
    Member

    Nested slicing hits the same problem through combine_slices, which adds a negative integer to the parent slice's start instead of counting from the end of the parent. Seen on astropy 7.2.0; combine_slices is the same on main.

    from astropy.wcs import WCS
    from astropy.wcs.wcsapi import SlicedLowLevelWCS
    
    wcs = WCS(naxis=2)
    wcs.wcs.ctype = ["WAVE", "TIME"]
    wcs.wcs.cunit = ["m", "s"]
    wcs.wcs.crpix = [1, 1]  # array index i along axis 0 has time i s
    wcs.pixel_shape = (3, 6)
    
    inner = SlicedLowLevelWCS(wcs, [slice(1, 5)])  # array indices 1 to 4
    print(SlicedLowLevelWCS(inner, [3]).dropped_world_dimensions["value"])   # correct: 4
    print(SlicedLowLevelWCS(inner, [-1]).dropped_world_dimensions["value"])  # expected 4
    [array(4.)]
    [array(0.)]
    

    inner[-1] should be array index 4, but combine_slices returns 1 + (-1) = 0. I think resolving negative indices against array_shape in SlicedLowLevelWCS.__init__, before combine_slices runs, would fix both the flat and the nested case.

    In the meantime ndcube resolves indices itself before slicing the WCS: sunpy/ndcube#979.

  2. astrofrog commented on Oct 22, 2026

    @astrofrog
    Member

    I believe this is fixed - the code above gives:

    [100.6 100.8 101. ]
    

    and if I comment out wcs._naxis = [5], I get:

    ValueError: Cannot use a negative slice start for dimension 0 since its size is not known
    
  3. nabobalis commented on Oct 22, 2026

    @nabobalis
    Member

    Thank you Tom

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions