Viewer classes (Jupyter objects you control from Python)#

Viewer classes are the stateful notebook objects returned by show() and show_anndata().

They are designed for two-way interaction:

  • Viewer → Python: hooks/events like @viewer.on_selection

  • Python → Viewer: commands like viewer.highlight_cells(...)

If you prefer a minimal interface, start with Jupyter (notebook embedding + hooks).


Fast path#

B) AnnData mode (convenient for exploration)#

from cellucid import AnnDataViewer

viewer = AnnDataViewer(
    adata,
    dataset_name="My study",
    dataset_id="my-study-v1",
)
viewer.display()

Practical path (what you can do with a viewer)#

1) Register hooks (viewer → Python)#

@viewer.on_selection
def on_selection(event):
    cells = event.get("cells", [])
    print("Selected", len(cells))

@viewer.on_ready
def on_ready(event):
    print("Viewer ready:", event)

2) Drive the UI from Python (Python → viewer)#

viewer.set_color_by("cell_type")
viewer.highlight_cells([0, 1, 2], color="#00ff00")
viewer.reset_view()

3) Robust notebooks: wait for readiness#

viewer.wait_for_ready(timeout=30)

4) Capture a session bundle (advanced)#

bundle = viewer.get_session_bundle(timeout=60)

See Sessions (.cellucid-session bundles) for applying the bundle back to AnnData.


Lifecycle and cleanup (important)#

Under the hood, a viewer starts a local server process/thread.

Best practices:

  • If you create many viewers in a long-running notebook, call viewer.stop() when done.

  • If you repeatedly re-run a cell, you may end up with multiple servers unless the old viewer is stopped.


API reference#

CellucidViewer#

class cellucid.CellucidViewer(data_dir, port=None, height=600, auto_open=True, *, client_server_url=None, web_source_url='https://www.cellucid.com', web_cache_dir=None)[source]#

Bases: BaseViewer

Interactive cellucid viewer for Jupyter notebooks (pre-exported data).

Embeds the cellucid web viewer in a notebook cell, connected to a local data server. Supports bidirectional communication via hooks.

Example

>>> viewer = CellucidViewer("/path/to/dataset")
>>> viewer.display()
>>>
>>> @viewer.on_selection
... def handle_selection(event):
...     print(f"Selected {len(event['cells'])} cells")
>>>
>>> # Low-level message API still available:
>>> viewer.send_message({'type': 'highlight', 'cells': [1,2,3]})
Parameters:
  • data_dir (str | Path)

  • port (int | None)

  • height (int)

  • auto_open (bool)

  • client_server_url (str | None)

  • web_source_url (str)

  • web_cache_dir (str | Path | None)

__init__(data_dir, port=None, height=600, auto_open=True, *, client_server_url=None, web_source_url='https://www.cellucid.com', web_cache_dir=None)[source]#

Initialize the viewer.

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

  • port (int | None) – Port for the data server (auto-selected if None)

  • height (int) – Height of the embedded viewer in pixels

  • auto_open (bool) – Automatically display when created

  • client_server_url (str | None) – Exact browser-reachable data server base URL.

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

  • web_cache_dir (str | Path | None) – Directory holding the active verified web build.

AnnDataViewer#

class cellucid.AnnDataViewer(data, port=None, height=600, auto_open=True, *, latent_key=None, gene_id_column=None, normalize_embeddings=True, centroid_outlier_quantile=0.95, centroid_min_points=10, dataset_name, dataset_id, vector_field_default=None, client_server_url=None, web_source_url='https://www.cellucid.com', web_cache_dir=None)[source]#

Bases: BaseViewer

Interactive viewer for AnnData objects in Jupyter notebooks.

This viewer serves AnnData directly without requiring prepare. It’s more convenient for interactive exploration but slower than using pre-exported data. Supports bidirectional communication via hooks.

Supports: - In-memory AnnData objects - h5ad files (HDF5-based, with lazy loading via backed mode) - zarr stores materialized by anndata.read_zarr

Example

>>> viewer = AnnDataViewer(
...     adata,
...     dataset_name="Example",
...     dataset_id="example",
... )
>>> viewer.display()
>>>
>>> @viewer.on_selection
... def analyze_selection(event):
...     subset = adata[event['cells']]
...     sc.pl.violin(subset, ['gene1', 'gene2'])
>>>
>>> # From h5ad file with lazy loading
>>> viewer = AnnDataViewer(
...     "/path/to/data.h5ad",
...     dataset_name="Example",
...     dataset_id="example",
... )
Parameters:
  • data (str | Path | anndata.AnnData)

  • port (int | None)

  • height (int)

  • auto_open (bool)

  • latent_key (str | None)

  • gene_id_column (str | None)

  • normalize_embeddings (bool)

  • centroid_outlier_quantile (float)

  • centroid_min_points (int)

  • dataset_name (str)

  • dataset_id (str)

  • vector_field_default (str | None)

  • client_server_url (str | None)

  • web_source_url (str)

  • web_cache_dir (str | Path | None)

__init__(data, port=None, height=600, auto_open=True, *, latent_key=None, gene_id_column=None, normalize_embeddings=True, centroid_outlier_quantile=0.95, centroid_min_points=10, dataset_name, dataset_id, vector_field_default=None, client_server_url=None, web_source_url='https://www.cellucid.com', web_cache_dir=None)[source]#

Initialize the AnnData viewer.

Parameters:
  • data (str | Path | anndata.AnnData) – AnnData object or path to h5ad file or zarr directory.

  • port (int | None) – Port for the data server (auto-selected if None).

  • height (int) – Height of the embedded viewer in pixels.

  • auto_open (bool) – Automatically display when created.

  • latent_key (str | None) – Explicit key in obsm for the latent space.

  • gene_id_column (str | None) – Exact column in var containing gene identifiers. If None, identifiers come from var.index.

  • normalize_embeddings (bool) – Whether to normalize embeddings into the viewer coordinate range.

  • centroid_outlier_quantile (float) – Quantile used for categorical centroids.

  • centroid_min_points (int) – Minimum category size used for centroid computation.

  • dataset_name (str) – Explicit human-readable dataset name.

  • dataset_id (str) – Explicit stable dataset identifier.

  • vector_field_default (str | None) – Exact field id required when multiple UMAP vector fields exist.

  • client_server_url (str | None) – Exact browser-reachable data server base URL.

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

  • web_cache_dir (str | Path | None) – Directory holding the active verified web build.

Return type:

None

property viewer_url: str#

Get the full viewer URL with anndata flag.


Edge cases (do not skip)#

Not running in a notebook#

  • If you instantiate a viewer in a plain Python script, display() will print a URL instead of embedding an iframe.

Re-running cells creates multiple servers#

  • Each viewer starts a local server on a port.

  • If you re-run the cell repeatedly without stopping old viewers, you may end up with multiple servers and confusing behavior.

Callbacks and exceptions#

  • Hook callbacks run in registration order. A callback exception propagates through event delivery and is reported by the event request.


Troubleshooting (symptom → diagnosis → fix)#

Symptom: “viewer.display() prints a URL instead of showing an embedded viewer”#

Fix:

  • You are likely not in a notebook context; open the printed URL in a browser tab, or run inside Jupyter/VSCode/Colab.

Symptom: “Hooks never fire”#

Fix:

  • Wait for the viewer to be ready: viewer.wait_for_ready().

  • Temporarily register @viewer.on_message to see raw events and confirm communication.

Symptom: “I have too many running servers”#

Fix:

  • Call viewer.stop() on old viewers.

  • Restart the kernel if you’ve lost track of old viewer instances.


See also#