Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
a0a2db0
feat(experimental): add assign_stitch_groups for tile-cut stitching
timtreis May 29, 2026
2e06b7e
test: add quantitative recovery floor from validation sweep
timtreis May 29, 2026
4c25fe0
docs: add stitch-score explainer figures for the PR
timtreis May 29, 2026
099eded
test: trim assign_stitch_groups suite to user-observable behaviour
timtreis May 30, 2026
584417e
docs: drop committed explainer figures (belong in the PR description,…
timtreis May 30, 2026
b2bb95a
refactor: drop the cross-module drive-by, simplify uns/diagnostics
timtreis May 30, 2026
a55ab0c
refactor: drop feature_weights + save_diagnostics; flat-mean score
timtreis May 30, 2026
f2c0508
style: align test layout + drop banner dividers with the codebase
timtreis May 30, 2026
4883a53
style: remove banner-divider comments repo-wide
timtreis May 30, 2026
08e9fdf
perf: address review - prune low-confidence pairs + reuse pre-fetched…
timtreis Jun 2, 2026
4667b80
docs: fix RTD -W build (drop misparsed "Advanced:" prefix, suppress m…
timtreis Jun 2, 2026
b24c826
refactor: derive the prune bound from the scorer so it can't drift
timtreis Jun 2, 2026
99fdfcf
test: add CI-generated baseline for the stitch seam-recolor visual test
timtreis Jun 2, 2026
1ff7f43
test: make the seam-recolor visual deterministic across platforms
timtreis Jun 2, 2026
f98f744
test: render the seam-recolor visual 1:1 to kill cross-platform resam…
timtreis Jun 2, 2026
2f21a65
test: add regenerated CI baseline for the 1:1 seam-recolor visual
timtreis Jun 2, 2026
5ea2cb1
test: drop the early-prune unit test (over-testing a private helper)
timtreis Jun 3, 2026
5be9e39
Merge branch 'main' into feature/tiling-stitch-algo
selmanozleyen Jun 8, 2026
98566ee
Merge branch 'main' into feature/tiling-stitch-algo
timtreis Jun 9, 2026
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
2 changes: 2 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ See the {doc}`extensibility guide </extensibility>` for how to implement a custo

experimental.tl.calculate_tiling_qc
experimental.tl.TilingQCParams
experimental.tl.assign_stitch_groups
experimental.tl.StitchParams
experimental.pl.tiling_qc
experimental.im.fit_stain_reference
experimental.im.apply_stain_normalization
Expand Down
8 changes: 0 additions & 8 deletions src/squidpy/experimental/im/_tiling.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,7 @@ class TileSpec:
owned_ids: frozenset[int]


# ---------------------------------------------------------------------------
# Centroid computation
# ---------------------------------------------------------------------------


def compute_cell_info(labels: np.ndarray) -> dict[int, CellInfo]:
Expand Down Expand Up @@ -194,9 +192,7 @@ def compute_cell_info_tiled(
return result


# ---------------------------------------------------------------------------
# Tile spec building
# ---------------------------------------------------------------------------


def _auto_margin(cell_info: dict[int, CellInfo]) -> int:
Expand Down Expand Up @@ -281,9 +277,7 @@ def build_tile_specs(
return specs


# ---------------------------------------------------------------------------
# Tile extraction
# ---------------------------------------------------------------------------


def extract_tile(
Expand Down Expand Up @@ -405,9 +399,7 @@ def _zero_non_owned(tile_labels: np.ndarray, owned_ids: frozenset[int]) -> None:
tile_labels[~np.isin(tile_labels, owned_arr)] = 0


# ---------------------------------------------------------------------------
# Coverage verification
# ---------------------------------------------------------------------------


def verify_coverage(
Expand Down
3 changes: 2 additions & 1 deletion src/squidpy/experimental/tl/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

from ._tiling_qc import TilingQCParams, calculate_tiling_qc
from ._tiling_stitch import StitchParams, assign_stitch_groups

__all__ = ["TilingQCParams", "calculate_tiling_qc"]
__all__ = ["StitchParams", "TilingQCParams", "assign_stitch_groups", "calculate_tiling_qc"]
43 changes: 35 additions & 8 deletions src/squidpy/experimental/tl/_tiling_qc.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
compute_cell_info_tiled,
extract_labels_tile_lazy,
)
from squidpy.experimental.tl._tiling_stitch import _STITCH_COLUMNS, _STITCH_PARAM_KEYS, StitchParams
from squidpy.experimental.utils._labels import resolve_labels_array

__all__ = ["TilingQCParams", "calculate_tiling_qc"]
Expand Down Expand Up @@ -137,9 +138,7 @@ def _has_distributed_client() -> bool:
return True


# ---------------------------------------------------------------------------
# Core geometry
# ---------------------------------------------------------------------------


@njit(cache=True, nogil=True)
Expand Down Expand Up @@ -355,9 +354,7 @@ def _straight_edge_metrics(
return float(straight_ratio), float(cardinal), float(cut_score)


# ---------------------------------------------------------------------------
# Per-tile scoring
# ---------------------------------------------------------------------------


def _score_tile(
Expand Down Expand Up @@ -430,9 +427,7 @@ def _score_tile(
return pd.DataFrame.from_dict(rows, orient="index")


# ---------------------------------------------------------------------------
# Centroid computation (shared logic with _feature.py)
# ---------------------------------------------------------------------------


def _compute_centroids_for_labels(
Expand All @@ -457,9 +452,7 @@ def _compute_centroids_for_labels(
return compute_cell_info_tiled(labels_da)


# ---------------------------------------------------------------------------
# Public API
# ---------------------------------------------------------------------------


_METHOD_KEY = "tiling_qc"
Expand Down Expand Up @@ -733,6 +726,40 @@ def _process_one(spec):

if inplace:
table_key = table_key_added if table_key_added is not None else f"{labels_key}_qc"
_warn_if_dropping_stitch_columns(sdata, table_key, labels_key)
sdata.tables[table_key] = TableModel.parse(adata)
return None
return adata


def _warn_if_dropping_stitch_columns(sdata: sd.SpatialData, table_key: str, labels_key: str) -> None:
"""Warn if re-running QC would drop downstream stitch results.

``calculate_tiling_qc`` replaces the QC table wholesale, so any columns
added by :func:`~squidpy.experimental.tl.assign_stitch_groups` to a previous
version of this table are about to disappear. We emit an actionable warning
listing the previous stitch parameters (from ``.uns["tiling_stitch"]``) and a
copy-pasteable invocation to restore them.
"""
if table_key not in sdata.tables:
return
existing = sdata.tables[table_key]
present = [c for c in _STITCH_COLUMNS if c in existing.obs.columns]
if not present:
return

prev_params = existing.uns.get("tiling_stitch", {}) if hasattr(existing, "uns") else {}
parts = [f"labels_key={labels_key!r}"]
parts.extend(f"{k}={v!r}" for k, v in prev_params.items() if k in _STITCH_PARAM_KEYS)
nested = prev_params.get("stitch_params")
if isinstance(nested, dict) and nested:
defaults = asdict(StitchParams())
diff = {k: v for k, v in nested.items() if k in defaults and defaults[k] != v}
if diff:
parts.append(f"stitch_params={diff!r}")
rerun = f"sq.experimental.tl.assign_stitch_groups(sdata, {', '.join(parts)})"
logg.warning(
f"Re-running calculate_tiling_qc dropped previous stitch columns "
f"({', '.join(present)}) from sdata.tables[{table_key!r}]. "
f"To restore them, run: {rerun}"
)
Loading
Loading