Server (browser tab + local HTTP server)#

This page documents server-mode usage: open Cellucid in a browser tab while a local server serves the data.

You have two equivalent entry points:

The page either opens (the printed Viewer URL, with the viewer’s id and token) holds a viewer channel, so an agent app on this computer can work in it through cellucid mcp (Local agents (cellucid mcp)).

Both take any file or folder Cellucid reads — an .h5ad file, an AnnData Zarr store (folder or zipped), an .h5mu or MuData Zarr store, a .loom file, a 10x .h5 file or Cell Ranger outs/ folder, a MatrixMarket folder (a .mtx[.gz] of any name, such as GEO’s GSM…_matrix.mtx.gz), an .rds/.rda/.RData (gzipped or not) — or, in Python, an in-memory AnnData or MuData.


Fast path (beginner-friendly)#

A) Serve from the terminal#

# .h5ad, Zarr store folder, or zipped Zarr store:
cellucid serve /path/to/data.h5ad --dataset-name "My dataset" --dataset-id my-dataset
cellucid serve /path/to/data.zarr --dataset-name "My dataset" --dataset-id my-dataset
cellucid serve /path/to/data.zarr.zip --dataset-name "My dataset" --dataset-id my-dataset
# MuData, Loom, 10x, MatrixMarket, R objects:
cellucid serve /path/to/cite.h5mu --dataset-name "CITE-seq" --dataset-id cite --modality prot
cellucid serve /path/to/GSM4567_seurat.rds.gz --dataset-name "GSM4567" --dataset-id gsm4567
cellucid serve /path/to/outs --dataset-name "PBMC 1k" --dataset-id pbmc-1k

--dataset-name and --dataset-id default to the store’s own uns['cellucid']['name'] and uns['cellucid']['id'] (every file prepare() writes declares both); name the dataset when the store declares none.

Then open the printed URL (or let it auto-open).

B) Serve from Python#

from cellucid import serve_anndata

serve_anndata("my_study.h5ad")  # a prepared file names itself; blocks until Ctrl+C

Practical path (deployment patterns)#

1) A prepared file or any AnnData#

A Cellucid-ready AnnData (recommended for speed + reproducibility):

Any other AnnData:

  • Serve with serve_anndata() or cellucid serve data.h5ad --dataset-name "My dataset" --dataset-id my-dataset

  • The viewer reads the data itself — in place, with HTTP range requests, where the format allows it, once from the start for an R object or a MatrixMarket folder. A file in priority order (prepare()’s) is served byte for byte; an in-memory AnnData, and an AnnData file in any other order, are served as a Zarr store in priority order whose chunks are made as they are asked for (cellucid._served_store), so a subsample transfers only its cells; a MuData object is served the same way, as a MuData store.

  • Python reads the identity (uns['cellucid']) only of an AnnData or MuData, so an R object, a Loom, 10x or MatrixMarket dataset always needs --dataset-name and --dataset-id.

2) Local machine vs remote server (HPC / cloud VM)#

Local machine:

  • Keep default host 127.0.0.1 (only accessible on your machine).

Remote server + SSH tunnel (recommended for HPC):

  1. On the remote machine (where the data lives):

    cellucid serve /path/to/data.h5ad --dataset-name "My dataset" --dataset-id my-dataset --host 127.0.0.1 --port 8765 --no-browser
    
  2. On your laptop:

    ssh -L 8765:127.0.0.1:8765 user@remote
    
  3. In your laptop browser:

    • Open the printed Viewer URL: http://127.0.0.1:8765/?anndata=true

Direct LAN access (use carefully):

  • Bind to 0.0.0.0 to make the server accessible to other machines on the network:

    cellucid serve /path/to/data.h5ad --dataset-name "My dataset" --dataset-id my-dataset --host 0.0.0.0
    
  • This is also what a compute node needs when the tunnel has to terminate on a different machine, such as a cluster login node — see HPC clusters: Slurm, compute nodes, and --host 0.0.0.0.

  • A non-loopback bind has no authentication: every user who can reach the port reads the dataset. Do this only if you understand your network/security posture.

3) Launch choices#

