aggregate(image, by=labels) silently ignores translations/offsets between the two rasters
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 394
- Forks
- 95
- Avg merge
- 4d 3h
- Merged PRs (30d)
- 7
Description
[!NOTE]
This whole message is AI-generated. The issue was automatically discovered and reported by an AI agent (Claude) during an autonomous bug hunt on thespatialdatacode base. It has not been verified or triaged by a human yet; theneeds: triagelabel is set so that a maintainer can confirm it. The reproduction script below was executed by the agent in an isolated environment (see Environment) and its output is pasted verbatim.
Summary
When the by and values transformations differ, aggregate calls transform() on both rasters; for rasters transform() applies only the linear part and keeps the translation in the element's transformation (documented behaviour of transform). _aggregate_image_by_labels then runs xrspatial.zonal_stats on the raw pixel grids, i.e. it assumes pixel (i, j) of the image and of the labels coincide. An image shifted by a Translation (e.g. a crop, or a query result) is therefore attributed to the wrong cells.
Severity (agent's assessment): high — wrong numbers, no warning
Where: src/spatialdata/_core/operations/aggregate.py::aggregate (~line 150-160) and _aggregate_image_by_labels
Expected behaviour
Either the offset is honoured (rasters aligned on a common grid before zonal_stats) or a clear NotImplementedError is raised when the affine matrices differ after the linear part has been applied.
Reproduction
Save as repro.py and run uv run repro.py (the PEP 723 header pins spatialdata to the commit the bug was found on; replace the URL fragment with @main to test the current main branch).
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "spatialdata @ git+https://github.com/scverse/spatialdata.git@ccf1ea048d054b6624214bf618008a9f9ae223e0",
# ]
# ///
"""aggregate(image, by=labels) ignores the translation between the two rasters (silently wrong result)."""
import warnings
import numpy as np
from spatialdata import aggregate
from spatialdata.models import Image2DModel, Labels2DModel
from spatialdata.transformations import Identity, Translation
warnings.simplefilter("ignore")
# label 1 = top-left 2x2 block, label 2 = bottom-right 2x2 block
lab = Labels2DModel.parse(np.array([[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 2, 2], [0, 0, 2, 2]], dtype=np.uint16))
arr = np.zeros((1, 4, 4))
arr[0, :2, :2] = 1.0 # ones in the top-left block (intrinsic coordinates)
results = {}
for name, t in [("identity", Identity()), ("translated by (2, 2)", Translation([2, 2], axes=("x", "y")))]:
img = Image2DModel.parse(arr.copy(), transformations={"global": t})
table = aggregate(values=img, by=lab, agg_func="sum")["table"]
sums = dict(zip(table.obs.index.tolist(), table.X.toarray().ravel().tolist()))
results[name] = sums
print(f"image {name:22s}: sums per label {sums}")
print("expected for the translated image: {'1': 0.0, '2': 4.0} (the ones now sit on label 2)")
bug = results["translated by (2, 2)"].get("2") != 4.0
print("VERDICT:", "BUG REPRODUCED" if bug else "NOT REPRODUCED")
Observed output
image identity : sums per label {'1': 4.0, '2': 0.0}
image translated by (2, 2) : sums per label {'1': 4.0, '2': 0.0}
expected for the translated image: {'1': 0.0, '2': 4.0} (the ones now sit on label 2)
VERDICT: BUG REPRODUCED
Possible fix direction (unverified)
Align the rasters onto the target grid (reindex via the coordinates derived from the transformations, or rasterize() both onto the same grid) before calling zonal_stats; at minimum raise when the translations differ. Related: #950 reports an error for more complex transformations; this report is about the silent wrong result for translations.
Environment
uv run repro.py with the PEP 723 metadata in the script (fresh, isolated environment; spatialdata built from main @ ccf1ea0 (2026-08-28); Python 3.13, latest releases of the dependencies at run time: pandas 3.0, anndata 0.13, zarr 3.3, dask 2026.8, numpy 2.5, geopandas 1.1, shapely 2.1). macOS (arm64). Also reproduced in a second environment with pandas 2.3.3 / anndata 0.12.11 / numpy 2.4.4 / zarr 3.2.1.
Possibly related issues
#950
Automatically generated; discovered by an AI agent (Claude) and not yet reviewed by a human.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/spatialdata/_core/operations/aggregate.py, especially aggregate and _aggregate_image_by_labels, then run the supplied repro.py with uv run. Trace how raster transformations and translations are handled before zonal_stats. Done means translated rasters produce the expected label sums, or differing affine matrices raise the documented error.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- data
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100