Selection synchronization (views, pages, filters, Python)#

Highlighting feels “simple” until you use multi-view snapshots, change filters, or try to coordinate with Python/Jupyter. This page makes the scope rules explicit so you can predict what will happen.

At A Glance#

Audience

  • Wet lab / beginner: understand “why did my selection disappear when I clicked another panel?”

  • Computational users: understand reproducibility and what is view-scoped vs global.

  • Developers: understand which state lives in the viewer vs the app state, and what is session-persisted.

Time

  • ~15–25 minutes

Prerequisites

What you’ll learn

  • What syncs across views/snapshots

  • What switching highlight pages changes (and what it does not)

  • How filters affect selection and highlight visibility

  • What to expect from Python/Jupyter integration (and how to diagnose when it’s not active)


The scopes table (bookmark this)#

Thing

Scope

Persists?

Notes

Filters / visibility mask

Per view (live + each snapshot may differ)

Session (dataset-dependent)

Filters control which cells are selectable and drawn in that view.

Selection tool mode (annotation / lasso / proximity / KNN)

Global UI choice

Session (dataset-dependent layout)

Affects how Alt gestures are interpreted.

Select mode and its Intersect / Add / Subtract choice

Global input setting

Not saved

Stands in for holding Alt (and Shift/Ctrl) on a touch screen; like a held key, it is not part of a session.

Selection candidate set (in-progress selection)

Global (shared across tools)

No

Temporary; can be confirmed into a group or canceled.

Preview highlight (while selecting)

Global, rendered per view

No

Shown only for visible cells in each view.

Highlight pages

Global (dataset-scoped)

Yes (session, dataset-dependent)

Pages are alternate “workspaces” of highlight groups.

Highlight groups (inside a page)

Global (dataset-scoped), but page-local

Yes (session, dataset-dependent)

Groups store explicit arrays of cell indices.

Active highlight page

Global

Yes (session, dataset-dependent)

Switching pages changes which groups contribute to highlighting.

Dataset identity

Global

N/A

Cell indices are meaningful only for a specific dataset ordering.

Important

If a session’s dataset fingerprint does not match the currently loaded dataset, the whole restore is rejected: no state, highlights included, is applied.


Sync between views and snapshots#

What users usually expect#

People typically expect:

  • “If I highlight cells, they should highlight in every panel.”

  • “If I select cells in one view, I should see the corresponding cells in other views.”

  • “If I switch focus to a different view panel, I shouldn’t lose my selection.”

What actually happens (current behavior)#

Permanent highlights (confirmed groups)

  • Are global: once you confirm a selection into a group, those cells are highlighted across all panels.

  • Are still subject to visibility: each panel will only show highlights for cells that are visible in that panel (filters apply per view).

Two 3D panels of the same dataset side by side with the sidebar closed, each under a title chip (1 · UMAP 3D · cell_type, 2 · UMAP 3D · cell_type): the left panel at the default close-up camera, the right panel zoomed out and rotated; the cells confirmed by one lasso drawn in the left panel are drawn in the highlight colour in both.

One lasso, drawn once in one panel, shown in two. The panels are looking at the same cells from different angles; the highlighted membership is identical because there is only one membership list for the dataset.#

Note

There is no separate “cross-highlighting” feature to switch on, and no control that links or unlinks panels for highlighting. A highlight is one list of cell indices held once for the whole dataset, and every panel packs its own draw buffer from that same list on every frame. Propagation is the default and the only behaviour; the only thing that stops a highlight appearing in a panel is that panel not drawing the cell (see below).

Analysis plots are not part of this: highlighting a set of cells in the embedding does not mark them in the plots under Analysis.

In-progress selection (candidate set + preview highlight)

  • The candidate set is global (shared across selection tools).

  • The preview highlight is global, but rendered per view (visible cells only).

  • The gesture you perform is tied to the specific panel you start it in (especially for lasso).

Annotation in multi-view grid

  • The click or drag is read on the field of the panel you press, not on the focused view’s, and selects only the cells that panel shows. View focus stays where it was.

  • So with the focused view colored by a continuous field and another panel by cell_type, an Alt+click in that other panel selects the clicked cell’s cell_type category.

Lasso in multi-view grid

  • Lasso selection is anchored to the panel you started drawing in.

  • Keep the lasso path inside one panel to avoid “wrong panel” confusion.

Proximity/KNN in multi-view

  • The seed click happens in one panel and is read with that panel’s filters; view focus stays where it was. The resulting selected indices are global.

  • Filters in the target panel can affect which cells are selectable (filtered-out cells are excluded).

The two reasons a panel does not draw a highlight#