Every launch option is optional: embedding_keys, knn_key, expression_source, gene_id_column, obs_keys, latent_key, vector_field_default, normalize_embeddings, centroid_min_points, and modality. For an AnnData or MuData, each one you set is checked against the store’s metadata before the server binds (a named obsm, obsp, layer, column or modality must exist); for a format only the browser reads (an R object, Loom, 10x, MatrixMarket), only its form is checked here and the viewer checks it against the data when it opens it. It is handed to the viewer as a launch default. One you leave unset is taken from the store’s own uns['cellucid']['defaults'], else the viewer applies its default rule; see Data mapping.

cellucid serve /path/to/data.h5ad --dataset-name "My dataset" --dataset-id my-dataset \
    --knn connectivities
from cellucid import serve_anndata

server = serve_anndata(
    "data.h5ad",
    dataset_name="My dataset",
    dataset_id="my-dataset",
    knn_key="connectivities",
)

No choice costs startup time: the viewer reads the neighbour graph the first time a view draws it, and a vector field when the overlay shows it. Naming an element the store does not have is an error before the bind, for example knn_key names obsp['connectivities'], which this store does not have.

A choice you set overrides the store’s own uns['cellucid']['defaults'] for this server only; the file is not changed.

4) Which URL the banner prints#

A server bound to a wildcard address — --host 0.0.0.0, --host ::, or an empty host — accepts connections on every interface, but the wildcard is not an address any browser can open. So the banner prints the loopback origin as Local URL and Viewer URL (that is what a browser on the serving machine uses, and what an SSH tunnel terminates on), and names the addresses other machines use separately:

A wildcard bind prints the loopback origin plus the machine’s own name; see Remote servers, SSH tunneling, and cloud.

  • The From another machine block appears only when this machine has a usable name of its own. A hostname that resolves back to loopback names nothing outside the machine, so it is reported as no origin at all rather than as a URL that cannot travel.

  • An IPv6 literal bind is bracketed as a URL requires: http://[::1]:8765.

  • Open the exact Viewer URL the banner printed. 0.0.0.0 is never printed as a URL because nothing can connect to it.


Deep path (how server mode works)#

What the server provides#

  • The data’s bytes under /_cellucid/anndata/<dataset_id><ending> for one file (.h5ad, .zarr.zip, .h5mu, .loom, .h5, .rds.gz, …; the ending its format names it by), <dataset_id>.zarr/<key> for a Zarr store folder, or <dataset_id>/<path> for a folder of files, with Range, 206 Partial Content, Content-Range, HEAD, and ETag answered exactly and the bytes sent by the kernel (sendfile). A Zarr store folder is served key by key (404 for an absent key), with consolidated metadata built in memory when the store has none. The route is named by the dataset id, so the local file name is never published.

  • CORS headers so the viewer UI can request data

  • Host validation ahead of routing: on a loopback bind (the default), only one well-formed authority naming localhost or a loopback IP literal on the bound port is served (421 otherwise), which is what defeats DNS rebinding. Behind a reverse proxy, declare its host name with --allowed-host HOST or allowed_hosts=[...]; declaring names also applies the check to a non-loopback bind, which otherwise answers any Host; see Privacy, security, and network requirements

  • Health/info endpoints:

    • /_cellucid/health

    • /_cellucid/info

    • /_cellucid/datasets

    • /_cellucid/protocol (where the notebook viewer channel is, and what it carries)

  • The notebook viewer channel /_cellucid/ws (a WebSocket; opened only by a registered notebook viewer with its token, see Architecture: the viewer channel). The server answers no POST (405).

  • /_cellucid/datasets is {"datasets": [{"id", "name", "anndata": {"file": {"url", "kind", "layout", "size", "etag"}, "defaults": {...}}}]}. url is the data’s route relative to the server’s base URL, kind is the input format registry’s id (h5ad, zarr, h5mu, mudata-zarr, loom, tenx-h5, tenx-outs, mtx, rds, rda), layout is file, zip, or folder, size and etag are given for a file only (etag is the strong validator its bytes are answered with, read from the file at each request: the version the browser files what it keeps of the file under), a folder of files (tenx-outs, mtx) adds files: [{"path", "size", "etag"}, …] because a browser cannot list a folder, and defaults holds only the launch choices you set. /_cellucid/health is {"status": "ok", "type": "anndata", "version", "format", "n_cells", "n_genes"} (the counts null for a format Python does not read: an R object, Loom, 10x or MatrixMarket), and /_cellucid/info adds the bound host and port, and runtime: the program serving the viewer, which the viewer names in its Dataset box ("python"; "jupyter" for a viewer in a notebook kernel; the R package’s viewer says "r"). The server is threaded and keeps connections alive (HTTP/1.1), because a browser reads one file with many range requests. The full route table is in Server Mode (CLI + Python).

  • /_cellucid/info always carries the package version.

