API reference¶
The scMultiBench API (imported as multibench, aliased
throughout the docs as mtb) exposes a small, flat, free-function API organised
into a handful of namespaces:
mtb.*— the top-level surface:runa method,evaluatean output,to_longto reshape it,load_resultsfrom the published benchmark, and discovery helpers (list_methods,list_tasks,find_methods,method_info,inputs_for,labels_for,available_datasets).mtb.plot.*— scIB-style figures (bubble).mtb.eval.*— the evaluation pipeline (evaluate,to_long).mtb.io.*— the canonical-format adapter (to_canonical,read_canonical).mtb.catalog.*— typed views of the paper's metadata tables.mtb.config.*— resolved paths and on-disk token maps.mtb.env.*— per-method conda environment recipes and provisioning plans.
mtb.run returns a RunResult; its output flows into
mtb.evaluate, whose wide frame is reshaped by
mtb.eval.to_long into the same tidy long frame that
mtb.load_results returns and mtb.plot.bubble
consumes.
Method environments
Running a method shells out to the conda environment it shares with other
compatible tools via conda run -n <env> <cmd>, where <env> is
mtb.env.group_for(method) — the same env
mtb.env.plan provisions (overridable through
cmd_template). The original method scripts are never modified —
multibench only builds the command, converts inputs to the canonical
.h5, and loads the typed output.
Top-level functions¶
mtb.run¶
mtb.run(method: str, category: str, task: str = "clustering", *, inputs: dict, out_dir: str, params: dict | None = None, convert: bool = True, cmd_template: str | None = None, repo_path: Path | None = None) -> RunResult
Build a method variant's command, wrap it (default "conda run -n {env} {cmd}"),
run it in out_dir, and load the typed output. inputs is a {modality_role:
path} dict; non-canonical modality inputs are auto-converted to the canonical
scMultiBench .h5 unless convert=False. Auxiliary roles (data_dir,
source_data, target_data, source_cty, target_cty, out_dir) are passed
through verbatim. Returns a RunResult.
Parameters
method(str) — registry method id (seelist_methods).category(str) — one ofvertical,diagonal,mosaic,cross; drives variant selection together with the supplied modalities.task(str) — reserved for future per-task dispatch; not used for variant selection in v1.inputs(dict) —{modality_role: path}, e.g.{"rna1": ..., "atac_gas1": ...}.out_dir(str) — working directory; created if missing.params(dict | None) — extra method hyperparameters merged into the command.convert(bool) — convert non-aux inputs to the canonical.h5(defaultTrue).cmd_template(str | None) — command wrapper;Noneuses the method's env viaconda run -n {env} {cmd}.repo_path(Path | None) — path to the reference scMultiBench repo; defaults toconfig.DEFAULT.repo_path.
mtb.evaluate¶
mtb.evaluate(output, category: str, task: str = "clustering", labels=None, clustering=None, batch=None, metric_set: str = "scib") -> pd.DataFrame
Compute scIB metrics on a run output, returning a metric.csv-shaped frame
(index = metric, single Value column). v1 supports metric_set="scib" with
task in {clustering, batch, all}. Clustering metrics require both labels
(cell types) and clustering; batch/all additionally require batch. This
is re-exported from mtb.eval.evaluate.
Parameters
output— a run embedding (np.ndarray) or a path/handle readable as one.category(str) — reserved for future per-category metric dispatch; accepted but unused in v1.task(str) —clustering,batch, orall.labels— cell-type labels (np.ndarrayor readable source).clustering— predicted cluster assignments.batch— batch labels (required forbatch/all).metric_set(str) — only"scib"is wired in v1.
Graceful degradation
Metrics whose external dependency is unavailable return NaN with a warning
rather than failing the call: cLISI / iLISI need a compiled LISI binary,
and kBET needs rpy2. All other scIB metrics (ARI, NMI, ASW, iASW, iF1,
ASW_batch, GC) compute in pure Python.
mtb.load_results¶
mtb.load_results(category: str, task: str = "clustering", metric_set: str = "scib", dataset: str | None = None, method: str | None = None, metric: list[str] | str | None = None, clustering: str = "default", result_path: Path | str | None = None) -> pd.DataFrame
Return a tidy long frame (metric, value, method, dataset, category) of the
published benchmark metric tables, with metric codes and method ids
canonicalised. Optionally filter by dataset, method, and metric. When the
default-clustering correction file metric_asw_iasw_if1.csv is present, its
corrected ASW / iASW / iF1 values override those in metric.csv.
Published-metric availability
Only metric_set="scib" is wired in v1. Published scib metric tables
exist for the vertical, cross, and diagonal categories; mosaic
metrics are not published, so load_results(category="mosaic") raises
FileNotFoundError (the methods still run, there is just no published
table to load).
Parameters
category(str) —vertical,diagonal,mosaic, orcross.task(str) — task token (v1 results are clustering/batch underscib).metric_set(str) — only"scib"is wired in v1.dataset(str | None) — restrict to a single dataset id (e.g."D12").method(str | None) — restrict to one method (any known spelling).metric(list[str] | str | None) — restrict to one or more metric codes.clustering(str) —default,louvain, orkmeans.result_path(Path | str | None) — overrideconfig.DEFAULT.result_path.
mtb.available_datasets¶
mtb.available_datasets(category: str, metric_set: str = "scib", result_path: Path | str | None = None) -> list[str]
Return the dataset ids that have published metric_set results for a category —
exactly the datasets load_results can load. Returns []
when the category has no published metrics (e.g. mosaic). Use this to discover
what is loadable before calling load_results.
mtb.list_methods¶
mtb.list_methods(category: str | None = None, task: str | None = None, runnable: bool | None = None) -> list[str]
Return the registry method ids, optionally filtered to those declaring a given
category and/or task. Every registry method is wired to run; runnable
remains as a filter for forward compatibility (None, the default, returns
all).
mtb.list_tasks¶
Return the sorted set of tasks declared across all method specs.
mtb.find_methods¶
mtb.find_methods(category: str | None = None, task: str | None = None, needs_labels: bool | None = None, atac: str | None = None, modalities: list[str] | set[str] | None = None, runnable: bool | None = None) -> list[str]
Return method ids matching every supplied filter. modalities keeps only
methods that consume all of the requested base modality types (e.g.
["rna", "atac"]); needs_labels and atac filter by the method's declared
requirements.
Parameters
category(str | None) — integration category the method must declare.task(str | None) — task the method must declare.needs_labels(bool | None) — whether the method requires cell-type labels.atac(str | None) — required ATAC representation — exact match, one of"peak"or"gene_activity"(not a boolean).modalities(list[str] | set[str] | None) — modality types the method must consume, e.g.["rna", "atac"]. Derived from a method's variants.runnable(bool | None) — filter on whether the method has a runnable variant; every registry method currently does.
mtb.method_info¶
Return a flat dict combining the registry spec (id, language, categories,
tasks, env, atac, needs_labels, status, setup_hint, variants) with
optional catalog metadata (deep_learning, output) when files_dir is given.
env is the conda environment mtb.run actually executes the method
in — the resolved group_for env (a shared group env, or the
method's own scmb_<method> env).
mtb.inputs_for¶
mtb.inputs_for(dataset: str, method: str, category: str, modalities: list[str] | set[str] | None = None, data_path: Path | str | None = None, check: bool = False) -> dict
Resolve a catalog dataset id + method to concrete {modality_role: path} input
paths. The dataset tree is flat (<data_path>/<dataset>/<file>); each role
is resolved to the file actually present in that directory — the role token or
a known alias (atac_peak → peak.h5, atac_gas → atac.h5), falling back to
<role>.h5 when no candidate exists. When modalities is omitted and the
method has exactly one variant for the category, that variant is used; if
several match, a ValueError lists the modality-sets and asks you to
disambiguate with modalities=. Pass check=True to raise FileNotFoundError
(listing what is present) if any resolved file is missing, rather than returning
a best-effort path that only fails later inside run. Use
labels_for to get the matching cell-type label files for
evaluate.
Parameters
dataset(str) — catalog dataset id (e.g."D35").method(str) — registry method id.category(str) — integration category.modalities(list[str] | set[str] | None) — exact modality-set to select a variant.data_path(Path | str | None) — overrideconfig.DEFAULT.data_path.check(bool) — ifTrue, raiseFileNotFoundErrorwhen a resolved input file does not exist.
mtb.labels_for¶
Return {name: path} of the cell-type label CSVs for a dataset — the
*cty*.csv files in the (flat) dataset directory, under their dataset-specific
names (cty.csv, rna_cty.csv, cty1.csv, …), excluding tool-specific
*_scjoint* reformats. Use these as the labels= argument to
mtb.evaluate. Raises FileNotFoundError if the dataset
directory is absent.
Parameters
dataset(str) — catalog dataset id.data_path(Path | str | None) — overrideconfig.DEFAULT.data_path.
Benchmark workflow¶
The four category tutorials are built on these functions.
mtb.scan¶
mtb.scan(dataset: str, category: str | None = None,
data_path: Path | str | None = None) -> pd.DataFrame
Report every method that can run on dataset, and why the rest cannot: one row
per (method, category, modalities) with runnable and, when it is not, a
reason. modalities is a +-joined string here (e.g. "rna+adt");
run_all / inputs_for take it as a list, so split on "+".
mtb.run_all¶
mtb.run_all(dataset: str, category: str, *, out_dir, modalities=None,
methods=None, params=None, data_path=None, evaluate=True,
dry_run=False, verbose=True, timeout=None,
skip_existing=False) -> BatchResult
Run every applicable method (or the methods= subset) on dataset end to end
- inputs, the method's own conda env, output loading, metrics - and collect
everything in a BatchResult. dataset is the directory NAME of your data;
data_path is the folder that contains it (defaults to the configured data
root). A method that fails becomes a row in .failures, not an exception;
timeout= bounds each method's whole step; skip_existing=True resumes an
interrupted sweep.
BatchResult: .summary (one row per method), .long (tidy
metric/value frame - the input to mtb.plot.bubble), .failures, .plot()
(bubble figure of every scored method) and .save(out_dir) which writes
summary.csv, long.csv and failures.csv.
mtb.params_for¶
The tunable hyperparameters a method's variant exposes (with defaults), plus
the fixed arguments the wrapper controls. Multi-variant methods need
modalities= to pick the variant.
mtb.describe_layout¶
Human-readable description of the on-disk data layout each category expects.
mtb.sweep¶
mtb.sweep(dataset: str, category: str, method: str, param: str, values, *,
out_dir, modalities=None, data_path=None, timeout=None,
verbose=True) -> pd.DataFrame
Run ONE method repeatedly over a range of one hyperparameter, one output directory per value, and return the collected metric rows.
mtb.plot.*¶
mtb.plot.bubble¶
mtb.plot.bubble(long_df, *, metrics=None, methods=None, order=None, aggregate="dataset", cmap="Blues", title=None, save=None) -> matplotlib.figure.Figure
Render an scIB-style bubble table from a tidy long frame: each circle's radius
encodes the metric rank and its fill encodes the (min-max normalised) value, with
methods sorted by an overall column shown first. aggregate="dataset" averages
values across datasets; aggregate="summary" averages ranks across datasets.
If save is given, the figure is written there (bbox_inches="tight"). Returns
the matplotlib.Figure.
Parameters
long_df(pd.DataFrame) — long frame withmetric, value, method, datasetcolumns.metrics(list[str] | None) — metric columns to include, in order.methods(list[str] | None) — restrict to these methods.order(list[str] | None) — explicit row order (overrides the overall sort).aggregate(str) —"dataset"(mean value) or"summary"(mean rank).cmap(str) — matplotlib colormap for the fill (default"Blues").title(str | None) — axes title.save(str | None) — output path; e.g."fig.pdf".
Callable namespace
mtb.plot.bubble is callable for the common path and exposes the
underlying builders — mtb.plot.bubble.build_table(...) and
mtb.plot.bubble.render(...) reach the module functions directly. The same
callables are also exported on the namespace itself —
mtb.plot.plot_bubble, mtb.plot.build_table, mtb.plot.render — for
discoverability.
mtb.eval.*¶
mtb.eval.evaluate¶
mtb.eval.evaluate(output, category: str, task: str = "clustering", labels=None, clustering=None, batch=None, metric_set: str = "scib") -> pd.DataFrame
The evaluation entry point, also re-exported as mtb.evaluate.
See that entry for the full parameter list and the LISI/kBET graceful-NaN
behaviour.
mtb.eval.to_long¶
Reshape an evaluate wide frame (index = metric, column
Value) into the long frame (metric, value, method, dataset, category) that
load_results and plot.bubble consume,
canonicalising metric codes along the way. This is the bridge from the
evaluate (wide) output to the load_results/plot.bubble (long) shape, and is
also re-exported at the top level as mtb.to_long.
Parameters
value_df(pd.DataFrame) — anevaluate()result (index = metric,Valuecolumn).method(str) — method id to stamp onto every row.dataset(str) — dataset id to stamp onto every row.category(str) — integration category to stamp onto every row.
mtb.io.*¶
The input-format adapter to and from the canonical scMultiBench .h5 (an HDF5
file with matrix/data of shape features × cells, plus matrix/features and
matrix/barcodes).
mtb.io.to_canonical¶
mtb.io.to_canonical(src, out: Path | str | None = None, modality: str | None = None, convert: bool = True) -> Path
Convert src to a canonical .h5 and return its path. Accepts .h5ad,
.csv / .tsv, .loom, or an in-memory AnnData. An already-canonical
path is returned as-is when no conversion is needed; otherwise out is required.
Parameters
src— source data (path orAnnData).out(Path | str | None) — destination.h5; required unlesssrcis already canonical.modality(str | None) — optional modality hint.convert(bool) — force conversion even for a canonical source (defaultTrue).
mtb.io.read_canonical¶
Read a canonical .h5 back into an AnnData (cells × genes), restoring
var_names from matrix/features and obs_names from matrix/barcodes.
mtb.catalog.*¶
Typed views of the paper's metadata CSVs, plus the canonicalisers used throughout the API.
mtb.catalog.methods¶
The methods table with normalised columns (method, canonical_id, language,
deep_learning, atac, output, needs_labels) and list-valued categories /
tasks. Defaults to config.DEFAULT.files_path.
mtb.catalog.datasets¶
The datasets table with a derived simulated flag (true for ids beginning
SD).
mtb.catalog.metrics¶
The metric-details table (whitespace-normalised column names).
mtb.catalog.canonical_id¶
Return the canonical registry method id for any known display or result-dir
spelling (e.g. "seurat v5" → "Seurat_v5", "mofa+" → "MOFA2").
mtb.catalog.canonical_metric¶
Canonicalise a raw metric short-code (e.g. "ari" → "ARI", "kbet" →
"kBET"); returns None for blank or empty codes.
mtb.config.*¶
mtb.config.Config¶
@dataclass
class Config:
result_path: Path # published benchmark metric tables
files_path: Path # metadata CSVs (method/dataset/metric)
repo_path: Path # reference scMultiBench repo (method entrypoints)
data_path: Path # resolved input datasets
Resolved filesystem paths. Override any field to point at custom locations. A
module-level default instance is exposed as mtb.config.DEFAULT; callers may
replace its fields in place.
mtb.config.category_folder¶
Map a clean category token to the benchmark's space-named result folder (e.g.
"vertical" → "vertical integration"). Raises ValueError for an unknown
token.
mtb.config.metric_set_dir¶
Map a metric-set token to its top-level result directory (e.g. "scib" →
"scib_metric"). Raises ValueError for an unknown token.
mtb.env.*¶
Helpers for the conda environments that mtb.run orchestrates. They
describe how to provision an env, they do not create it for you — the recipes
are emitted for you to apply.
Two provisioning routes
There are two ways to provision, and run uses the shared group env by
default. (1) Group (what run uses): plan /
groups build the shared env named by
group_for (e.g. scmb_torch_v2 serves several torch methods).
(2) Per-method: recipe / the env recipe/env yml
CLI emit an isolated scmb_<method> env from one method's own deps; to run
in it, pass cmd_template="conda run -n scmb_<method> {cmd}" to run. Prefer
the group route unless you need an isolated per-method env.
mtb.env.recipe¶
Return the conda environment recipe for a method — the env name, language, channels, and the package/pin list needed to build the env that method runs in. The recipe mirrors what ships alongside the method in the reference scMultiBench repo.
mtb.env.group_for¶
Return the conda env a method runs and provisions in: its shared group env
(e.g. SCALEX and Cobolt map to "scmb_torch_v2"; the R methods to
"scmb_r") when the method belongs to a group, otherwise its own
default_env_name (scmb_<method>). This is the
{env} the default cmd_template fills, and the same value as
mtb.method_info(...)["env"]. Because plan
/ groups build exactly these names, the env you provision is
the env run executes in.
mtb.env.default_env_name¶
Return the method's own (singleton) env name — scmb_<method> (e.g.
"scmb_scalex"). This is only the env used when a method is not a member of
any shared group; the env run actually executes in is always
group_for (which returns the shared group env for grouped
methods and falls back to this name otherwise).
mtb.env.groups¶
Return the mapping of shared env name → the methods that share it. Several methods reuse a single environment, so provisioning one env can unlock several methods; this view shows which.
mtb.env.plan¶
Return an ordered provisioning plan — the deduplicated set of envs needed to run
the requested methods (or every verified method when None), each entry pairing
an env name with its recipe so shared envs are built only once.
RunResult¶
mtb.run returns a RunResult dataclass. Its fields:
method(str) — the method id that was run.out_dir(Path) — the working directory the command ran in.cmd(list[str]) — the fully wrapped argv that was executed (incl. theconda runprefix).output— the loaded primary output (e.g. the joint embeddingndarray).extra(dict) —{file: loaded_output}for any declared extra outputs.stdout(str) — captured standard output.stderr(str) — captured standard error.
A failed run (non-zero exit) raises RuntimeError with the tail of stderr/stdout
rather than returning a RunResult.
Versioning¶
The package version is available as multibench.__version__.