Skip to main content

standissect-lite

Find each cluster's minor siblings — the small stray fragments carrying its own label — and nothing else.

Why (出发点)

Single-cell annotation and quality control both lean on clustering — yet clustering followed by subset-and-recluster often fails to cleanly separate tiny subpopulations and low-quality subgroups from their parent cluster.

In practice analysts fall back on the UMAP: spot a small island sitting apart from its cluster's main blob, and lasso it by hand. UMAP is rightly criticised against over-interpretation; still, local separations in the embedding can provide useful candidate structure, because UMAP is built to preserve aspects of the high-dimensional neighbourhood graph. Analysts already treat UMAP islands as hypotheses — this package turns that visual heuristic into a systematic candidate-detection procedure: it clusters the UMAP coordinates (granularity-matched to the RNA-side clustering), crosses the two partitions, and hands the islands back as named, ranked fragments, while explicitly leaving validation to downstream evidence.

Two boundaries are deliberate:

  • Candidates, not conclusions. Whether a detected tiny cluster is biologically meaningful (or a doublet pocket / low-quality tail) is decided by downstream evidence, not by this method. Its only job is to replace inefficient manual lassoing with something reproducible.
  • Light by construction. The full standissect adds that interpretation layer (DEG, QC drift, LLM diagnosis, reports, review server). standissect-lite is the detection step alone, extracted so other projects can reuse it without the heavy stack: no scanpy, no DEG, no LLM, no server. One module, six light dependencies, pure functions.

What it does

It crosses two partitions of the same cells:

  1. your precomputed RNA-side Leiden clustering — read as-is from adata.obs[cluster_col], never recomputed;
  2. a UMAP-side clustering computed here — kNN graph on the 2-D UMAP coordinates + Leiden on that graph.

Naming happens in two steps. Step 1 — cartesian product: each non-empty (RNA cluster × UMAP cluster) combination is a fragment; think of it as the concatenated name c3u5 = cells in RNA cluster 3 ∩ UMAP cluster u5. Step 2 — rank by size: within each RNA cluster, fragments are sorted by cell count and renamed c{cluster}_{rank} — the largest becomes the main core, the rest are its minor siblings:

  step 1: product names                    step 2: sort by size, rename
  ─────────────────────                    ────────────────────────────
                    ┌── u2 (  412 cells) → c3u2 ─┐        ┌ c3_0 = c3u5 (8,021)  main core
  cluster 3 ────────┼── u5 (8,021 cells) → c3u5 ─┼───────▶┤ c3_1 = c3u2 (  412)  minor sibling
  (8,800 cells)     └── u9 (  367 cells) → c3u9 ─┘        └ c3_2 = c3u9 (  367)  minor sibling

A minor sibling is a small fragment carrying the same RNA label as its main core — "sibling" stresses that it belongs to the same parent cluster, not that it is some other small cluster elsewhere on the map.

The fragments table keeps both identities per row (subcluster = the ranked name, umap_label = the UMAP side of the product). Ranked names are byte-compatible with standissect's (c{cluster}_{rank}, rank 0 = main core), so outputs interoperate.

Usage

import anndata as ad
from standissect_lite import dissect_partition

adata = ad.read_h5ad("data.h5ad")   # needs obs['leiden'] + obsm['X_umap']
res = dissect_partition(adata, cluster_col="leiden", umap_key="X_umap")

# or hand a precomputed UMAP matrix directly (obsm not consulted;
# one row per cell in adata order, >=2 columns):
res = dissect_partition(adata, cluster_col="leiden", umap_Nx2_mat=my_umap)

res.fragments[res.fragments.is_minor_sibling]   # minor siblings: parent, size, rank, ...
res.overlap                             # RNA × UMAP cell-count crosstab
res.labels                              # per-cell: umap_cluster / subcluster / rank
res.info                                # UMAP-side resolution search diagnostics

dissect_partition is a pure function: it never modifies adata. Write-back is the caller's explicit one-liner:

adata.obs["original_cluster_split"] = res.labels["subcluster"]

The lower-level umap_leiden_partition(umap_xy, ...) is also exported for callers holding bare coordinates. All tuning knobs are documented in the dissect_partition docstring; defaults are sane and rarely worth touching.

Install

pip install -e /path/to/standissect-lite     # or add the parent to PYTHONPATH

Dependencies: numpy, pandas, scikit-learn, python-igraph, leidenalg, anndata. No scanpy.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

standissect_lite-0.1.0.tar.gz (13.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

standissect_lite-0.1.0-py3-none-any.whl (11.3 kB view details)

Uploaded Python 3

File details

Details for the file standissect_lite-0.1.0.tar.gz.

File metadata

  • Download URL: standissect_lite-0.1.0.tar.gz
  • Upload date:
  • Size: 13.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.1

File hashes

Hashes for standissect_lite-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e2f090aed0dad389529acc18861c33ae584a2cc28ada059f1cb9b9034b61dde5
MD5 30e92d79131d8f4c897e4b9db296be4d
BLAKE2b-256 516f3c7799ca99e7fdf34971ff5b9142058e69474f16eb4f43c7c74ddcc7acd4

See more details on using hashes here.

File details

Details for the file standissect_lite-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for standissect_lite-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 22606b538e7f6b22e34bb177696ded7b496447340e960d31d4894295d995d324
MD5 f8899a22bf87a2bf8589e4839a0d1159
BLAKE2b-256 d495a46b2968120dd54f2e1ed7a73c040623cda93a41e90d3e60ae7b457d0114

See more details on using hashes here.

Release history Release notifications | RSS feed

0.2.0

2 files

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page