Viewer UI hosting and source requirements#

By default, Cellucid establishes and serves the exact verified viewer UI generation from the same server origin. This avoids mixed-content and cross-origin issues for the browser tab. (A notebook widget, show_anndata, uses no server: the browser loads the app from web_source_url.)

If the runtime cannot fetch and verify the exact source generation, startup raises before binding the server. Use --web-cache-dir PATH or the web_cache_dir= argument to select its publication directory.

Startup progress (direct AnnData: four steps)#

Startup prints four numbered steps: [1/4] Detecting format, [2/4] Reading metadata, [3/4] Checking launch choices, [4/4] Starting server. Steps 1 to 3 read metadata only, never an array. The transcript is in Server Mode (CLI + Python).

  • Step 2 prints the cell and gene counts and the obsm, obs, obsp, and layers entries an AnnData or MuData holds; for another format it says the browser reads the contents when it opens the data.

  • Step 3 prints every launch choice it accepted, and Consolidated metadata: built in memory (…) for a Zarr store folder that has none.

  • A store holding an array the browser cannot decode (an HDF5 filter other than gzip, shuffle, Fletcher-32, or LZF, such as Blosc, Zstandard, szip, or scaleoffset; a Zarr codec such as bz2, lzma, or zfpy) prints Browser cannot decode: with the arrays, and is served through the store in priority order, which decodes each chunk on the kernel as it is asked for (h5py or zarr with their codec plugins). MuData, Loom and 10x files are read on the kernel the same way.

  • A MuData file not written by prepare(), a Loom file and a 10x Cell Ranger outs/ folder print Serving: a Zarr store in priority order, … (or a MuData Zarr store …): the store holds what the browser presents from the file itself, cells in priority order (cellucid._served_formats mirrors the browser’s layout views). A Loom file with no embedding, and a 10x .h5 alone (its projections are in its outs/ folder), are refused in the browser’s words.


API reference#

Functions#

cellucid.serve_anndata(data, port=8765, host='127.0.0.1', open_browser=True, quiet=False, *, latent_key=None, gene_id_column=None, normalize_embeddings=None, centroid_min_points=None, dataset_name=None, dataset_id=None, obs_keys=None, embedding_keys=None, knn_key=None, expression_source=None, vector_field_default=None, modality=None, serve_web_ui=True, web_source_url='https://www.cellucid.com', web_cache_dir=None, allowed_hosts=None, cache_bytes=None)[source]#

Serve a dataset (a file, a folder, an AnnData or MuData object) to the viewer, which reads it itself.

The viewer reads the data in place with range requests where the format allows it (only what a view needs is transferred), and once from the start for an R object or a MatrixMarket folder; nothing is converted first.

The page it opens (the printed Viewer URL, which carries the viewer’s id and token) holds a viewer channel, so an agent app on this computer can work in it through cellucid mcp: the viewer is published to agents here (CELLUCID_AGENTS=off keeps it from them). The bare /?anndata=true address opens the same dataset without a channel.

