Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ See the {doc}`extensibility guide </extensibility>` for how to implement a custo
experimental.tl.TilingQCParams
experimental.tl.assign_stitch_groups
experimental.tl.StitchParams
experimental.im.make_stitched_labels
experimental.pl.tiling_qc
experimental.im.fit_stain_reference
experimental.im.apply_stain_normalization
Expand Down
1 change: 1 addition & 0 deletions docs/release/notes-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Features

- Add {func}`squidpy.experimental.im.make_stitched_labels` to materialise a stitched labels element (and an optional collapsed table) from an {func}`squidpy.experimental.tl.assign_stitch_groups` result, completing the tile-cut stitching workflow.
- Fix {func}`squidpy.tl.var_by_distance` behaviour when providing {mod}`numpy` arrays of coordinates as anchor point.
- Update :attr:`squidpy.pl.var_by_distance` to show multiple variables on same plot.
[@LLehner](https://github.com/LLehner)
Expand Down
2 changes: 2 additions & 0 deletions src/squidpy/experimental/im/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
apply_stain_normalization,
fit_stain_reference,
)
from ._stitched_labels import make_stitched_labels

__all__ = [
"BackgroundDetectionParams",
Expand All @@ -26,6 +27,7 @@
"apply_stain_normalization",
"detect_tissue",
"fit_stain_reference",
"make_stitched_labels",
"make_tiles",
"make_tiles_from_spots",
"qc_image",
Expand Down
546 changes: 546 additions & 0 deletions src/squidpy/experimental/im/_stitched_labels.py

Large diffs are not rendered by default.

15 changes: 3 additions & 12 deletions src/squidpy/experimental/tl/_tiling_qc.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

import math
from collections.abc import Mapping
from dataclasses import asdict, dataclass, fields
from dataclasses import asdict, dataclass
from typing import Any, Literal

import anndata as ad
Expand All @@ -54,6 +54,7 @@
)
from squidpy.experimental.tl._tiling_stitch import _STITCH_COLUMNS, _STITCH_PARAM_KEYS, StitchParams
from squidpy.experimental.utils._labels import resolve_labels_array
from squidpy.experimental.utils._params import resolve_params

__all__ = ["TilingQCParams", "calculate_tiling_qc"]

Expand Down Expand Up @@ -92,23 +93,13 @@ def __post_init__(self) -> None:


_QC_DEFAULTS = TilingQCParams()
_QC_FIELDS = frozenset(f.name for f in fields(TilingQCParams))


def _resolve_qc_params(qc_params: TilingQCParams | Mapping[str, Any] | None) -> TilingQCParams:
"""Normalise the ``tiling_qc_params`` argument to a :class:`TilingQCParams` instance."""
if qc_params is None:
return _QC_DEFAULTS
if isinstance(qc_params, TilingQCParams):
return qc_params
if isinstance(qc_params, Mapping):
unknown = set(qc_params) - _QC_FIELDS
if unknown:
raise ValueError(
f"Unknown `tiling_qc_params` field(s): {sorted(unknown)}; expected from {sorted(_QC_FIELDS)}."
)
return TilingQCParams(**qc_params)
raise TypeError(f"`tiling_qc_params` must be TilingQCParams, Mapping, or None; got {type(qc_params).__name__}.")
return resolve_params(qc_params, TilingQCParams, label="`tiling_qc_params`")


# Standard consistency factor sd ~ 1.4826 x MAD for normal distributions.
Expand Down
11 changes: 6 additions & 5 deletions src/squidpy/experimental/tl/_tiling_stitch.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,11 @@
from scipy.ndimage import binary_closing
from scipy.sparse import csr_matrix
from scipy.sparse.csgraph import connected_components
from skimage.measure import find_contours, regionprops
from skimage.measure import label as cc_label
from skimage.measure import regionprops
from skimage.morphology import disk as morph_disk
from spatialdata._logging import logger as logg

from squidpy.experimental.utils._geometry import equivalent_diameter, largest_contour
from squidpy.experimental.utils._labels import iter_chunked_regionprops, resolve_labels_array
from squidpy.experimental.utils._params import resolve_params

Expand Down Expand Up @@ -302,10 +301,12 @@ def _extract_cut_edges(
if not cell_mask.any():
continue
outlier_crops[lid] = cell_mask
# 1px zero-pad so cells filling their bbox still trace a closed contour.
mask = np.pad(cell_mask.astype(np.float32), 1, mode="constant", constant_values=0)
contour = largest_contour(mask)
if contour is None:
contours = find_contours(mask, 0.5)
if not contours: # degenerate mask traces nothing; skip it
continue
contour = max(contours, key=len)
contour_global = contour.copy()
contour_global[:, 0] += min_r - 1
contour_global[:, 1] += min_c - 1
Expand All @@ -315,7 +316,7 @@ def _extract_cut_edges(
cy = float(ys.mean()) + min_r - 1
cx = float(xs.mean()) + min_c - 1
area = float(mask.sum())
eq_diameter = equivalent_diameter(area)
eq_diameter = float(np.sqrt(4 * area / np.pi)) # diameter of the equal-area circle
min_len = max(min_edge_length, min_edge_length_ratio * eq_diameter)

# find_contours places level set 0.5 outside the integer pixel boundary.
Expand Down
30 changes: 0 additions & 30 deletions src/squidpy/experimental/utils/_geometry.py

This file was deleted.

Loading
Loading