Jupyter (notebook embedding + hooks)#

This page documents the notebook-facing APIs:

  • Fastest notebook preview: show_anndata() (serve AnnData directly)

  • Reproducible notebook view: show() (view an exported dataset directory)

  • Interactive control: viewer objects (AnnDataViewer, CellucidViewer) support hooks + Python→frontend commands


Audience + prerequisites#

Audience

  • Wet lab / beginner: copy/paste the “Fast path” and use the troubleshooting section when something looks wrong.

  • Computational: use “Practical path” + “Edge cases” to avoid performance and data-shape pitfalls.

  • Power user: use “Deep path” to understand how the server + hooks + session capture work.

Prerequisites

  • pip install cellucid

  • If you use AnnData: install anndata (and typically numpy, scipy, pandas).

  • A notebook environment: classic Jupyter, JupyterLab, VSCode notebooks, or Google Colab.


Fast path (beginner-friendly)#

A) “I have an AnnData”#

from cellucid import show_anndata

viewer = show_anndata(
    adata,
    dataset_name="My study",
    dataset_id="my-study-v1",
)

What you should see:

  • A Cellucid viewer embedded in the notebook output, showing your embedding.

  • Progress while the complete configured web generation is fetched, verified, and published for this startup (unless output is quiet).

B) “I already exported a dataset folder”#

from cellucid import show

viewer = show("./my_export")

Practical path (step-by-step + common workflows)#

1) Notebook display vs browser tab#

Cellucid always runs in a browser context (the viewer UI), but you choose where it appears:

2) Choosing show_anndata vs show#

Use show_anndata() when:

  • you’re iterating quickly in analysis notebooks,

  • you don’t want to write an export folder yet,

  • you can accept slower loads and less shareable artifacts.

Use show() when:

  • you want reproducibility (the export folder is a concrete artifact),

  • you want speed (pre-quantized, pre-packed binaries),

  • you want to share the dataset directory or host it.

3) A minimal “hooks” example (viewer → Python)#

from cellucid import show_anndata

viewer = show_anndata(
    adata,
    dataset_name="My study",
    dataset_id="my-study-v1",
)

@viewer.on_selection
def on_selection(event):
    # event["cells"] is a list[int] of selected indices (row indices into adata)
    print("Selected", len(event.get("cells", [])), "cells")

4) A minimal “control” example (Python → viewer)#

# Highlight a few cells (indices into the dataset)
viewer.highlight_cells([0, 10, 20], color="#ff0000")

# Color points by an obs field (must exist in the dataset/AnnData)
viewer.set_color_by("cell_type")

# Hide a subset (or pass None to apply to all)
viewer.set_visibility([1, 2, 3], visible=False)

# Reset the camera
viewer.reset_view()

5) Waiting for the viewer to be ready (robust notebooks)#

If you need to run code only after the UI finished loading:

viewer.wait_for_ready(timeout=30)

6) Capturing a .cellucid-session bundle without downloading (advanced)#

This is the “no browser download” workflow:

bundle = viewer.get_session_bundle(timeout=60)
print(bundle.list_chunk_ids())

See Sessions (.cellucid-session bundles) for what a session bundle contains and how to apply it back onto an AnnData.


Deep path (how notebook embedding works)#

What starts when you call show(...) / show_anndata(...)#

  1. A local HTTP server starts (on 127.0.0.1:<port>).

  2. The exact verified viewer generation is served from that same origin.

  3. The viewer UI posts interaction events back to the local server at /_cellucid/events.

  4. The Python viewer routes those events to your hook callbacks (e.g., @viewer.on_selection).

Environment caveat: when the browser cannot reach the kernel’s localhost#

Some notebook setups run the kernel remotely. In those cases, your browser may not be able to reach http://127.0.0.1:<port> directly.

If that happens, pass the exact browser-reachable HTTP(S) base URL as client_server_url=... when constructing the viewer.


API reference#

Functions#

show_anndata#

cellucid.show_anndata(data, height=600, *, 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]#

Quickly display an AnnData object, h5ad file, or zarr store in a notebook.

This is the easiest way to visualize AnnData directly without running prepare first. However, it’s slower than using pre-exported data.

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

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

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

AnnDataViewer

Returns:

AnnDataViewer instance for interaction via hooks.

Supported formats:
  • In-memory AnnData objects

  • .h5ad files (HDF5-based, lazy loading via backed mode)

  • .zarr directories materialized by anndata.read_zarr

Example

>>> from cellucid import show_anndata
>>> viewer = show_anndata(
...     adata,
...     dataset_name="Example",
...     dataset_id="example",
... )
>>>
>>> @viewer.on_selection
... def handle(event):
...     subset = adata[event['cells']]
...     sc.pl.violin(subset, 'gene1')
>>> # With custom options
>>> viewer = show_anndata(
...     adata,
...     latent_key="X_pca",
...     dataset_name="Example",
...     dataset_id="example",
...     height=800,
... )

Note

For production use or sharing, consider using prepare to create optimized binary files, then use show() to display them.

show#

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

Quick function to display a cellucid dataset in a notebook.

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

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

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

