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_selectionPython → Viewer: commands like
viewer.highlight_cells(...)
If you prefer a minimal interface, start with Jupyter (notebook embedding + hooks).
Fast path#
A) Exported data (recommended for speed)#
from cellucid import CellucidViewer
viewer = CellucidViewer("./my_export")
viewer.display()
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:
BaseViewerInteractive 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:
- __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 directoryport (
int|None) – Port for the data server (auto-selected if None)height (
int) – Height of the embedded viewer in pixelsauto_open (
bool) – Automatically display when createdclient_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:
BaseViewerInteractive 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_zarrExample
>>> 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
obsmfor the latent space.gene_id_column (str | None) – Exact column in
varcontaining gene identifiers. If None, identifiers come fromvar.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
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_messageto 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#
Jupyter (notebook embedding + hooks) for function-level entry points (
show,show_anndata)Server (browser tab + local HTTP server) for serving in a browser tab