A panel skips a highlighted cell for exactly two reasons, both of them properties of that panel and neither of them a property of the highlight:

  1. The cell is filtered out in that panel. Panels keep independent visibility, so a snapshot with stricter filters shows fewer highlighted cells than the live view.

  2. The cell is above that panel’s current level of detail. On a large dataset a zoomed-out panel draws a subset; highlights are packed from the same subset. Zooming in brings them back with no change to membership.

Everything else — camera angle, embedding dimension, coloured field, render mode — has no effect on which cells are highlighted.

Common confusion patterns (and the mental fix)#

“I selected in panel A but panel B didn’t change.”

  • Most likely: panel B is filtering out those cells (visibility differs).

  • Or: you have not confirmed (you are only seeing preview highlight, and the other panel is hiding those cells).

“My selection disappeared when I clicked another panel.”

  • Often: you changed focus, not state.

  • Look for the step controls: if they still show your step count and candidate count, the selection is still in progress.

“I switched from Grid compare to Edit selected view and things changed.”

  • Layout changes can change what you notice (one panel full size vs small multiples), but the underlying highlight page/group state is global.


Sync with filtering and color-by#

Filters and selection#

Selection tools only select cells that are not filtered out. This is intentional:

  • it prevents selecting cells you have deliberately excluded,

  • it makes selection consistent across multi-view where each panel may have different filters.

LOD/downsampling is not part of this rule. With Level of detail enabled, a gesture still evaluates unfiltered cells the view is not drawing at the current zoom, so a lasso can select more cells than you can see (Highlight mental model).

Practical workflow tip:

  • If your goal is “select all cells in category X across the dataset”, disable filters first.

Filters and confirmed highlights#

Confirmed highlights can include cells that are currently filtered out (because you confirmed them earlier when they were visible).

This is why the highlight count can show:

  • “X of Y highlighted cells visible”

Color-by and selection/highlighting#

Changing the active color-by field:

  • does not change group membership,

  • can change which selection tool behaviors are available for annotation-based selection (because that tool depends on the kind of the field of the view you click in: categorical vs continuous),

  • can change how easy it is to visually judge the correctness of your selection.


Sync with highlight pages#

What switching pages does#

Switching the active highlight page:

  • changes which groups contribute to highlighting,

  • changes what appears in the group list,

  • changes the highlight count and what is emphasized in the canvas.

What switching pages does not do#

Switching pages does not:

  • change filters (visibility masks),

  • change the dataset,

  • automatically “merge” pages (you must explicitly combine pages via union/intersection).

Page combine (union / intersection) is a reproducibility tool#

Because page combination is a deterministic set operation, it’s a good way to:

  • create a derived page that’s stable and shareable (via sessions),

  • avoid manual “redo selection” when you want intersections/unions of prior work.


Python/Jupyter synchronization (advanced)#

Cellucid has a viewer channel to the program that opened it — cellucid-python (show_anndata() in a notebook, AnnDataViewer in a browser tab) or the R package’s cellucid_view(). Conceptually, it supports two directions:

Python → UI (actions)#

Every action of the viewer is a method of the Python viewer (and a function of the R package); examples from cellucid-python include:

  • viewer.highlight_cells(cells=[...])

  • viewer.color_by(field={"source": "obs", "key": "cell_type"})

  • viewer.cells_visibility_set(cells=[...], visible=False)

These actions identify cells by row index (or obs name, which Python turns into the row). That means they only make sense when:

  • the dataset in the viewer is the one you think it is, and

  • indices are aligned with your Python object (AnnData ordering).

UI → Python (events / hooks)#

UI interactions are sent to the host on the viewer channel (one WebSocket to the Python or R server, /_cellucid/ws), so hooks like @viewer.on_hover can fire. A confirmed selection is sent as one binary frame of cell indices (little-endian uint32, ascending), so @viewer.on_selection receives selections of any size.

Important nuance for selection:

  • In notebooks, the selection event is emitted when you confirm a selection (i.e. when it becomes a real highlight group), not while you are mid-dragging with a preview highlight.

  • Hover/click events are high-frequency; hover is debounced.

If you are debugging Python synchronization, start from:

Common failure modes (Python/Jupyter)#

  • A viewer page whose viewerId / viewerToken the server no longer knows (the viewer was stopped): the channel is refused and the viewer says to run the cell again

  • Dataset mismatch (indices don’t refer to the same cells)

  • A cell still running: a notebook widget’s events reach Python between cells

  • A browser-tab viewer whose server the page cannot reach (remote/HPC without tunneling), or a proxy that does not pass WebSockets: the viewer reports Viewer disconnected

  • A browser-tab viewer whose startup failed to establish its exact configured web generation

First-line diagnostic:

  • viewer.debug_connection() in a new cell (channel state + accepted-event counts; a browser-tab viewer adds server probes, a ping/pong and a frontend debug snapshot)