Crop mishandles negative array indices

Open
#860 3 comments 0 reactions 2 assignees View on GitHub

@DanRyanIrish is already working on this.

Since Aug 11, 2025.

Assessment

This issue has not been assessed yet.

Description

Bug
Describe the bug

NDCube.crop uses wcs.world_to_array_index to convert world coordinates to array indices. This function uses negative array indices to denote points to the left/below the extent of the data array. NDCube.crop naively uses the returned array indices to construct the required slice item. This can result in a slice item of slice(-1, 1) which is intended to be equivalent to slice(0, 1). However, Python's slicing notation interprets this can slicing forwards from the last array index to the first. This results in slicing the cube to a shape of (0,)

Proposed solution:

  • ndcube.utils.cube.get_crop_item_from_points should convert any negative array index to 0, so that it's output is always slice(0, 1), and never slice(-1, 1)
  • NDCube.__getitem__ should add to its slice input sanitization so that it errors for cases like slice(-1, 1) where the result will be shape (0,)

Thanks to @hayesla for revealing this bug.

To Reproduce
import astropy.units as u
import numpy as np
import sunpy.map

from astropy.coordinates import SkyCoord
from astropy.wcs import WCS
from ndcube import NDCube

def make_simple_cube():
    """
    A simple 9x9 map, with its center at (0, 0),
    and scaled differently in each direction.
    """
    data = np.arange(81).reshape((9, 9))
    ref_coord = SkyCoord(0.0, 0.0, frame='helioprojective', obstime='2020-01-01 00:00:00', unit='deg',
                         observer=SkyCoord(0 * u.deg, 0 * u.deg, 1 * u.AU, frame='heliographic_stonyhurst'))
    ref_pix = [4, 4] * u.pix
    scale = [2, 1] * u.arcsec / u.pix
    header = sunpy.map.make_fitswcs_header(data, ref_coord, reference_pixel=ref_pix, scale=scale)
    return NDCube(data, WCS(header))

cube = make_simple_cube()

# Create world coords to crop to.
bottom_left = cube.wcs.array_index_to_world(-1, -1)
top_right = cube.wcs.array_index_to_world(0, 0)

# Crop cube to 0-size
cube0 = cube.crop((bottom_left,), (top_right,))
Dominant language
Python
Stars
49
Forks
56
Avg merge
5h 54m
Merged PRs (30d)
9

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from sunpy/ndcube

All issues in sunpy/ndcube

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.