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 three equivalent entry points:


Fast path (beginner-friendly)#

A) Serve anything (auto-detected) from the terminal#

# Exported folder, .h5ad, or .zarr are all supported:
cellucid serve /path/to/data
cellucid serve /path/to/data.h5ad
cellucid serve /path/to/data.zarr

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

B) Serve an exported dataset from Python#

from cellucid import serve

serve("./my_export")  # blocks until Ctrl+C

Practical path (deployment patterns)#

1) Exported dataset vs AnnData mode#

Exported dataset (recommended for speed + reproducibility):

AnnData mode (convenient, often slower):

  • Serve with serve_anndata() or cellucid serve data.h5ad

  • Useful during exploratory analysis when you don’t want to write an export yet

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 --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 http://127.0.0.1:8765/

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 --host 0.0.0.0
    
  • Do this only if you understand your network/security posture.



Deep path (how server mode works)#

What the server provides#

  • Static or virtual endpoints for dataset files (exported data or AnnData-backed “virtual files”)

  • CORS headers so the viewer UI can request data

  • Health/info endpoints:

    • /_cellucid/health

    • /_cellucid/info

    • /_cellucid/datasets

Viewer UI hosting and offline behavior#

By default, Cellucid serves the viewer UI from the same server origin via a hosted-asset proxy. This avoids:

  • mixed-content issues (HTTPS notebook + HTTP localhost)

  • cross-origin iframe restrictions

If the runtime cannot reach the hosted viewer assets, you may see a “viewer UI unavailable” error page. Use the environment variable:

  • CELLUCID_WEB_PROXY_CACHE_DIR to control where the UI cache is stored.


API reference#

Functions#

cellucid.serve(data_dir, port=8765, host='127.0.0.1', open_browser=True, quiet=False)[source]#

Serve a cellucid dataset directory.

This is the main entry point for serving data. It starts an HTTP server that serves the dataset files with CORS headers enabled.

Parameters:
  • data_dir (str | Path) – Path to the dataset directory

  • 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 the viewer in browser (default: True)

  • quiet (bool) – Suppress info messages

Example

>>> from cellucid import serve
>>> serve("/path/to/my_dataset")

# For remote server access via SSH: >>> serve(“/path/to/data”, host=”0.0.0.0”) # Then on local machine: ssh -L 8765:localhost:8765 remote-server

cellucid.serve_anndata(data, port=8765, host='127.0.0.1', open_browser=True, quiet=False, **kwargs)[source]#

Serve an AnnData object or h5ad file directly.

This is a convenience function for quickly visualizing AnnData. For production use, consider using prepare instead.

Parameters:
  • data (str, Path, or AnnData) – Path to h5ad file or AnnData object.

  • 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.

  • **kwargs – Additional arguments passed to AnnDataAdapter.

Returns:

The running server instance.

Return type:

AnnDataServer

Example

>>> from cellucid import serve_anndata
>>> serve_anndata("/path/to/data.h5ad")
>>> # Or with in-memory AnnData
>>> import anndata as ad
>>> adata = ad.read_h5ad("data.h5ad")
>>> serve_anndata(adata)

Classes#

class cellucid.CellucidServer(data_dir, port=8765, host='127.0.0.1', open_browser=False, quiet=False)[source]#

Bases: object

Cellucid data server for serving datasets over HTTP.

Supports multiple deployment modes: - Local: Direct browser access on localhost - SSH tunnel: Access via port forwarding from remote server - Jupyter: Embedded in notebook environment

Example

server = CellucidServer(“/path/to/data”) server.start() # Blocking

# Or non-blocking: server.start_background() # … do other things … server.stop()

Parameters:
__init__(data_dir, port=8765, host='127.0.0.1', open_browser=False, quiet=False)[source]#

Initialize the server.

Parameters:
  • data_dir (str | Path) – Path to the dataset directory (single dataset or multi-dataset)

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

  • host (str) – Host to bind to (default: 127.0.0.1 for localhost only)

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

  • quiet (bool) – Suppress info messages

property url: str#

Get the server URL.

property viewer_url: str#

Get the full URL to open the viewer with this server’s data.

start(blocking=True)[source]#

Start the server.

Parameters:

blocking (bool) – If True, block until interrupted. If False, start in background.

start_background()[source]#

Start the server in a background thread.

stop()[source]#

Stop the server.

is_running()[source]#

Check if the server is running.

Return type:

bool

wait()[source]#

Wait for the server to stop (blocks until Ctrl+C or stop()).

class cellucid.AnnDataServer(data, port=8765, host='127.0.0.1', open_browser=False, quiet=False, **adapter_kwargs)[source]#

Bases: object

Server for serving AnnData data in Cellucid format.

Example

server = AnnDataServer(adata) server.start() # Blocking

# Or non-blocking: server.start_background() # … do other things … server.stop()

Parameters:
  • data (Union[str, Path, 'anndata.AnnData'])

  • port (int)

  • host (str)

  • open_browser (bool)

  • quiet (bool)

__init__(data, port=8765, host='127.0.0.1', open_browser=False, quiet=False, **adapter_kwargs)[source]#

Initialize the server.

Parameters:
  • data (str, Path, or AnnData) – Path to h5ad file or AnnData object.

  • 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.

  • **adapter_kwargs – Additional arguments passed to AnnDataAdapter.

property url: str#

Get the server URL.

property viewer_url: str#

Get the full URL to open the viewer.

start(blocking=True)[source]#

Start the server.

Parameters:

blocking (bool)

start_background()[source]#

Start the server in a background thread.

stop()[source]#

Stop the server and cleanup resources.

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.

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

“The dataset directory contains multiple datasets”#

  • CellucidServer supports serving a directory that contains multiple exported datasets as subfolders.

  • Confirm by visiting /_cellucid/datasets.

“Exported folder missing some files”#

  • The viewer expects a minimum set of files (obs_manifest.json and at least one points_*d.bin(.gz)).

  • If those are missing, the server may still start, but the viewer will fail to load the dataset correctly.


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:

  • You served a directory that is not a valid exported dataset (missing manifests/points files).

  • You served a parent folder with multiple datasets but opened the wrong path.

How to confirm:

  • Visit /_cellucid/datasets and confirm the dataset path you intended exists.

  • Try fetching dataset_identity.json and obs_manifest.json in the browser.

Fix:

  • Serve the correct dataset directory (the folder produced by prepare(...)).

  • Or re-export 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 conflicting extensions for the session, or use a different browser profile.


Symptom: “Viewer UI unavailable” / blank page#

Likely causes:

  • The hosted viewer assets could not be fetched and are not cached.

Fix:

  • Ensure HTTPS access to the hosted UI once (to populate cache), or set a persistent CELLUCID_WEB_PROXY_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 crashes/gets slow for large ones”#

Likely causes:

  • AnnData mode is generating virtual files on demand and may hit memory/CPU limits.

Fix:

  • Export with prepare() (quantization + compression) and serve the exported directory.

  • Use .h5ad backed mode (default) or .zarr for lazy loading if staying in AnnData mode.


Symptom: “cellucid serve data.h5ad says ‘Importing dependencies…’ and feels stuck”#

What’s happening:

  • The first import may be slow in fresh environments because large scientific dependencies are loaded.

Fix:

  • Wait once (subsequent runs are faster in the same process).

  • If it truly hangs, run with --verbose and check for import errors.


See also#