Parameters:
  • data (str, Path, AnnData or MuData) – A file or folder in any format Cellucid reads (.h5ad, AnnData Zarr folder or .zip, .h5mu, MuData Zarr, .loom, a 10x .h5 file or outs/ folder, a MatrixMarket folder, .rds/.rda/.RData, gzipped or not), or an AnnData or MuData object. A leading ~ in a path is expanded to the user’s home directory. An AnnData or MuData object, and an AnnData, MuData, Loom or 10x file not in priority order, are served as a Zarr store in priority order, made as the viewer reads it from a snapshot taken when the server starts; no copy of an object is written as a file.

  • port (int) – Port to serve on (default: 8765).

  • host (str) – Host to bind to (default: 127.0.0.1).

  • open_browser (bool) – Whether to open browser (default: True).

  • quiet (bool) – Suppress info messages.

  • latent_key (str, optional) – obsm array (a latent space such as scVI or PCA) the viewer’s outlier filter measures in, instead of the store’s own uns['cellucid']['defaults']['latentKey']. The viewer reads the outlier quantiles the store holds for it, or computes them on first use.

  • gene_id_column (str, optional) – Exact column in var (raw.var with expression_source="raw") whose values name the genes. If None, genes are named by the index.

  • normalize_embeddings (bool, optional) – Whether the viewer scales embeddings into its coordinate range.

  • centroid_min_points (int, optional) – The fewest cells a category needs to get outlier quantiles (10 when None).

  • dataset_name (str, optional) – Exact non-empty human-readable name without surrounding whitespace or control characters. Unicode is preserved. Defaults to uns['cellucid']['name'], else the file’s name, or AnnData (<n> cells) for an object.

  • dataset_id (str, optional) – Portable 1-180 byte ASCII identifier beginning with a letter or digit and otherwise using only letters, digits, ., _, or -; it cannot end in . or use a Windows device name. Defaults to uns['cellucid']['id'], else made from the file’s name without its extension, or from the object’s label (AnnData (N cells)) (said in one line).

  • obs_keys (sequence of str, optional) – Exact obs columns the viewer shows, in this order. If None, every column is shown.

  • embedding_keys (mapping, optional) – The embedding of a dimension slot, overriding the default for that slot: {"2d": "X_tsne"} reads the first two columns of obsm['X_tsne'], and {"2d": ("X_pca", [2, 0])} reads the 0-based columns named.

  • knn_key (str, optional) – The obsp matrix the viewer draws as the neighbour graph, usually "connectivities"; read only when a view draws it.

  • expression_source (str, optional) – Where gene expression is read: "X", "raw" or "layer:<name>"; None follows the viewer’s default rule.

  • vector_field_default (str, optional) – The vector field the overlay opens on: <field> of an obsm array <field>_<basis> drawn over X_<basis>, one of whose embeddings is shown when the store opens (as for AnnDataServer).

  • modality (str, optional) – The modality a multimodal dataset opens on (as for AnnDataServer).

  • serve_web_ui (bool) – Establish and serve the exact current web build.

  • web_source_url (str) – Origin publishing the web asset inventory.

  • web_cache_dir (str or Path, optional) – Directory holding the active verified web build.

  • allowed_hosts (sequence of str, optional) – Extra Host names this server answers to, needed only behind a reverse proxy such as jupyter-server-proxy. Each entry is one bare DNS name or IP literal — no port, no scheme, no wildcard — and is matched on any port.

  • cache_bytes (int, optional) – What a store served in priority order (an object, or a file not in priority order) keeps of what it makes, in bytes, least recently used first out: the genes it renumbered and sorted for the chunks it answers. None keeps a 64th of the machine’s memory (256 MiB on a 16 GB machine), at most the share the web app gives its decoded chunks, and cellucid-r’s cache_bytes keeps; 0 keeps nothing (each gene is made again when it is read again).

Returns:

The server, after it stops (start blocks until then).

Return type:

AnnDataServer

Example

>>> from cellucid import serve_anndata
>>> serve_anndata(
...     "/path/to/data.h5ad",
...     dataset_name="Example",
...     dataset_id="example",
... )
>>> # Or an in-memory AnnData
>>> import anndata as ad
>>> adata = ad.read_h5ad("data.h5ad")
>>> serve_anndata(
...     adata,
...     dataset_name="Example",
...     dataset_id="example",
... )

The viewer’s web build is cached locally (see Server mode (advanced)):

cellucid.get_web_cache_dir()[source]#

Return this user’s default web cache directory (it may not exist yet).

~/.cache/cellucid/web on Linux ($XDG_CACHE_HOME when set), ~/Library/Caches/cellucid/web on macOS and %LOCALAPPDATA%\cellucid\web on Windows: each user of a shared machine has their own. Pass web_cache_dir= to a viewer or server to use another directory.

Return type:

Path

cellucid.clear_web_cache(*, cache_dir=None)[source]#

Delete the selected cache generation and propagate any cleanup failure.

cache_dir must name a directory dedicated to the web build, because the whole directory is removed. The filesystem root, the current working directory, the home directory, and the directory holding every home are refused before anything is inspected or removed, whether they are named directly, through ~, or through a symbolic link.

Parameters:

cache_dir (str or Path, optional) – The cache directory to remove; get_web_cache_dir() when None.

Returns:

The absolute path of the directory removed (or already absent).

Return type:

Path

Classes#

class cellucid.AnnDataServer(data, port=8765, host='127.0.0.1', open_browser=False, quiet=False, *, latent_key=None, gene_id_column=None, normalize_embeddings=None, centroid_min_points=None, dataset_name=None, dataset_id=None, obs_keys=None, embedding_keys=None, knn_key=None, expression_source=None, vector_field_default=None, modality=None, serve_web_ui=True, web_source_url='https://www.cellucid.com', web_cache_dir=None, allowed_hosts=None, cache_bytes=None)[source]#

