Skip to content

phenotype

phenotype

phenotype(
    data,
    phenotype,
    gate=0.5,
    label="phenotype",
    imageId="imageid",
    phenoThresholdPercent=None,
    phenoThresholdAbs=None,
    layer=None,
    streamData=False,
    verbose=True,
    maxWorkers=None,
    outputDir=None,
    sdataTable=None,
)

Assign cell types from a hierarchical gating workflow.

Phenotyping is driven by a CSV you write once:

ELANE CD57 CD45 ECAD
all ECAD+ pos
all Immune pos
Immune NK cells allpos
  • Column 1 is the parent group. all means every cell; any other value means "only cells already labelled that, at a previous level".
  • Column 2 is the cell type to assign.
  • The remaining columns are markers, and the cells hold gating keywords: pos, neg, anypos, anyneg, allpos, allneg.

Groups are processed in order, so Immune is resolved before NK cells refines it. At each level, cells that match the group but none of its children are held as a temporary "<group>-rest" label; when consolidation runs at the end, those rest labels collapse back to the last real phenotype — a cell that ends up Immune-rest is reported as Immune, and a cell with no phenotype at all as Unknown.

Scores are computed per marker: positive keywords read the matrix directly, negative keywords read 1 - matrix, which is why the input should be rescaled first. Marker scoring runs across a ThreadPoolExecutor.

Parameters:

Name Type Description Default
data (AnnData | SpatialData | str, required)

The cell table. An AnnData, a path to an .h5ad file, a SpatialData object, or a path to a .zarr SpatialData store.

required
phenotype (DataFrame | DataFrame | str, required)

The gating workflow: a path to the CSV, or the table itself.

required
gate float

The score above which a cell counts as positive. 0.5 is the boundary that sp.pp.rescale produces.

0.5
label str

Column in obs the cell type labels are written to.

'phenotype'
imageId str

Column in obs holding image identifiers.

'imageid'
phenoThresholdPercent float

Drop any phenotype that accounts for less than this percentage of cells, relabelling those cells 'Unknown'. Useful for suppressing cell types called from a handful of cells.

None
phenoThresholdAbs int

Same, but as an absolute cell count.

None
layer str

Which matrix to score. 'raw' uses .raw.X, None uses .X, any other string names a key in .layers.

None
maxWorkers int

Cap on parallel workers. Defaults to max(1, cpu_count() - 1). Lower it to cut peak memory.

None
verbose bool

Print progress messages.

True
outputDir str

Directory to write the updated object to. With None the object is returned instead.

None
streamData bool

Run out of core against an .h5ad path with CAP-AnnData, reading only the sections this function needs and writing back only what it changes. Requires data to be a path; the file is updated in place and None is returned.

False
sdataTable str

Which SpatialData table to work on. Ignored for AnnData input, and optional when the store has exactly one table.

None

Returns:

Name Type Description
adata AnnData | SpatialData | None

The updated object with obs[label] holding the cell types. None in streaming mode.

Example
adata = sp.pp.rescale(adata, gate="manual_gates.csv")
adata = sp.tl.phenotype(adata, phenotype="phenotype_workflow.csv")
adata.obs["phenotype"].value_counts()

# Suppress cell types called from fewer than 1% of cells.
adata = sp.tl.phenotype(
    adata, phenotype="phenotype_workflow.csv", phenoThresholdPercent=1
)

# Out of core.
sp.tl.phenotype("big.h5ad", phenotype="phenotype_workflow.csv", streamData=True)