prepare() overview#

Audience: everyone who will share, host, or repeatedly open a dataset Time: 10 minutes to a first file Goal: write a Cellucid-ready AnnData and open it

prepare() takes an AnnData (data=adata), or arrays and data frames — embeddings, cell and gene metadata, an expression matrix, a neighbour graph, vector fields — or both (an argument replaces that one component of data), checks every one of them, and writes one standard AnnData that the Cellucid web app reads fast. Given a MuData it writes a Cellucid-ready MuData instead: Prepare an AnnData or a MuData whole (data=).

You pass

It is stored as

data=adata

every component below that adata holds: obs, X with var, obsm, obsp['connectivities'], uns['cellucid']

embeddings={"X_umap": ..., "X_pca": ...}

obsm[key], float32, every column

obs= (a DataFrame)

obs; repeated text becomes categorical

var= (a DataFrame)

var

gene_expression= (sparse or dense)

X, gene-major (CSC when sparse), float32

connectivities=

obsp['connectivities'], symmetric CSR float32

vector_fields={"velocity": {"X_umap": ...}}

obsm['velocity_umap'] (<field>_<basis> for X_<basis>, scVelo’s name)

dataset_id, dataset_name, citation, source, launch defaults

uns['cellucid'] (and uns['title'])

The required format names the container, and the output path ends in its suffix:

format

Writes

Choose it for

"zarr"

a .zarr store folder of small files (Zarr format 2 unless zarr_format=3)

GitHub: no file over 100 MB, no LFS, many small files at once over HTTP/2

"h5ad"

one HDF5 .h5ad file

everything else: single-file hosts (Zenodo, Figshare, Hugging Face, S3, a lab server), local files, cellucid serve and Jupyter

"zarr.zip"

the store folder in one .zarr.zip file, entries stored uncompressed

wherever an .h5ad goes, as Zarr

"h5mu"

one .h5mu file, for a MuData (data=mdata)

a MuData wherever an .h5ad goes; "zarr" and "zarr.zip" write a MuData too

There is no default: a call without format is refused with these choices. Why each goes where, measured: Which format?. Every layout detail is in Cellucid-ready AnnData specification.

Values and coordinates are stored as given (float32), and the browser normalizes embeddings and computes centroids itself. The one thing computed here is the outlier filter’s quantiles, when latent_key names a latent space: every categorical obs column’s, stored in uns['cellucid']['outlierQuantiles'] (Embeddings and coordinates).


Fast path#

From an AnnData object#

import anndata as ad
import cellucid

adata = ad.read_h5ad("pbmc.h5ad")

cellucid.prepare(
    "pbmc_cellucid.h5ad",
    format="h5ad",
    data=adata,
    dataset_id="pbmc-3k",
    dataset_name="PBMC 3k",
)

data=adata takes obs, X with var, every numeric obsm array and obsp['connectivities']; to choose instead, pass the component yourself (embeddings={"X_umap": adata.obsm["X_umap"]} writes that one embedding).

prepare() returns the path it wrote. It writes beside the target under a temporary hidden name and moves the finished file into place, so a failed or interrupted call never leaves a half-written file. An existing output is replaced only with force=True.

Open it#

  • In Python: cellucid.serve_anndata("pbmc_cellucid.h5ad") or, in a notebook, cellucid.show_anndata("pbmc_cellucid.h5ad"). The file names itself (uns['cellucid']), so no dataset_name/dataset_id is passed.

  • On the command line: cellucid serve pbmc_cellucid.h5ad.

  • In the browser: the web app’s Open… button, or the Link or server bar for a hosted file (Data Loading in the Web App (All Paths)).

The Session panel with the Pancreatic endocrinogenesis sample loaded: the Dataset box with its name, cells and genes, format and host, description and a collapsed Details; Open data with the Sample dataset dropdown, My datasets naming the open sample, the Open… button and the Link or server bar; the Stored line; and the collapsed Subsampling and Data mapping sections.

The Session panel gathers every loading path under Open data.#

What success looks like#

  • The dataset opens under the name you gave it.

  • Every obs column is listed (or the obs_keys you chose, in that order).

  • Typing a gene name colours the cells by its expression.

  • The embedding you named in embedding_defaults is the one shown first.


Required and optional inputs#

Required: out_path, format, at least one embedding (embeddings=, or a numeric obsm array of data), and dataset_id and dataset_name (passed, or read from data’s uns['cellucid']). Everything else is optional:

Argument

Without it

obs

Cells are named "0" … "n - 1"; no metadata fields.

var, gene_expression

No X; gene search is unavailable. var without gene_expression is refused.

connectivities

No neighbour graph.

vector_fields

No velocity overlay.

dataset_description, citation_text/citation_url, source_name/source_url

Not shown.

embedding_defaults, latent_key, obs_keys, var_gene_id_column, vector_field_default, normalize_embeddings, centroid_min_points

The viewer’s own choice; nothing is written to uns['cellucid']['defaults']. Without latent_key no outlier quantiles are stored, and the outlier filter waits for a latent space chosen in the viewer.

dataset_id is the dataset’s stable key — sessions and community annotations are keyed by it — so keep it when you rewrite the same dataset, and change it when the cells change. See Dataset identity and reproducibility.

prepare() or open the AnnData directly?#

You want to

Use

look at an AnnData now, on this machine or in a notebook

show_anndata() / serve_anndata() / cellucid serve, no preparation

share or host a dataset, or open a large one repeatedly

prepare() once, then open the result anywhere

ship a dataset that opens with a name, citation and chosen defaults

prepare()

A file prepare() did not write still opens; only a row-major (CSR) expression matrix makes the browser build a gene index first, which on a 562k-cell dataset took 4.1 s over a slow link where the prepared file took 0.09 s (Performance and storage).

Next#