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) # or "data.h5ad" / "data.zarr"
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)[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]})
AnnDataViewer#
- class cellucid.AnnDataViewer(data, port=None, height=600, auto_open=True, **adapter_kwargs)[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 (directory-based, inherently lazy-loaded)
Example
>>> viewer = AnnDataViewer(adata) >>> 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")
- Parameters:
data (str | Path | anndata.AnnData)
port (int | None)
height (int)
auto_open (bool)
- __init__(data, port=None, height=600, auto_open=True, **adapter_kwargs)[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.
**adapter_kwargs – Additional arguments passed to AnnDataAdapter.
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 are best-effort; exceptions are logged rather than raised to the notebook output.
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