Skip to content

exceeding rasterize's maximum label index #987

Description

@LouisK92

I am using sd.rasterize on cell polygons of >100k cells and run into the error.

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[14], line 1
----> 1 sdata["cell_labels"] = sd.rasterize(
...
      9 )

File ~/miniconda3/envs/g3/lib/python3.11/site-packages/spatialdata/_core/operations/rasterize.py:351, in rasterize(data, axes, min_coordinate, max_coordinate, target_coordinate_system, target_unit_to_pixels, target_width, target_height, target_depth, sdata, value_key, table_name, return_regions_as_labels, agg_func, return_single_channel)
    349     return rasterized
    350 if model in (PointsModel, ShapesModel):
--> 351     return rasterize_shapes_points(
...    368     )
    369 raise ValueError(f"Unsupported model {model}.")

File ~/miniconda3/envs/g3/lib/python3.11/site-packages/spatialdata/_core/operations/rasterize.py:723, in rasterize_shapes_points(data, axes, min_coordinate, max_coordinate, target_coordinate_system, target_unit_to_pixels, target_width, target_height, target_depth, element_name, sdata, value_key, table_name, return_regions_as_labels, agg_func, return_single_channel)
    721 max_uint16 = np.iinfo(np.uint16).max
    722 if max_label > max_uint16:
--> 723     raise ValueError(f"Maximum label index is {max_label}. Values higher than {max_uint16} are not supported.")
    724 agg = agg.astype(np.uint16)
    725 return Labels2DModel.parse(agg, transformations=transformations)

ValueError: Maximum label index is 117340. Values higher than 65535 are not supported.

I was wondering if the threshold needs to be that low or could be increased?

To reproduce the error:

import numpy as np
import spatialdata as sd

def get_n_coords(n):
    coords = np.random.rand(n, 2)
    return coords
    
sdata1 = sd.SpatialData(points={"points": PointsModel.parse(get_n_coords(65534))})
sdata2 = sd.SpatialData(points={"points": PointsModel.parse(get_n_coords(65536))})

# sdata1 would work
img_extent = sd.get_extent(sdata2['points'])
sd.rasterize(
    sdata2["points"],
    ["x", "y"],
    min_coordinate=[int(img_extent["x"][0]), int(img_extent["y"][0])],
    max_coordinate=[int(img_extent["x"][1]), int(img_extent["y"][1])],
    target_coordinate_system="global",
    target_unit_to_pixels=1,
    return_regions_as_labels=True,
)

Activity

  1. LouisK92 commented on Sep 22, 2025

    @LouisK92
    Author

    A quick workaround (assuming that cell labels don't overlap) would be the following. Note that I used circles instead of points for the example, which is closer to what I actually wanted. In case of points the .iloc fails since we'd deal with a dask dataframe in that case.

    import numpy as np
    import spatialdata as sd
    from spatialdata.models import ShapesModel
    
    def get_n_coords(n):
        coords = np.random.rand(n, 2)
        return coords
        
    sdata = sd.SpatialData(shapes={"shapes": ShapesModel.parse(get_n_coords(65536), geometry=0, radius=np.ones(65536))})
    
    img_extent = sd.get_extent(sdata['shapes']) # NOTE: Here I actually use sd.get_extent(sdata['image'])
    
    N = 65535 # number of shapes that are rasterised per step
    n_cells = len(sdata['shapes'])
    n_iter = n_cells // N + bool(n_cells % N)
    
    rasterize_args = {
        "min_coordinate": [int(img_extent["x"][0]), int(img_extent["y"][0])],
        "max_coordinate": [int(img_extent["x"][1]), int(img_extent["y"][1])],
        "target_coordinate_system": "global",
        "target_unit_to_pixels": 1,
        "return_regions_as_labels": True,
    }
    
    for i in range(n_iter):
        labels_image_ = sd.rasterize(sdata['shapes'].iloc[i*N:min((i+1)*N, n_cells)], ["x", "y"], **rasterize_args)
        if i == 0:
            labels_image = labels_image_
        else:
            labels_image.values[labels_image_.values > 0] = labels_image_.values[labels_image_.values > 0]
    
    sdata['labels'] = labels_image
  2. LucaMarconato commented on May 21, 2026

    @LucaMarconato
    Member

    Related discussion: #187

  3. LucaMarconato commented on Sep 13, 2026

    @LucaMarconato
    Member

    This whole message is AI-generated. The issue was automatically discovered and reported by an AI agent (Claude) during an autonomous bug hunt on the spatialdata code base. It has not been verified or triaged by a human yet; the needs: triage label 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.

    I re-attempted to reproduce this issue on the current main branch (commit ccf1ea048d054b6624214bf618008a9f9ae223e0) as part of a triage pass over open issues, and confirmed it reproduces.

    Reproduction script (PEP 723 inline metadata; run with uv run repro.py, no other setup needed):

    # /// script
    # requires-python = ">=3.12"
    # dependencies = [
    #     "spatialdata @ git+https://github.com/scverse/spatialdata.git@ccf1ea048d054b6624214bf618008a9f9ae223e0",
    # ]
    # ///
    """#987: rasterize(..., return_regions_as_labels=True) refuses more than 65535 shapes (uint16 output)."""
    import warnings
    import numpy as np
    from spatialdata import get_extent, rasterize
    from spatialdata.models import ShapesModel
    
    warnings.simplefilter("ignore")
    rng = np.random.default_rng(0)
    bug = False
    for n in [65_534, 70_000]:
        shapes = ShapesModel.parse(rng.uniform(0, 1000, (n, 2)), geometry=0, radius=np.full(n, 0.5))
        ext = get_extent(shapes)
        try:
            lab = rasterize(shapes, ["x", "y"], min_coordinate=[ext["x"][0], ext["y"][0]], max_coordinate=[ext["x"][1], ext["y"][1]],
                            target_coordinate_system="global", target_unit_to_pixels=1, return_regions_as_labels=True)
            print(f"{n} circles: OK, labels dtype {lab.dtype}")
        except Exception as e:  # noqa: BLE001
            print(f"{n} circles: {type(e).__name__}: {str(e)[:100]}")
            bug = True
    print("VERDICT:", "REPRODUCED (hard uint16 limit; rasterize_bins already uses _get_uint_dtype to pick uint32/uint64)" if bug else "NOT REPRODUCED")

    Environment: uv run --no-project --python 3.13, which resolves spatialdata from git+https://github.com/scverse/spatialdata.git@ccf1ea048d054b6624214bf618008a9f9ae223e0 (extra dependencies, if any, are pinned in the script's inline metadata above).

    Output (verbatim, only uv package-resolution/install log lines removed):

    65534 circles: OK, labels dtype uint16
    70000 circles: ValueError: Maximum label index is 70000. Values higher than 65535 are not supported.
    VERDICT: REPRODUCED (hard uint16 limit; rasterize_bins already uses _get_uint_dtype to pick uint32/uint64)
    exit=0
    

    Agent's severity assessment: medium (see the priority: * label added to this issue).


    Automatically generated; discovered by an AI agent (Claude) and not yet reviewed by a human.

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