Skip to content

feat: reuse SpatialData table coordinates for spatial neighbors - #1313

Open
Georicl wants to merge 4 commits into
scverse:mainfrom
Georicl:feature/1199-coordinate-reuse
Open

Georicl wants to merge 4 commits into
scverse:mainfrom
Georicl:feature/1199-coordinate-reuse

Conversation

@Georicl

@Georicl Georicl commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

Description

SpatialData inputs currently recompute element centroids and coordinate transformations on every spatial-neighbor call, even when the selected table already contains the required coordinates. This repeats input preparation when users rebuild a graph with different parameters, as reported in #1199.

Add the keyword-only parameter coordinate_source to all six spatial-neighbor entry points. The default, "elements", preserves centroid computation. With "table", graph construction reads the selected table's obsm[spatial_key] directly and skips centroid computation and coordinate transformation. AnnData inputs continue to use their existing coordinates with either value.

Table mode retains region and instance association checks and requires finite, real numeric NumPy coordinates of shape (n_obs, 2) in table observation order. Coordinates must already be in the desired coordinate system. Missing or invalid coordinates raise an error without falling back to element centroids. With copy=True, coordinates are copied into the existing lightweight temporary AnnData without loading the expression matrix. With copy=False, the original coordinate array is reused and graph results are saved to the table.

The change includes shared parameter documentation, a radius-graph example, regression tests, and a reproducible benchmark comparing element coordinates, table coordinates, and the equivalent AnnData input.

How has this been tested?

  • Independently reran the four affected test files on Python 3.13.3/macOS ARM64: 154 passed, 0 failed, 0 skipped, including 33 new coordinate-source cases.
  • Coverage includes all six entry points, custom coordinate keys, both copy modes, transformed elements, multiple regions, reordered observations, Labels, invalid inputs, read-only backed tables, construction failures, and builders that modify received coordinates. Existing copy and positional-argument regression tests also pass.
  • Additional behavior checks confirm that table mode with copy=False makes no coordinate assignments, missing keys raise KeyError in every entry point, and coordinate changes by a builder leave source data unchanged with copy=True.
  • Ruff checks, formatting checks, and git diff --check pass. Checked expanded documentation for all six interfaces and rendered the affected API documentation and benchmark README with Sphinx.
python -m pytest \
  tests/graph/test_spatial_neighbors_coordinate_source.py \
  tests/graph/test_spatial_neighbors_copy.py \
  tests/graph/test_spatial_neighbors.py \
  tests/utils/test_old_positionals.py

Performance

Benchmarked commit cbf140d on macOS ARM64 with Python 3.13.3 and SpatialData 0.8.0. Each case uses synthetic 16-vertex polygons and identical coordinates and region groups across the three paths. Radius is 1.6, copy=True, and n_jobs=1; numerical-library thread limits are one. Imports, warmup, fixture construction, and initial coordinate preparation are excluded from graph timings. The values below are medians of five repeated calls per path, in seconds.

Cells Regions Elements Table AnnData reference Elements / table
10,000 1 0.06074 0.04586 0.04273 1.32x
100,000 1 0.52817 0.47049 0.46633 1.12x
100,000 20 0.68310 0.43761 0.39888 1.56x

For 100,000 cells across 20 regions, total time decreases by 35.9%. Input preparation drops from 0.28549 s to 0.03208 s (8.90x), while graph construction time remains similar. Table mode makes zero centroid calls in all cases; element mode calls it once per region on every graph call. All 51 timed graph outputs match the reference CSR structure and values, and input observations and coordinates remain unchanged. The CSV samples and summary medians were independently cross-checked, and the recorded source hashes match the tested code.

Reproduce with the benchmark script:

PYTHONPATH="$PWD/src" python benchmarks/bench_spatial_neighbors_input.py \
  --output /tmp/squidpy-1199-benchmark

The benchmark README also documents the historical baseline and the earlier Linux run, with their environments and raw measurements. The table above compares paths within the final macOS run.

Closes

Closes #1199.

This branch has not been deployed

No deployments
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.

speed up _resolve_data in spatial neighbors when working with spatialdata

1 participant