scanpy.pp.hashsolo#

scanpy.pp.hashsolo(adata, hashes, *, priors=(0.01, 0.8, 0.19), pre_existing_clusters=None, n_noise_barcodes=None, out=False)[source]#

Probabilistic demultiplexing of cell hashing data using HashSolo [Bernstein et al., 2020].

Array type support#

Array type

supported

… experimentally in dask Array

numpy.ndarray

✅

❌

scipy.sparse.{csr,csc}_{array,matrix}

✅

❌

Parameters:
adata AnnData

The (annotated) data matrix of shape n_obs × n_vars. Rows correspond to cells and columns to genes.

hashes MultiAcc | Collection[AdRef] | Collection[str]

References to the vectors holding the cell hashing counts, e.g. A.obs[["Hash1", "Hash2"]] for columns in obs or A.X[:, ["Hash1", "Hash2"]] for hashing barcodes among the var_names. A MultiAcc such as A.obsm["hto"] refers to all columns of what it points to, named after the DataFrame’s columns or, for a plain array, its column positions.

priors tuple[float, float, float] (default: (0.01, 0.8, 0.19))

Prior probabilities of each hypothesis, in the order [negative, singlet, doublet]. The default is set to [0.01, 0.8, 0.19] assuming barcode counts are from cells that have passed QC in the transcriptome space, e.g. UMI counts, pct mito reads, etc.

pre_existing_clusters AdRef | str | None (default: None)

Reference to a vector of pre-existing cluster assignments (e.g. Leiden clusters or cell types, but not batch assignments). If provided, demultiplexing is performed separately for each cluster.

n_noise_barcodes int | None (default: None)

The number of barcodes used to create the noise distribution. Defaults to len(hashes) - 2.

out AdRef[Idx2D | int, AnnData] | str | HashsoloOut | bool (default: False)

Where to write the outputs. A single accessor writes classification to it and names the others after its key k: k in kinds of places no other output goes to, else k_{name}, e.g. .obsp['k_distances'] next to .obsp['k']. Outputs that aren’t written by default stay unwritten. A mapping from output names to accessors writes only the outputs it names, each to a different place, e.g. {'classification': A.obs['hto']}. strs are anndata.acc.AdAcc.resolve()d. If True, they are returned as a HashsoloResult instead of written. If False, they are written to their default locations. The outputs are:

classification

Classification of each cell. By default written to A.obs['hashsolo'].

probabilities

Probabilities of each hypothesis. By default written to A.obsm['hashsolo'].

Return type:

HashsoloResult | None

Returns:

Returns the outputs as a HashsoloResult if out=True, else None. By default sets the following fields (see out for others):

adata.obs['hashsolo']Categorical (shape (n_obs,))

Classification of each cell: the name of one of the hashes, "Negative", or "Doublet".

adata.obsm['hashsolo']DataFrame (shape (n_obs, 3))

Probability of the negative, singlet, and doublet hypothesis.

Examples

Simulate 300 cells, each carrying one of 3 hashtag oligos:

>>> import numpy as np
>>> import scanpy as sc
>>> from anndata import AnnData
>>> from anndata.acc import A
>>>
>>> rng = np.random.default_rng(0)
>>> hto = rng.poisson(20, size=(300, 3))  # ambient background
>>> hto[np.arange(300), np.arange(300) % 3] = rng.poisson(1000, 300)  # signal
>>> adata = AnnData(rng.poisson(1, (300, 5)).astype("f4"), obsm=dict(hto=hto))

A MultiAcc demultiplexes using every column it points to. A plain array has no column names, so the barcodes are named after their positions:

>>> sc.pp.hashsolo(adata, A.obsm["hto"])
>>> adata.obs["hashsolo"].cat.categories.astype("string")
Index(['0', '1', '2'], dtype='string')
>>> adata.obs["hashsolo"].value_counts().tolist()
[100, 100, 100]

The same counts as obs columns (as in a Cell Ranger run’s “Multiplexing Capture” features), referenced one by one:

>>> adata.obs[["Hash1", "Hash2", "Hash3"]] = hto
>>> sc.pp.hashsolo(adata, A.obs[["Hash1", "Hash2", "Hash3"]], out=A.obs["hs2"])
>>> adata.obs["hs2"].cat.categories.astype("string")
Index(['Hash1', 'Hash2', 'Hash3'], dtype='string')