Bases: object

Server that hands one dataset (a file or folder Cellucid reads, or an AnnData or MuData object) to the Cellucid viewer.

The viewer reads the data itself, with range requests where the format allows them; this server names the dataset, serves the store’s bytes, carries the launch choices, and hosts the notebook channel.

Examples

Start a blocking server:

AnnDataServer(
    "/path/to/data.h5ad",
    dataset_name="Example",
    dataset_id="example",
).start()

Start and stop a background server:

server = AnnDataServer(
    adata,
    dataset_name="Example",
    dataset_id="example",
)
server.start_background()
server.stop()
Parameters:
  • data (str | Path | anndata.AnnData | mudata.MuData)

  • port (int)

  • host (str)

  • open_browser (bool)

  • quiet (bool)

  • latent_key (str | None)

  • gene_id_column (str | None)

  • normalize_embeddings (bool | None)

  • centroid_min_points (int | None)

  • dataset_name (str | None)

  • dataset_id (str | None)

  • obs_keys (Sequence[str] | None)

  • embedding_keys (Mapping[str, EmbeddingKeySpec] | None)

  • knn_key (str | None)

  • expression_source (str | None)

  • vector_field_default (str | None)

  • modality (str | None)

  • serve_web_ui (bool)

  • web_source_url (str)

  • web_cache_dir (str | Path | None)

  • allowed_hosts (Sequence[str] | None)

  • cache_bytes (int | None)

__init__(data, port=8765, host='127.0.0.1', open_browser=False, quiet=False, *, latent_key=None, gene_id_column=None, normalize_embeddings=None, centroid_min_points=None, dataset_name=None, dataset_id=None, obs_keys=None, embedding_keys=None, knn_key=None, expression_source=None, vector_field_default=None, modality=None, serve_web_ui=True, web_source_url='https://www.cellucid.com', web_cache_dir=None, allowed_hosts=None, cache_bytes=None)[source]#

Check the store and the launch choices; the server binds on start.

