ecotyper.api

scverse-style entry points: recovery(), discovery(), infer_data_type().

These take anndata.AnnData objects as produced by scanpy/squidpy (sc.read_10x_mtx, sc.read_visium, sc.read_h5ad…), with dense or sparse X or a layer, and store results in adata.obs/obsm/uns under key_added (default "ecotyper"). They wrap the exact engine in ecotyper.workflows, so results equal the file-based workflows (and R).

Data types

"bulk" samples x genes (bulk RNA-seq or microarray); "scRNA" cells x genes, raw-scale (counts/TPM), obs with a cell type column; "visium" spots x genes (10x Visium), with CIBERSORTx cell type fractions; "profiles" (discovery only) per-cell-type expression profiles: a dict {cell type: AnnData (samples x genes)} (CIBERSORTx HiRes output or presorted/purified populations).

Functions

discovery(data, *[, data_type, layer, ...])

Discover cell states and ecotypes; returns an in-memory EcoTyperModel.

infer_data_type(adata, *[, cell_type_key])

Guess the data type of adata.

recovery(adata[, model, data_type, layer, ...])

Recover cell states and ecotypes defined by model in new data.

ecotyper.api.infer_data_type(adata, *, cell_type_key='CellType')[source]

Guess the data type of adata.

  • a dict of per-cell-type objects → "profiles";

  • obsm["spatial"] or uns["spatial"] (squidpy/scanpy Visium) → "visium";

  • obs[cell_type_key] present → "scRNA";

  • otherwise → "bulk".

Raises ValueError when the signals conflict (spatial coordinates and a per-observation cell type column, as in imaging-based single-cell spatial data) or when the data look single-cell (sparse, many observations) but there is no cell type column. Pass data_type= explicitly in those cases.

Parameters:

cell_type_key (str)

Return type:

Literal[‘bulk’, ‘scRNA’, ‘visium’, ‘profiles’]

ecotyper.api.recovery(adata, model='Carcinoma', *, data_type=None, layer=None, cell_type_key='CellType', sample_key='Sample', fractions=None, malignant_cell='Epithelial.cells', library_id=None, subsample=-1, key_added='ecotyper', copy=False, seed=42, n_jobs=1, r_exact=True, exact=True)[source]

Recover cell states and ecotypes defined by model in new data.

Parameters:
  • adata – Observations (samples, cells or spots) x genes. X (or layer) holds expression on the raw scale (counts, TPM, or normalised microarray values); dense and sparse matrices are accepted. Bulk data with values > 50 are log2(x+1)-transformed as in R.

  • model (EcoTyperModel | str) – An EcoTyperModel (e.g. from discovery()), a built-in model name ("Carcinoma", "Lymphoma") or a path to a saved model.

  • data_type (Literal['bulk', 'scRNA', 'visium', 'profiles'] | None) – "bulk", "scRNA" or "visium"; inferred with infer_data_type() when omitted.

  • cell_type_key (str) – scRNA: obs column with cell type labels. They must match the model’s cell type names (model.cell_type_order); cells of other types are ignored.

  • sample_key (str | None) – scRNA: obs column with the sample of each cell. Needed for ecotype abundances per sample.

  • fractions (DataFrame | str | None) – Visium: CIBERSORTx cell type fractions per spot, a DataFrame (index: obs_names; columns: cell types, extra CIBERSORTx columns such as P.value are dropped) or the name of an obsm entry.

  • malignant_cell (str | None) – Visium: the cell type treated as malignant/background fraction (R’s Malignant cell type); None for none.

  • library_id (str | None) – Visium: sample name used in the output (default: the single key of uns["spatial"], else "Visium").

  • subsample (int) – scRNA: maximum number of cells per cell type (R’s -s; values below 50 keep all cells).

  • key_added (str) – Prefix of the result keys.

  • copy (bool) – Return a modified copy instead of writing into adata.

  • seed (int) – Random seed of NMF prediction (R’s set.seed), number of worker processes, and R-exact arithmetic (keep True for results identical to R).

  • n_jobs (int) – Random seed of NMF prediction (R’s set.seed), number of worker processes, and R-exact arithmetic (keep True for results identical to R).

  • r_exact (bool) – Random seed of NMF prediction (R’s set.seed), number of worker processes, and R-exact arithmetic (keep True for results identical to R).

  • exact (bool) – False selects the fast mode: NMF with BLAS matrix products and no emulation of R’s text round trips. Results match R’s to ~1e-12 relative and state/ecotype assignments were identical on the tutorial data, but bit-identity with R is not guaranteed (see the docs, “Fast mode”).

  • layer (str | None)

