Highlight mental model#
Highlights are annotations on top of visibility:
Filtering decides which cells are currently visible (per view).
Highlighting marks cells of interest (and can remain meaningful even if those cells are currently filtered out).
If you remember one sentence, make it this:
Filters control visibility. Highlights control membership.
At A Glance#
Audience
Wet lab / beginner: learn “selection vs highlight” and how to make a selection persist.
Computational users: learn the exact set logic (union/intersect/subtract), scope rules, and performance pitfalls.
Developers: learn what is stored (cell indices), how sessions persist highlights, and why some things are view-scoped.
Time
~15–25 minutes
Prerequisites
Any dataset loaded (demo is fine)
Familiarity with basic navigation + fields:
What you’ll learn
What a highlight page is vs a highlight group
What “preview highlight” is (and why it disappears)
Why you cannot select filtered-out cells (by design)
What persists in sessions vs what is temporary
The mental picture (one diagram)#
Think of highlighting as a bookkeeping layer on top of what the view is currently drawing:
Dataset (N cells; fixed order)
│
├─ View A filters → visibility mask A (which cells are interactable in View A)
├─ View B filters → visibility mask B (can differ in snapshots)
│
└─ Highlight pages (global, dataset-scoped)
├─ Page 1 (active) → list of highlight groups (each group = a set of cell indices)
├─ Page 2
└─ ...
Renderer (per view):
draw only visible cells in that view,
and add a highlight halo for cells that are “highlighted” on the active page.
Two key consequences:
You can have highlighted cells that are not currently visible.
You cannot select cells that a filter has hidden. Level of detail is a different thing: when a large dataset is drawn at reduced detail, the cells it leaves undrawn are still selectable.
Here is what that looks like once one selection has been confirmed:
One confirmed group. The panel counts membership (826 cells highlighted); the
canvas draws the members it is currently allowed to draw. Those are two
different numbers whenever a filter is active, and the panel says so by
switching to “N of M highlighted cells visible”.#
Definitions (the words people mix up)#
Cell index (what Cellucid stores)#
Internally, Cellucid identifies a cell by its index: 0..(n_cells-1) in the loaded dataset’s order.
This makes highlights dataset-dependent: if you reorder your dataset or write it again, “cell #123” may no longer refer to the same biological cell.
Important
Session restore rejects and rolls back the complete operation if the saved dataset fingerprint does not match the current dataset. It never applies layout while skipping highlights. This prevents “wrong highlights on the wrong dataset.”
Selection candidate set (temporary)#
When you use a selection tool, you build up a candidate set (“the current selection”).
Key properties:
It is temporary.
It can be multi-step (you can refine with multiple gestures).
It can be confirmed into a highlight group, or canceled.
Preview highlight (temporary rendering)#
While you are mid-selection (especially while dragging), Cellucid shows a preview highlight: it temporarily highlights your current candidate set so you can see “what would be selected if I confirmed now”.
Preview highlight is not saved. It will disappear when you:
confirm a selection,
cancel a selection,
switch highlight pages (which recomputes permanent highlights), or
reload without restoring a session.
Highlight group (persistent set of cells)#
A highlight group is a named entry in the “Highlighted groups” list.
In the current UI, groups are:
created by confirming a selection (lasso/proximity/KNN/annotation),
labeled automatically (e.g.
Lasso (12,345 cells)),enabled/disabled and removable,
stored as an explicit list of cell indices.
Note
Groups are not “colored labels” yet; Cellucid currently renders highlighted cells using a single highlight style (halo/ring). Highlight pages have colors in the UI, but highlight groups do not.
Highlight page (persistent collection of groups)#
A highlight page is a container that holds a list of highlight groups.
Why pages exist:
Wet lab workflow: “my selection for condition A” vs “my selection for condition B”.
Computational workflow: “hypothesis 1” vs “hypothesis 2”.
Review workflow: keep multiple alternative selections without destroying prior work.
Only one page is active for rendering/highlighting at a time.
The pipeline: visibility first, then highlights#
Step 1: filters decide what is selectable#
Selection tools only consider cells that are not filtered out in the view you are selecting in.
That includes:
standard filters (Filtering (Visibility, Outliers, and Filter Stacks)),
view-specific filters in multi-view snapshots (if snapshots have independent filters).
It does not include LOD/downsampling. With Visualization → Performance → Level of detail (LOD) enabled (Render modes: Points or Volumetric smoke), a zoomed-out camera makes Cellucid draw only a subset of the points — but a lasso, proximity drag, or KNN growth still evaluates every unfiltered cell. So a gesture can select cells the view is not currently drawing, and the group you confirm can be larger than the dots you drew around. That is deliberate: a selection that changed with the camera would not be reproducible.
To see how much of a result is actually on screen, read the “N of M highlighted cells visible” counter above the group list (Highlight UI (modes, pages, groups)). That counter does account for LOD, so “visible” there can be a smaller number than “selected”.
One exception: the Alt+click that starts a gesture picks the cell under the pointer,
and that pick can only land on a cell the view is drawing. Annotation-based, proximity,
and KNN selection all begin that way, so with LOD on and the camera far out a click can
report “no cell” even where cells exist — zoom in to seed, then drag. Lasso has no seed
click and is never affected.
This is why “I can’t lasso those points” means “they are filtered out in this view”, not “they are too small to be drawn right now”.
Step 2: highlights decide what is emphasized#
Permanent highlights come from:
all enabled groups on the active highlight page.
Preview highlight temporarily adds:
the current candidate set (while you are mid-selection).
Step 3: what you see is per view#
Each view renders highlights only for cells that are visible in that view.
So in multi-view:
the same highlighted cell may be visible (and highlighted) in View A,
but invisible (and therefore not highlighted) in View B if View B has stricter filters.
Selection tools are “set operations”#
Most selection tools support three operations on your current candidate set:
Intersect (keep only cells in both sets) — “refine / whittle down”
Union (add cells) — “grow”
Subtract (remove cells) — “carve away”
In Cellucid, these operations are controlled by modifier keys held during the gesture:
Alt= start selection gestureShift+Alt= union (add)Ctrl+AltorCmd+Alt= subtract (remove)
Without a keyboard (a phone or tablet), Select mode (in the Highlighting
panel, or on the selection bar at the bottom of the plot) stands in for Alt,
and its Intersect / Add / Subtract buttons pick the operation instead of
the modifier keys (Select mode (touch screens, or no Alt key)).
Tip
In 3D, intersection across multiple angles is the most reliable way to isolate a “true 3D region” using 2D tools.
Example: draw a lasso, rotate 90°, draw another lasso with Alt to intersect.
For categorical “annotation-based” selection, Alt acts like replace (not intersect), because intersecting “all cells in category X” with “all cells in category Y” is usually empty and not what users intend.
What persists (and where)#
What persists in a session#
When you save a session (Session Saving, Restoring, and Sharing), Cellucid can persist:
highlight pages (names, colors, active page),
highlight groups (labels/types, enabled flags),
highlight memberships (cell indices).
Large highlights can make sessions much larger; see Edge cases (highlighting and selection) for guidance.
What does not persist automatically#
The temporary candidate set (mid-selection)
The preview highlight
Anything if you reload without restoring a session
Dataset binding (important)#
Highlights are dataset-dependent. If the session’s dataset fingerprint doesn’t match your currently loaded dataset, Cellucid rejects the whole restore: nothing, highlights included, is applied.
Fast Path (Wet Lab Friendly)#
Goal: select a cluster and make it persist.
Load any dataset (demo is fine).
Open Highlighting in the left sidebar.
Pick Lasso.
Hold
Altand draw around a cluster.Release mouse → you should see a “Step 1” count and the points preview-highlighted.
Click Confirm (in the step controls).
You now have a highlight group in the list, and the highlight remains even if you change fields.
Step 3 in the panel. The pressed Tool button is the tool in use, and the Selection (i) describes every tool and its modifier keys.#
The four steps as they actually look, gesture by gesture, are in Verified highlighting captures.
Try this once to learn the key idea:
Apply a filter that hides that cluster → the group still exists, but becomes invisible.
Remove the filter → the group becomes visible again.
Practical Path (Computational)#
Workflow A: tight 3D selection using intersection#
Lasso roughly around the region (
Alt).Rotate to a very different angle.
Lasso again with
Alt(intersect) to reduce false positives from projection.Repeat once more if needed.
Confirm.
Workflow B: graph-aware selection (KNN drag)#
Enable/show connectivity edges (if available).
Use KNN drag to grow a selection along the neighbor graph.
Union/subtract as needed.
Confirm.
Workflow C: per-condition pages#
Create/rename pages like
Control,Treated.Do selections and confirm groups inside each page.
Use analysis later to compare pages.
Performance notes (read before selecting 1M cells)#
Operations that scale with the number of cells:
selection preview for lasso/proximity (can scan many cells repeatedly during drags),
recomputing highlight buffers when you add/remove/enable/disable groups,
saving sessions (membership arrays are stored in the bundle).
If selection feels laggy, the most effective “first aid” is:
filter down to fewer visible cells,
temporarily reduce view count (fewer snapshots),
avoid long continuous drags that force repeated full scans.
Deep Path (Expert / Developer)#
What is stored#
Highlight membership is stored as arrays of cell indices.
Rendering uses a per-cell
Uint8Arrayhighlight intensity buffer (binary in practice:0or255).
Why the highlight count can say “X of Y visible”#
The highlight UI distinguishes:
total highlighted cells (membership), and
visible highlighted cells (after filters and LOD/downsampling in the current view).
If you zoom/pan and see “visible highlighted” change, you may be seeing LOD behavior rather than filters.
Session storage (high level)#
For session bundles, each highlight group’s membership is one dataset-dependent chunk, stored in whichever encoding is smallest for it (sorted gaps, a bitset over all cells, or runs of consecutive cells) and gzip-compressed. A group made from a whole category is stored the same way, as its own cells (a category’s cells usually form few runs, so it stays small); on restore every group’s cells are checked against the saved digest.
Python/Jupyter synchronization (implemented)#
Cellucid has a viewer channel to cellucid-python (over the notebook widget’s
connection, or one WebSocket, /_cellucid/ws, for a browser tab) that supports:
Python → UI actions: every action of the viewer is a Python method (e.g.
viewer.highlight_cells(cells=...),viewer.color_by(field=...)), applied as a step of the history labelled as the notebook’sUI → Python hooks (e.g.
@viewer.on_selection,@viewer.on_click,@viewer.on_hover)Results back in one call:
viewer.pull(adata)writes every highlight group (acellucid_highlight__<id>column), label field and score ontoadata.obsNo-download session capture: pull the current
.cellucid-sessioninto Python as an object, read its history and apply one of its steps onto anAnnData
Recommended patterns:
If you want to react immediately, use hooks.
If you want your highlight groups as columns, run
viewer.pull(adata)in a later cell.If you want a durable, reproducible artifact, use a session – the whole history – (in a notebook, ask in one cell and collect in the next):
request = viewer.request_session()
session = request.result() plan = session.apply(adata) # dry run: what would change, one row each plan.table report = plan.apply() # writes the rows into adata, records the apply
Each highlight group of the step becomes one
boolcolumn,cellucid_highlight__<page>__<group>(from the page’s name and the group’s label). Applying the same step again changes nothing, and a column you made yourself is never replaced.
Important constraint: selections/highlights in sessions name cells by original position (each cell’s row in the order the dataset’s cells were given, whatever order a file stores them in), so only apply sessions to the AnnData that produced them, in that original order (a Cellucid-ready file read with anndata: cellucid.restore_original_order(adata) first).
Developer reference: Reference (hooks, commands, schemas, endpoints)
Edge cases and troubleshooting#
Edge cases checklist: Edge cases (highlighting and selection)
Troubleshooting: Troubleshooting (highlighting and selection)