Parameters:
  • data (str, Path, AnnData or MuData) – A file or folder in any format Cellucid reads (.h5ad, a zipped Zarr store, a Zarr store folder, .h5mu or MuData Zarr, .loom, a 10x .h5 file or outs/ folder, a MatrixMarket folder, .rds/.rda/.RData, gzipped or not), or an AnnData or MuData object. A leading ~ in a path is expanded to the user’s home directory. An AnnData object, and an AnnData, MuData, Loom or 10x file whose cells are not in priority order, are served as a Zarr store in priority order made from them as the viewer reads it (cellucid._served_store); a file prepare() wrote, an R object and a MatrixMarket folder are served as they are on disk. An object is served from a snapshot taken as the server is made (MuData as AnnData), its expression matrices laid out gene-major in the background.

  • port (int) – Port to serve on.

  • host (str) – Host to bind to.

  • open_browser (bool) – Whether to open browser on start.

  • quiet (bool) – Suppress info messages.

  • latent_key (str, optional) – obsm array (a latent space such as scVI or PCA) the viewer’s outlier filter measures in, instead of the store’s own uns['cellucid']['defaults']['latentKey']. The viewer reads the outlier quantiles the store holds for it, or computes them on first use.

  • gene_id_column (str, optional) – Exact column in var (raw.var with expression_source="raw") whose values name the genes. If None, genes are named by the index.

  • normalize_embeddings (bool, optional) – Whether the viewer scales embeddings into its coordinate range.

  • centroid_min_points (int, optional) – The fewest cells a category needs to get outlier quantiles (10 when None).

  • dataset_name (str, optional) – Exact non-empty human-readable name without surrounding whitespace or control characters. Unicode is preserved. Defaults to uns['cellucid']['name'], else the file’s name, or AnnData (<n> cells) for an object.

  • dataset_id (str, optional) – Portable 1-180 byte ASCII identifier beginning with a letter or digit and otherwise using only letters, digits, ., _, or -; it cannot end in . or use a Windows device name. Sessions and community annotations are keyed by it. Defaults to uns['cellucid']['id'], else made from the file’s name without its extension, or from the object’s label (AnnData (N cells)) (said in one line).

  • obs_keys (sequence of str, optional) – Exact obs columns the viewer shows, in this order. If None, every column is shown.

  • embedding_keys (mapping, optional) – The embedding of a dimension slot, overriding the default for that slot: {"2d": "X_tsne"} reads the first two columns of obsm['X_tsne'], and {"2d": ("X_pca", [2, 0])} reads the 0-based columns named. Slots not named follow the default rule (X_umap_1d/X_umap_2d/X_umap_3d, else the first 1- to 3-column of X_umap, X_UMAP, X_wnn.umap and X_ref.umap); when no slot resolves, the viewer makes a deterministic best guess from the other obsm arrays and reports it.

  • knn_key (str, optional) – The obsp matrix the viewer draws as the neighbour graph, usually "connectivities". None follows the viewer’s default rule. The graph is read only when a view draws it.

  • expression_source (str, optional) – Where gene expression is read: "X", "raw" (raw.X, with genes named from raw.var), or "layer:<name>"; None follows the viewer’s default rule (raw when the file has it and it holds more genes than X or X holds scaled values, as Scanpy reads genes; else X; without X, raw or a layer, reported as guessed).

  • vector_field_default (str, optional) – The vector field the overlay opens on: <field> of an obsm array <field>_<basis> drawn over X_<basis> (velocity for velocity_umap). One of its embeddings must be shown when the store opens (a chosen or default embedding, or a 1-3 column array that is not the latent space).

  • modality (str, optional) – The modality a multimodal dataset (a MuData, a Seurat object with several assays) opens on, one of its modality names; None opens the default one (the first named as gene expression – rna, gex, gene expression, gene_expression, sct – else the first). Set only for multimodal data.

  • serve_web_ui (bool) – Establish and serve the exact current web build.

  • web_source_url (str) – Origin publishing the web asset inventory.

  • web_cache_dir (str or Path, optional) – Directory holding the active verified web build.

  • allowed_hosts (sequence of str, optional) – Extra Host names this server answers to, needed only behind a reverse proxy such as jupyter-server-proxy. Each entry is one bare DNS name or IP literal — no port, no scheme, no wildcard — and is matched on any port. Declaring names also applies the Host check to a non-loopback bind.

  • cache_bytes (int, optional) – What a store served in priority order (an object, or a file not in priority order) keeps of what it makes, in bytes, least recently used first out: the genes it renumbered and sorted for the chunks it answers. None keeps a 64th of the machine’s memory (256 MiB on a 16 GB machine), at most the share the web app gives its decoded chunks, and cellucid-r’s cache_bytes keeps; 0 keeps nothing (each gene is made again when it is read again).

Return type:

None

cache_bytes#

What a store served in priority order keeps of what it makes (bytes).

next_free_port#

Whether a taken port is passed over for the next free one (AnnDataViewer sets it when no port was given).

runtime#

The program serving the viewer, as /_cellucid/info names it and the viewer shows it (the shared protocol’s runtimes): “python”, or “jupyter” for a notebook viewer (AnnDataViewer sets it).

viewer_channel#

Whether the page this server opens holds a viewer channel of its own (serve_anndata and cellucid serve set it): its address carries the viewer’s id and token, and the viewer is published to agent apps on this computer (cellucid mcp). A notebook viewer’s server leaves it off: AnnDataViewer holds the channel.

answer_request(method, path, range_header)[source]#

Answer one request for the dataset as the HTTP handler does, without a socket.

This is how a notebook widget’s viewer reads the dataset (cellucid.jupyter._widget): the routes of AnnDataRequestHandler but the viewer channel and the web build – the documents (_cellucid/health, info, datasets, protocol) and the store’s bytes, one Range interval at a time (206 with Content-Range, 416 for an interval the resource does not have). path is relative to the base address; method is GET or HEAD. Returns the status, the headers and the body (empty for HEAD).

Return type:

tuple[int, dict[str, str], bytes]

Parameters:
  • method (str)

  • path (str)

  • range_header (str | None)

property file_route: str#

The store’s route, relative to the server’s base URL.

property obs_names: Index | None#

The served cells’ obs names in their original order – the order the viewer names cells in – or None when this process cannot read them (a format only the browser reads).

One source with what is served: a store made for an object or a file holds the names it took with the cells (an object’s at show time, whatever is done to it after); a file served as it is gives the names it holds at the version it is served as, read again when it changes (a file prepared again to the same path).