CellucidViewer

Returns:

CellucidViewer instance for interaction via hooks.

Example

>>> from cellucid.jupyter import show
>>> viewer = show("/path/to/my_dataset")
>>>
>>> @viewer.on_selection
... def handle(event):
...     print(f"Selected {len(event['cells'])} cells")

Classes (see dedicated page)#


Edge cases (do not skip)#

Data size and performance#

  • Very large adata.X can be slow in AnnData mode; consider exporting with prepare().

  • A .h5ad path is always opened read-only-backed; a .zarr path is loaded eagerly.

“My embedding is not 2D/3D”#

  • Cellucid supports 1D/2D/3D embeddings; if the embedding is missing or has an unexpected shape, you’ll see missing plot / errors.

Duplicate gene identifiers#


Troubleshooting (symptom → diagnosis → fix)#

Symptom: “Viewer does not appear in the notebook output”#

Likely causes:

  • You are not actually running inside a notebook (e.g., plain Python script).

  • The notebook output is blocked (content security policy / iframe blocked).

How to confirm:

  • Print viewer.viewer_url and try opening it in a new browser tab.

Fix:

  • Use a notebook environment (Jupyter, JupyterLab, VSCode notebooks, Colab).

  • If iframes are blocked, open viewer.viewer_url manually.


Symptom: remote notebook iframe is blank or unreachable#

Likely causes:

  • The browser cannot reach the kernel’s localhost server (remote kernel or strict origin policy).

Fix:

  • expose the server through your notebook deployment, and

  • pass that exact base URL as client_server_url.


Symptom: “Port already in use”#

Fix:

  • Choose a different port (pass port=... to the viewer class, or stop the process using the port).


Symptom: “I registered @viewer.on_selection but nothing prints”#

Likely causes:

  • The viewer is not ready yet.

  • You selected nothing (or selection tools differ from expectation).

How to confirm:

  • Call viewer.wait_for_ready() and then try selecting again.

Fix:

  • Ensure the viewer is loaded, then select cells (lasso/shift-click/etc.).


Symptom: “The iframe is blank / white / stuck loading”#

Likely causes:

  • Viewer construction raised because the configured generation could not be established.

  • The server isn’t reachable from the browser (remote kernel / HTTPS notebook constraints).

How to confirm:

  • Open viewer.viewer_url in a new browser tab (sometimes notebook output hides useful errors).

Fix:

  • Ensure the configured source is reachable at startup and the selected generation directory is writable. A previously published generation is not substituted after source failure.

  • If the browser cannot reach localhost, expose the server and pass its exact browser-reachable base URL as client_server_url.


Symptom: web-generation startup failure#

Likely causes:

  • The configured source generation could not be fetched, verified, or atomically published.

How to confirm:

  • Run viewer.debug_connection() and inspect the web_ui section.

Fix:

  • Ensure the runtime can reach the configured source at viewer startup.

  • Pass a writable web_cache_dir and correct the exact reported source or inventory failure.


Symptom: “viewer.set_color_by(...) does nothing”#

Likely causes:

  • The field name does not exist in obs (or has a different spelling/case).

  • The viewer is not ready yet.

How to confirm:

  • Wait for readiness: viewer.wait_for_ready().

  • In AnnData mode, print adata.obs.columns and confirm the field exists.

Fix:

  • Use the exact field name.

  • Prefer exporting with prepare() for stable field naming across sessions.


Symptom: “viewer.highlight_cells(...) does nothing”#

Likely causes:

  • The viewer is not ready yet.

  • Indices are out of range (wrong dataset / wrong cell order).

How to confirm:

  • viewer.wait_for_ready()

  • Try highlighting a small index like [0].

Fix:

  • Ensure indices correspond to the dataset loaded in the viewer.

  • If you subset/reorder AnnData, re-run the viewer from the same object.


Symptom: “Selections map to the wrong cells in my AnnData”#

Likely causes:

  • The viewer is connected to a dataset whose row order does not match your adata.

How to confirm:

  • Select a single cell and print identifying metadata from adata.obs.iloc[cell_index].

  • Compare with what you expect in the UI.

Fix:

  • Ensure you apply selection indices to the same AnnData used to create/serve the viewer.

  • Avoid reordering adata after starting the viewer; restart the viewer after reindexing.


Symptom: “My hook callback crashes silently”#

What’s happening:

  • Hook callbacks are wrapped; exceptions are logged rather than crashing the notebook cell.

How to confirm:

  • Enable debug logging:

    import logging
    logging.basicConfig(level=logging.DEBUG)
    

Fix:

  • Add defensive checks inside callbacks (validate keys, lengths, types).

  • Start with @viewer.on_message to inspect raw event payloads.


Symptom: “I don’t know what’s wrong / I need a diagnostic dump”#

Fix:

  • Run:

    report = viewer.debug_connection()
    report
    
  • The report includes:

    • server health/info probes,

    • dataset_identity_probes, keyed by every exact declared dataset id/path,

    • detected notebook context (Jupyter/Colab/VSCode),

    • viewer UI cache status,

    • recent events and readiness state.


See also#