Jupyter: show_anndata() quickstart#
This page shows how to embed Cellucid in a notebook output cell and interact with it from Python.
Use this when you want:
a tight analysis loop (select cells → compute something → highlight back),
reproducible exploration inside a notebook,
and/or to use hooks/events (selection, hover, click).
If you are not in a notebook environment, start with CLI: cellucid serve quickstart.
At a glance#
Audience
Wet lab / non-technical: copy/paste “Minimal cells”, stop at “What success looks like”.
Computational: focus on how
show_anndatareads.h5adand Zarr stores in place, and remote notebook caveats.Power users: focus on what happens while a cell runs, and
viewer.debug_connection().
Time
Minimal embed: ~5 minutes
Full read (edge cases + troubleshooting): ~20–30 minutes
Prerequisites
pip install cellucid(it installsanywidget)A notebook that shows widgets: JupyterLab, Jupyter Notebook 7, VS Code, Google Colab, marimo or Databricks (Supported environments matrix)
Read once: where the viewer comes from#
Important
show_anndata(...) shows a notebook widget (an anywidget) in the cell’s
output. The widget frames the Cellucid app, which your browser loads from
https://www.cellucid.com (or the copy you name with web_source_url=), and
connects it to the kernel through the notebook’s own connection: the viewer
reads your dataset from the kernel through the widget, so no port is opened
and nothing is uploaded anywhere.
The kernel handles the widget’s messages between cells: the viewer loads once the cell that showed it finishes.
Minimal cells (copy/paste)#
A) Show an in-memory AnnData#
from cellucid import show_anndata
viewer = show_anndata(adata)
Data that declares no identity of its own (uns['cellucid']) is named
AnnData (<n> cells) with an ID made from that, printed in one line; sessions
are kept under it. Name it for an ID that stays the same:
show_anndata(adata, height=600, dataset_name="My study", dataset_id="my-study-v1").
In marimo, make the widget the cell’s output (end the cell with viewer);
the other notebooks show it at once.
B) Show a file or folder, read by the viewer itself#
from cellucid import show_anndata
viewer = show_anndata(
"data.h5ad",
height=600,
dataset_name="My study",
dataset_id="my-study-v1",
)
# A Zarr store (folder or .zip) uses the same call shape, and so do .h5mu,
# .loom, a 10x .h5 or outs/ folder, a MatrixMarket folder and .rds/.rda files.
C) Show a MuData#
viewer = show_anndata(mdata, dataset_name="CITE-seq", dataset_id="cite", modality="rna")
The object is served as a MuData store made from it, as an AnnData is;
modality= names the modality the viewer opens on.
D) Show a Cellucid-ready AnnData (fastest; names itself)#
A file written by cellucid.prepare() declares its own name and id in
uns['cellucid'], so no identity is passed:
from cellucid import show_anndata
viewer = show_anndata("pbmc_cellucid.h5ad", height=600)
What success looks like#
You see an interactive viewer inside the notebook output cell.
You can pan/zoom and select cells.
The kernel stays running (the viewer reads the dataset through it).
Path or object (how to choose)#
You pass |
Best for |
Tradeoffs |
|---|---|---|
a path ( |
large data; files you will reopen |
read in place, nothing copied (an AnnData file not in priority order is served in priority order, from the file) |
an in-memory |
the object you are analysing now |
served in priority order, made from it as the viewer reads it: the viewer opens at once, and its expression matrices are laid out gene-major in the background (read-only meanwhile); released when the viewer stops, or when the cell that showed it runs again |
a file written by |
the fastest reads; sharing |
written once by |
How the embed works (so you can debug it)#
When you call show_anndata(...), Cellucid:
checks the dataset and the launch choices you passed (an in-memory AnnData or MuData is served in priority order, made from it as the viewer reads it, its expression matrices laid out gene-major in the background), and
shows a
Widgetwhose output frames the app athttps://www.cellucid.com/?viewer=embedded. The page asks the widget for its credentials and a private channel (aMessagePort), then reads the dataset’s bytes and opens the viewer channel through it; the widget relays both to the kernel over the notebook’s own connection.
No server is started and no port is opened, so the same cell works on a laptop, on a remote JupyterHub, in VS Code and in Colab. Details: Notebook / widget mode (advanced) and Architecture: the viewer channel.
A viewer in a browser tab of its own instead (a plain script, an SSH tunnel)
is AnnDataViewer: the same API, served from this machine.
Programmatic control (quick preview)#
Actions travel on the viewer’s channel – every action of the viewer is a method. One sent before the viewer has connected (the viewer loads once the cell finishes) waits and is delivered, in order, the moment it connects:
viewer.highlight_cells(cells=[0, 1, 2], color="#ff0000")
viewer.color_by(field={"source": "obs", "key": "cell_type"})
viewer.cells_visibility_set(cells=[0, 1, 2], visible=False)
viewer.camera_reset(view="live")
Full hooks/events docs: Jupyter Hooks System (Python ↔ Frontend).
Cleanup (important for long notebook sessions)#
When you’re done:
viewer.stop()
This freezes the output on its last view, stops answering it, and releases what
it served: the store of an in-memory AnnData or MuData with the files its
expression matrices were laid out in. A viewer is stopped by itself when the
cell that showed it runs again (its output is replaced), and when it is
closed (viewer.close()).
More lifecycle details (ports, multiple viewers): Viewer lifecycle, cleanup, ports, and multiple viewers.
Troubleshooting#
Start here:
In a notebook, also run (in a new cell):
viewer.debug_connection()