property url: str#

Get the URL of the currently running server.

A bind to every interface reports the loopback origin, because the wildcard is not an address anything can open. The addresses other machines use are reported separately by network_urls.

property viewer_url: str#

with its viewer channel’s id and token when the server holds one (viewer_channel).

Type:

Get the full URL to open the viewer

property network_urls: list[tuple[str, str]]#

Return the origins another machine can open, when any exist.

start(blocking=True)[source]#

Start this single-use server.

Parameters:

blocking (bool)

start_background()[source]#

Start the server in a background thread.

stop()[source]#

Stop the server and release what it held (a served store’s scratch folder).

is_running()[source]#

Check if the server is running.

Return type:

bool

wait()[source]#

Wait for the server to stop.


Edge cases (do not skip)#

“It works locally but not on the remote server”#

  • If the server is on a remote machine, your browser cannot directly reach its localhost.

  • Use SSH tunneling (preferred) or bind to an external interface + open firewall rules (higher risk).

“I bound to 0.0.0.0 and now anyone can access it”#

  • Binding --host 0.0.0.0 exposes the server to your network.

  • There is no authentication on a non-loopback bind: every user who can reach the port reads the dataset. --host’s own help text states this.

  • The banner still prints the loopback origin as Local URL / Viewer URL, plus a Bound to every network interface. From another machine: block when this machine has a routable name. 0.0.0.0 itself is never rendered inside a URL.

  • Cellucid servers are designed for local/private use (not hardened for public internet exposure).

“The graph is there, but the viewer will not draw edges”#

  • The viewer draws obsp['connectivities'] by default. A graph stored under another key is drawn when you name it with --knn KEY (or knn_key="KEY"), or pick it under Session › Data mapping.

  • A file written by prepare() holds a graph only when connectivities= was passed.


Troubleshooting (symptom → diagnosis → fix)#

Symptom: “Port already in use”#

Fix:

  • Use --port 0 if supported by your workflow (otherwise choose a free port).

  • Or pick another port manually: --port 9000.


Symptom: “Data directory not found”#

Fix:

  • Confirm the path exists on the machine where you ran the server.

  • If you’re on a remote server, remember your local machine path is different.


Symptom: “I can open /_cellucid/health but the dataset won’t load”#

Likely causes:

  • The store holds no plottable embedding in obsm, or a shape mismatch.

  • A Zarr store folder’s consolidated metadata is stale.

How to confirm:

  • Visit /_cellucid/datasets and confirm the store route and launch choices.

  • Read the viewer’s own error; viewer.debug_connection() probes the store.

Fix:

  • Name the embedding with embedding_keys, or write the file again with prepare().


Symptom: “CORS blocked” (browser console error)#

Likely causes:

  • A corporate environment / browser extension blocks cross-origin requests.

Fix:

  • Prefer opening the viewer URL served by the same origin (default).

  • Disable the conflicting extension for the site, or verify the request in a clean profile with extensions disabled.


Symptom: web-generation startup failure#

Likely causes:

  • The configured source inventory or one of its declared objects could not be fetched or verified.

Fix:

  • Ensure source access at startup and pass a writable web_cache_dir.


Symptom: “Browser can’t connect / connection refused”#

Fix:

  • Confirm server is running and you are opening the correct URL.

  • If remote: confirm your SSH tunnel is active and mapped to the correct port.


Symptom: “It works for small datasets but gets slow for large ones”#

Likely causes:

  • A high-latency link between browser and server: the viewer reads a store with many range requests.

  • The first gene of a row-major (CSR) expression matrix: the browser builds a gene index over the matrix once.

Fix:

  • Run the server on the machine that holds the data and tunnel to it.

  • Store a matrix you open often column-major (CSC), so one gene is one contiguous read.


Symptom: cellucid serve stops on a module it could not import#

What’s happening:

  • An import failure is not one condition, and the message names which of three it is:

    • The distribution is not installed. The message names the package and the exact pip install <name> that supplies it.

    • It is installed, but too old to hold the name Cellucid asked of it. Installing the same version again repeats the failure, so the message names the file it imported and asks for pip install --upgrade <name>.

    • It is a standard-library module this interpreter cannot provide. No package installs it. The message names the running Python version, that interpreter’s own path, and the version range Cellucid supports.

Fix:

  • Follow the exact remedy in the message; for the third case, run Cellucid on a Python inside the supported range instead of installing anything.


See also#