Subsampling#

subsample_cells() gives the cells a Cellucid subsample keeps, as rows of obs: the cells the web app opens for the same request (Open data, Cells to open), and the cells R’s cellucid_subsample_cells() gives. Use it to take in a notebook exactly the cells the viewer showed, or to choose cells the same way before opening.

import cellucid

kept = cellucid.subsample_cells(adata, fraction=0.1, seed=0)                     # uniform
kept = cellucid.subsample_cells(adata, 50_000, method="stratified", groupby="cell_type")
kept = cellucid.subsample_cells(adata, fraction=0.05, method="spatial", basis="X_umap")
kept = cellucid.subsample_cells(adata.n_obs, fraction=0.1, method="blocks", block_size=2048)
small = adata[kept].copy()
  • The same data, method, size and seed give the same cells, in all three implementations: they follow one specification (Subsampling specification) and one shared conformance fixture.

  • uniform and blocks are nested: with one seed, a smaller subsample is inside a larger one.

  • Any count from 1 is a selection. The web app opens a subsample of at least 2 cells, since one cell has no coordinate variation to draw (At least two cells).

  • blocks needs block_size: the web app derives it from the file’s chunk layout and shows it with the subsample (Session › Dataset › Details).

  • A size of every cell or more returns every cell.

  • The rows of data are taken as the cells’ original positions, so adata[kept] holds the cells the viewer opens. An object read from a Cellucid-ready file in priority order (anndata.read_zarr of prepare()’s output, any sample dataset) holds them in its stored order: it is refused with a ValueError until restore_original_order() puts the cells back, as viewer.pull(), viewer.subset() and applying a session refuse it. (Its first k rows are the uniform subsample of k cells under the file’s seed, uns['cellucid']['priority']['seed'].)

adata = cellucid.restore_original_order(anndata.read_zarr("pbmc.zarr"))
kept = cellucid.subsample_cells(adata, fraction=0.1, seed=0)

API reference#

cellucid.subsample_cells(data, n_cells=None, *, fraction=None, method='uniform', seed=0, groupby=None, allocation='proportional', min_per_group=0, block_size=None, basis=None, columns=(0, 1), grid_size=32)[source]#

The cells a Cellucid subsample keeps, as original positions.

The same request opens the same cells in the web app (Open data, Cells to open) and in R (cellucid_subsample_cells()): every implementation follows one specification and is checked against one conformance fixture.

Parameters:
  • data (Any) – An AnnData, a MuData, or the cell count n_obs itself (enough for uniform and blocks). Its rows are the cells’ original positions: an object read from a Cellucid-ready file in priority order (anndata.read_zarr of prepare()’s output) is refused until restore_original_order() puts it back, as pull, subset and a session refuse it.

  • n_cells (int | None) – How many cells to keep; or give fraction. A count of every cell or more keeps every cell.

  • fraction (float | None) – The share of cells to keep, in (0, 1]; the count is n_obs × fraction rounded half up, at least 1, computed exactly from the fraction’s shortest decimal text (repr), never as a binary64 product, as the web app and R compute it. Any count from 1 is a selection here; the web app opens a subsample of at least 2 cells, since one cell has no coordinate variation to draw.

  • method (Literal['uniform', 'blocks', 'stratified', 'spatial']) – "uniform" (every cell alike), "blocks" (runs of block_size neighbouring cells in file order, kept together), "stratified" (split over the categories of groupby), or "spatial" (split over the occupied boxes of a grid_size grid on basis, balanced, so sparse regions keep their cells).

  • seed (int) – A uint32. The same seed keeps the same cells; with uniform and blocks a smaller subsample is inside a larger one.

  • groupby (Any) – stratified: an obs column name, or one value per cell. A categorical keeps its categories’ order; plain values (text) become categories in code-point order, as in the web app and R. Cells without a category are one more stratum.

  • allocation (Literal['proportional', 'balanced']) – stratified: "proportional" (largest remainder) or "balanced" (equal shares, water-filled).

  • min_per_group (int) – stratified: each category first gets this many cells (or all it has).

  • block_size (int | None) – blocks: cells per block. The web app derives it from the file’s chunk layout and shows it; give that value to reproduce its cells.

  • basis (Any) – spatial: an obsm key, or an array of coordinates (one row per cell).

  • columns (Sequence[int]) – spatial: the embedding columns used, one to three.

  • grid_size (int) – spatial: boxes per axis.

Returns:

The kept cells’ positions (rows of obs), ascending, int64.

Return type:

numpy.ndarray

Examples

>>> kept = cellucid.subsample_cells(adata, fraction=0.1, seed=0)
>>> small = adata[kept].copy()

A file prepare() wrote holds its cells in priority order; put them back first:

>>> adata = cellucid.restore_original_order(anndata.read_zarr("pbmc.zarr"))
>>> kept = cellucid.subsample_cells(adata, fraction=0.1, seed=0)

See also#