Skip to content

Support single N-D Time and Quantity lookup tables in extra_coords#941

Open
nabobalis wants to merge 2 commits into
sunpy:mainfrom
nabobalis:nd-table-extra-coords
Open

Support single N-D Time and Quantity lookup tables in extra_coords#941
nabobalis wants to merge 2 commits into
sunpy:mainfrom
nabobalis:nd-table-extra-coords

Conversation

@nabobalis

Copy link
Copy Markdown
Member

PR Description

TimeTableCoordinate and QuantityTableCoordinate now accept a single N-D
table, representing one physical coordinate that varies over N pixel
dimensions. For example, a 2-D Time table indexed by (raster scan, raster
step) can now be attached with:

cube.extra_coords.add("time", (0, 1), times_2d, physical_types="time")

Previously QuantityTableCoordinate raised "Currently all tables must be
1-D" and TimeTableCoordinate was hardwired to one dimension, so per-exposure
times on a multi-scan cube could not be expressed as an extra coord at all.

Implementation notes:

  • N-D tables expose their model inputs in pixel order (reversed array
    order). NDCube._generate_world_coords transposes world values assuming
    the APE-14 pixel-axis convention, so an array-ordered model produces
    transposed axis_world_coords output. ExtraCoords.mapping reverses the
    converted axes for such coordinates to stay consistent (see the new
    BaseTableCoordinate._model_inputs_are_pixel_ordered property).
  • ExtraCoords._getitem_lookup_tables now drops integer-sliced axes from a
    table's axes tuple when the sliced table actually loses pixel dimensions.
    Previously the axes tuple kept stale (even negative) entries; this was
    latent for existing coordinate types but breaks N-D tables. Range slices
    keep the table N-D, integer slices reduce it, and slicing away all table
    dimensions drops the coordinate into dropped_tables as before.
  • interpolate supports N-D tables via scipy.interpolate.interpn
    (TimeTableCoordinate.interpolate now takes *new_array_grids, matching
    the other table coordinate types; the old single-grid call still works).
  • Fixed a latent Length1Tabular dispatch bug: a table of shape (1, n) was
    routed to the length-1 1-D model because the check used len(table) == 1
    instead of table.shape == (1,).

AI Assistance Disclosure

AI tools were used for:

  • Code generation (e.g., when writing an implementation or fixing a bug)
  • Test/benchmark generation
  • Documentation (including examples)
  • Research and understanding
  • No AI tools were used

Regardless of AI use, the human contributor remains fully responsible for correctness, design choices, licensing compatibility, and long-term maintainability.

A single N-D table now represents one coordinate varying over N pixel
dimensions, e.g. a 2-D Time table indexed by (raster scan, raster step).
N-D table models expose their inputs in pixel order to match the APE-14
convention assumed by NDCube world-coordinate generation, and slicing
drops integer-sliced axes from a table's axes when the table loses pixel
dimensions. Also fixes a latent Length1Tabular dispatch bug for tables of
shape (1, n).


@pytest.mark.xfail(reason=">1D Tables not supported")
def test_2d_nout_1_no_mesh(lut_2d_distance_no_mesh):

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixture was deleted?



@pytest.mark.xfail(reason=">1D Tables not supported")
def test_2d_nout_1_no_mesh_slice(lut_2d_distance_no_mesh):

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixture was deleted?



@pytest.mark.xfail(reason=">1D Tables not supported")
def test_mtc_dropped_quantity_table(lut_1d_time, lut_2d_distance_no_mesh):

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixture was deleted?



@pytest.mark.xfail(reason=">1D Tables not supported")
def test_mtc_dropped_quantity_inside_table_no_mesh(lut_2d_distance_no_mesh):

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixture was deleted?

ec_shape = cube.data.shape[1:3]
data = np.arange(np.prod(ec_shape)).reshape(ec_shape) * u.m / u.s

# The lookup table has to be in world order so transpose it.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this still be the case?

@nabobalis nabobalis marked this pull request as ready for review June 12, 2026 20:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant