Skip to content
1 change: 1 addition & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ See the {doc}`extensibility guide </extensibility>` for how to implement a custo
experimental.im.calculate_image_features
experimental.tl.calculate_tiling_qc
experimental.tl.TilingQCParams
experimental.tl.SeamDetectionParams
experimental.tl.assign_stitch_groups
experimental.tl.StitchParams
experimental.tl.make_stitched_labels
Expand Down
34 changes: 32 additions & 2 deletions src/squidpy/experimental/im/_tiling.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,12 +351,42 @@ def extract_labels_tile_lazy(
-------
``(crop_h, crop_w)`` numpy array with non-owned cells zeroed.
"""
cy0, cx0, cy1, cx1 = spec.crop
tile_labels = _as_2d(_materialize(labels_da.isel(y=slice(cy0, cy1), x=slice(cx0, cx1))).copy())
tile_labels = _crop_labels(labels_da, spec)
_zero_non_owned(tile_labels, spec.owned_ids)
return tile_labels


def _crop_labels(labels_da: xr.DataArray, spec: TileSpec) -> np.ndarray:
"""Materialize a tile's crop region as a writable 2-D label array, before any masking."""
cy0, cx0, cy1, cx1 = spec.crop
return _as_2d(_materialize(labels_da.isel(y=slice(cy0, cy1), x=slice(cx0, cx1))).copy())


def extract_labels_tile_with_occupancy(
labels_da: xr.DataArray,
spec: TileSpec,
) -> tuple[np.ndarray, np.ndarray]:
"""Extract a labels tile together with the *unmasked* occupancy of the same crop.

``tile_labels`` has non-owned cells zeroed, so every cell is scored by exactly one
tile. ``occupancy`` marks every labelled pixel in the crop, owned or not.

Geometry that asks "is there tissue beyond this edge?" must use ``occupancy``: on the
masked array a cell whose neighbour is owned by the adjacent tile reads that neighbour
as background, which turns an ordinary inter-cell membrane into an apparent wide gap
along every tile border. Only one crop is materialized for both outputs.

Returns
-------
``(tile_labels, occupancy)`` -- the owned-only label crop and the boolean occupancy of
the same region before masking.
"""
tile_labels = _crop_labels(labels_da, spec)
occupancy = tile_labels != 0
_zero_non_owned(tile_labels, spec.owned_ids)
return tile_labels, occupancy


def _zero_non_owned(tile_labels: np.ndarray, owned_ids: frozenset[int]) -> None:
"""Zero out labels not in *owned_ids* (in-place).

Expand Down
10 changes: 8 additions & 2 deletions src/squidpy/experimental/pl/_tiling_qc.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ def tiling_qc(
"max_straight_edge_ratio",
"cardinal_alignment_score",
"is_outlier",
"is_seam_cut",
"seam_dist",
] = "nhood_outlier_fraction",
cmap: str = "RdYlGn_r",
figsize: tuple[float, float] | None = None,
Expand All @@ -44,7 +46,9 @@ def tiling_qc(
Which ``.obs`` column to colour by. One of
``"nhood_outlier_fraction"``, ``"smoothed_cut_score"``,
``"cut_score"``, ``"max_straight_edge_ratio"``,
``"cardinal_alignment_score"``, ``"is_outlier"``.
``"cardinal_alignment_score"``, ``"is_outlier"`` (MAD gate),
or -- from ``calculate_tiling_qc(detect_seams=True)`` -- the
emergent-seam columns ``"is_seam_cut"`` and ``"seam_dist"``.
cmap
Matplotlib colormap name.
figsize
Expand All @@ -70,9 +74,11 @@ def tiling_qc(
"nhood_outlier_fraction": "Neighborhood outlier fraction",
"smoothed_cut_score": "Smoothed cut score",
"cut_score": "Cut score",
"is_outlier": "Outlier flag",
"is_outlier": "Outlier flag (MAD)",
"max_straight_edge_ratio": "Max straight edge ratio",
"cardinal_alignment_score": "Cardinal alignment score",
"is_seam_cut": "Seam-cut flag (emergent seam)",
"seam_dist": "Distance to seam",
}

show_kwargs: dict[str, object] = {"title": _TITLES.get(score_col, score_col)}
Expand Down
10 changes: 9 additions & 1 deletion src/squidpy/experimental/tl/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
from __future__ import annotations

from ._seam import SeamDetectionParams
from ._stitched_labels import make_stitched_labels
from ._tiling_qc import TilingQCParams, calculate_tiling_qc
from ._tiling_stitch import StitchParams, assign_stitch_groups

__all__ = ["StitchParams", "TilingQCParams", "assign_stitch_groups", "calculate_tiling_qc", "make_stitched_labels"]
__all__ = [
"SeamDetectionParams",
"StitchParams",
"TilingQCParams",
"assign_stitch_groups",
"calculate_tiling_qc",
"make_stitched_labels",
]
Loading
Loading