Skip to content

Discover methods

scMultiBench's registry holds 40 methods across four integration categories, the 40 benchmark methods, with SCALEX registered for both the diagonal and cross scenarios. Before you run anything, the discovery API answers the only question that matters at the start of a project: given the data I have and the task I care about, which methods can I actually use?

This page is pure metadata lookup, no method environments, no GPUs, no data on disk. Everything here is a fast, in-process query against the registry and the published benchmark catalog.

TL;DR

import multibench as mtb

mtb.list_tasks()                     # ['batch', 'classification', 'clustering', ...]
mtb.list_methods(category="vertical")        # every method in a category
mtb.find_methods(category="diagonal",        # filter by what your data has
                 modalities=["rna", "atac"],
                 needs_labels=False)
mtb.method_info("SCALEX")            # language, env, atac kind, status, variants
mtb.inputs_for("D35", "SCALEX", "diagonal")  # resolve benchmark input paths

The four integration categories

Every method declares one or more categories describing the experimental design it integrates. Pick the row that matches your data, then filter within it.

Category Design Typical modalities
vertical Paired, the same cells measured in several modalities RNA+ADT, RNA+ATAC, RNA+ADT+ATAC
diagonal Unpaired, separate cells per modality, bridged by shared features RNA batch + ATAC batch
mosaic Overlapping modalities tied together by a bridge dataset mixed, partially paired
cross Several fully matched datasets integrated together replicate cohorts

Category is the first filter

A method written for paired CITE-seq (vertical) cannot consume an unpaired RNA + ATAC design (diagonal). Always pass category= first, it is the single largest constraint on what is applicable.


List what exists

mtb.list_tasks() returns the sorted set of tasks declared across the registry, and mtb.list_methods() returns method ids, optionally narrowed by category and/or task.

import multibench as mtb

mtb.list_tasks()
# ['batch', 'classification', 'clustering', 'imputation', 'registration']

mtb.list_methods()                       # all 40 registry methods
mtb.list_methods(category="vertical")    # only paired-design methods
mtb.list_methods(category="diagonal", task="clustering")

Both arguments are AND-combined: a method is returned only if it declares the requested category and the requested task.


Filter by what your data has

mtb.list_methods filters on category and task only. When you want to filter by the shape of your data, which modalities you measured, whether you have ATAC, whether you have cell-type labels to supervise with, use mtb.find_methods.

mtb.find_methods(
    category=None,        # restrict to one of vertical/diagonal/mosaic/cross
    task=None,            # restrict to a single task token
    needs_labels=None,    # True / False, does the method require cell-type labels?
    atac=None,            # "gene_activity" or "peak", how ATAC must be encoded
    modalities=None,      # e.g. ["rna", "atac"], modality types the method consumes
) -> list[str]

A worked example, I have an unpaired RNA batch and an ATAC batch, I have no cell-type annotation, and I want a method that consumes both modalities:

mtb.find_methods(
    category="diagonal",
    modalities=["rna", "atac"],
    needs_labels=False,
)
# ['SCALEX', 'Portal', 'uniPort', ...]

How the filters combine

find_methods returns the methods matching all supplied filters; passing None (the default) disables a filter. modalities is a subset test, a method matches if the modality types it consumes across its variants are a superset of what you ask for, so ["rna"] is broad and ["rna", "atac"] is stricter. The modality types are derived from each method's argument roles (auxiliary roles such as data_dir and out_dir are ignored).

The atac filter is about encoding, not presence: methods that consume ATAC do so either as a gene-activity matrix (atac="gene_activity") or as raw peaks (atac="peak"). If your ATAC is already summarised to gene activities, filter for it so you do not pick a peak-only method.

mtb.find_methods(category="diagonal", atac="gene_activity")

Inspect a single method

mtb.method_info returns a flat dict combining the registry spec with optional catalog metadata. It is the fastest way to understand a method before you commit to running it.

mtb.method_info("SCALEX")
# {
#   'id': 'SCALEX',
#   'language': 'python',
#   'categories': ['diagonal'],
#   'tasks': ['clustering', 'batch'],
#   'env': 'scmb_torch_v2',
#   'atac': 'gene_activity',
#   'needs_labels': False,
#   'status': 'verified',
#   'setup_hint': '',
#   'variants': ['tools_scripts/SCALEX/main_SCALEX.py'],
# }
Field Meaning
id canonical registry token (the name you pass to run)
language python or r, determines the conda env conventions
categories integration categories the method supports
tasks tasks the method's output is scored on
env conda env name; run orchestrates via conda run -n <env>
atac "gene_activity", "peak", or None if it consumes no ATAC
needs_labels whether the method requires cell-type labels to run
status verification state; every registry method is verified
variants the per-design entrypoints (one method can have several)

Pass files_dir= to enrich the dict with catalog columns (deep_learning, output) joined from the published benchmark tables:

mtb.method_info("SCALEX", files_dir="multibench/files")
# adds: 'deep_learning': 'Yes', 'output': 'embedding'

The full benchmark catalog

mtb.catalog.* exposes the published benchmark metadata as tidy DataFrames, useful when you want the whole picture rather than a single lookup.

from multibench import catalog

catalog.methods()    # one row per method: language, deep_learning, atac, output,
                     # needs_labels, categories, tasks, + canonical_id
catalog.datasets()   # one row per dataset, with a derived `simulated` flag
catalog.metrics()    # the metric-details table

Each table reads from config.DEFAULT.files_path by default; pass files_dir= to read a catalog elsewhere. The bundled catalog (catalog.datasets()) covers 63 real + 8 simulated datasets (71 total), a subset of the full published benchmark; the simulated flag (set for ids beginning SD) separates them:

ds = catalog.datasets()
ds[~ds["simulated"]]    # real datasets only

Two helpers normalise the catalog's free-text spellings to canonical tokens:

catalog.canonical_id("Seurat v5")     # 'Seurat_v5'
catalog.canonical_metric("kbet")      # 'kBET'

catalog.methods() carries a canonical_id column so you can join the published table to the registry tokens used by run and method_info.


Which method should I use?

A practical decision path tied to the four categories:

  1. Start from your design. Paired cells → category="vertical"; unpaired modalities bridged by features → "diagonal"; partially overlapping with a bridge → "mosaic"; replicate matched datasets → "cross".
  2. Filter by data shape. find_methods(category=..., modalities=[...], atac=..., needs_labels=...), drop methods that need labels you do not have, or an ATAC encoding you cannot provide.
  3. Keep only runnable methods. Intersect with the verified set so you do
  4. Read the spec. method_info confirms the conda env, language, and the exact variants, then resolve inputs with inputs_for and run.
candidates = mtb.find_methods(
    category="diagonal",
    modalities=["rna", "atac"],
    needs_labels=False,
)
runnable = [m for m in candidates
            if mtb.method_info(m)["status"] == "verified"]
runnable

Where to go next

  • Run a chosen method end-to-end: see the API reference for mtb.run and the typed RunResult.
  • Score an output with scIB metrics: mtb.evaluate (note that cLISI/iLISI need a compiled LISI binary and kBET needs rpy2; missing dependencies degrade to NaN with a warning rather than failing).
  • Compare methods across datasets: mtb.load_results + mtb.plot.bubble.

Next: pick a method and run it end-to-end in Run a method.