Annotations#

How do I import GeoJSON, QuPath, or NDPA annotations?#

zs.io.load_annotations(wsi, "annotations.geojson", key_added="annotations")
zs.io.load_annotations(wsi, "slide.ndpa", key_added="annotations")

GeoJSON exported by QuPath is read through GeoPandas. LazySlide also handles Hamamatsu NDPA coordinates using metadata from the matching slide.

How do I inspect annotation classes and geometries?#

annotations = wsi.shapes["annotations"]
print(annotations.columns)
print(annotations.geom_type.value_counts())
print(annotations.head())
zs.pl.annotations(wsi, key="annotations")

Do this before filtering or joining. External tools can store class labels in nested fields; json_flatten="classification" handles the usual QuPath classification field.

How do I join annotations to tiles or other shapes?#

Use join_with for source layers and join_to for the destination layer:

zs.io.load_annotations(
    wsi,
    "annotations.geojson",
    join_with="tiles",
    join_to="tiles",
    key_added="annotations",
)

Inspect the resulting columns to confirm the spatial relationship matches the intended labeling rule. Boundary tiles may intersect more than one annotation.

How do I analyze only annotated regions?#

Use the imported annotation key as the region source for tiling:

zs.pp.tile_tissues(
    wsi,
    256,
    mpp=0.5,
    tissue_key="annotations",
    key_added="roi_tiles",
)

Filter the annotation GeoDataFrame first if only one class should be tiled, then store the filtered shapes under a new key.

How do I fix shifted annotations?#

Determine which coordinate system the exporter used. LazySlide shape coordinates are level-0 pixels. The in_bounds=True option translates annotations using slide bounds when the source coordinates are relative to the bounded image:

zs.io.load_annotations(
    wsi,
    "annotations.geojson",
    in_bounds=True,
    key_added="annotations_in_bounds",
)

Do not apply the translation merely until a plot “looks close.” Verify against known landmarks and scanner metadata.

How do I export annotations for QuPath?#

zs.io.export_annotations(
    wsi,
    key="cells",
    classes="class",
    format="qupath",
    file="cells.geojson",
)

The parent directory must already exist. Use in_bounds=True if the receiving tool expects coordinates translated out of the slide bounds.