Returns:

  • None (or the copy with copy=True). Results

  • obs[f"{key}_state_{cell type}"] – cell state per observation (bulk/Visium: dominant state; scRNA: the state of each cell of that type, NaN for other cells);

  • obsm[f"{key}_abundance_{cell type}"] – cell state abundances (columns S01…);

  • obs[f"{key}_ecotype"] – bulk: assigned ecotype (Unassigned if not significant), with obs[f"{key}_max_ecotype"] and obs[f"{key}_ecotype_q"]; scRNA: ecotype of each cell’s state;

  • obsm[f"{key}_ecotype_abundance"] – bulk and Visium: ecotype abundances per observation;

  • obsm[f"{key}_state_abundance"] – Visium: fraction-weighted state abundances per spot (columns <cell type>_<state>);

  • uns[key] – parameters, NMF iterations per cell type, and for scRNA the ecotype abundances (ecotype_abundance, samples x ecotypes) and assignment (ecotype_assignment) per sample.

ecotyper.api.discovery(data, *, data_type=None, layer=None, cell_type_key='CellType', sample_key='Sample', annotation=None, name='custom', filter_genes='cell type specific', scale_column=None, max_states=20, restarts=5, cophenetic_cutoff=None, p_value_cutoff=1.0, min_states=3, key_added='ecotyper', n_jobs=1, r_exact=True, verbose=True, exact=True, nmf_method='brunet')[source]

Discover cell states and ecotypes; returns an in-memory EcoTyperModel.

Parameters:
  • data –

    • scRNA-seq: AnnData (cells x genes, raw-scale expression) with cell type labels in obs[cell_type_key] and samples in obs[sample_key];

    • per-cell-type profiles: {cell type: AnnData} (samples x genes, the same samples in every object), e.g. CIBERSORTx HiRes purified profiles or presorted populations. Sample annotation from annotation (column ID plus covariates) or the obs of the first object.

  • data_type (Literal['bulk', 'scRNA', 'visium', 'profiles'] | None) – "scRNA" or "profiles"; inferred when omitted. Bulk discovery from mixtures needs CIBERSORTx (not part of this package): run it and pass the HiRes profiles as "profiles".

  • filter_genes (str | int) – scRNA gene filter (R’s Filter genes): "cell type specific", "no filter", or the number of top variable genes.

  • scale_column (str | None) – Annotation column to scale within (R’s Scale column), e.g. a batch.

  • max_states (int) – NMF and ecotype parameters as in the R configuration files. cophenetic_cutoff defaults to 0.975 (scRNA) and 0.95 (profiles).

  • restarts (int) – NMF and ecotype parameters as in the R configuration files. cophenetic_cutoff defaults to 0.975 (scRNA) and 0.95 (profiles).

  • cophenetic_cutoff (float | None) – NMF and ecotype parameters as in the R configuration files. cophenetic_cutoff defaults to 0.975 (scRNA) and 0.95 (profiles).

  • p_value_cutoff (float) – NMF and ecotype parameters as in the R configuration files. cophenetic_cutoff defaults to 0.975 (scRNA) and 0.95 (profiles).

  • min_states (int) – NMF and ecotype parameters as in the R configuration files. cophenetic_cutoff defaults to 0.975 (scRNA) and 0.95 (profiles).

  • key_added (str) – scRNA: prefix of the per-cell results written to data.obs.

  • exact (bool) – False selects the fast mode (BLAS NMF updates, no R text round trips); see recovery().

  • nmf_method (str) – "brunet" (default, EcoTyper’s KL multiplicative updates) or "cd": Frobenius-loss coordinate descent from scikit-learn, an opt-in extension that is not equivalent to EcoTyper (states can differ; see the docs, “Alternative NMF solver”).

  • layer (str | None)

  • cell_type_key (str)

  • sample_key (str)

  • annotation (DataFrame | None)

  • name (str)

  • n_jobs (int)

  • r_exact (bool)

  • verbose (bool)

Return type:

EcoTyperModel

Notes

The model keeps the full discovery result in model.discovery_result. model.save(path) writes it in the R layout; for the complete R output tree use ecotyper.workflows.write_discovery_scrna() / ecotyper.workflows.write_discovery() on model.discovery_result.