spacr.qt.widgets.umap_search_viewer

Native interactive viewer and gallery for Image UMAP search results.

Unlike the general spaCR figure queue, these widgets hold the coordinate arrays themselves. A 3-D map can therefore be spun and recoloured after it has been computed, and clicking a gallery tile opens the exact embedding that was scored rather than a PNG or a stochastic refit.

The renderer uses Qt’s painter only. It has no OpenGL or pyqtgraph dependency, works in the offscreen test platform, and keeps the RAPIDS extra about compute rather than pulling in a second GUI stack.

Classes

UmapAppearanceDialog

Non-modal point renderer controls for one embedding view.

UmapEmbeddingView

A black-background 2-D/3-D point view; drag a 3-D map to spin it.

UmapExplorer

Small shell around UmapEmbeddingView with a reset control.

UmapGalleryDialog

All table embeddings on black, with a click returning the real trial.

Functions

available_colormaps(→ List[str])

Every installed Matplotlib colour map, plus spaCR's native palette.

axis_frame(→ dict)

Return projected grid lines and exactly two or three primary axes.

colors_for_labels(→ List[PySide6.QtGui.QColor])

One readable colour per point, with HDBSCAN noise in grey.

project_points(→ Tuple[numpy.ndarray, numpy.ndarray])

Orthographically project a 2-D/3-D map without distorting its axes.

thumbnail_image(→ PySide6.QtGui.QImage)

Deterministic black-background thumbnail used by the all-map grid.

Module Contents

class spacr.qt.widgets.umap_search_viewer.UmapAppearanceDialog(appearance: dict, parent: PySide6.QtWidgets.QWidget | None = None)[source]

Bases: PySide6.QtWidgets.QDialog

Non-modal point renderer controls for one embedding view.

Parameters:
  • appearance – the settings to open on, read with .get so a partial dict is legitimate and anything absent falls back to the control’s own default.

  • parent – parent widget.

NON-MODAL, which is the point: the view stays visible and usable while this is open, so a change can be judged against the picture it changes.

Build the embedding-appearance dialog.

Parameters:
  • appearance – the current settings; each control opens on its value and falls back to the view’s default when the key is absent.

  • parent – parent widget, or None.

values() → dict[source]

Whatever the controls currently read.

Returns:

the appearance settings as a plain dict.

class spacr.qt.widgets.umap_search_viewer.UmapEmbeddingView(parent: PySide6.QtWidgets.QWidget | None = None)[source]

Bases: PySide6.QtWidgets.QWidget

A black-background 2-D/3-D point view; drag a 3-D map to spin it.

Parameters:

parent – parent widget.

Create an empty embedding view.

Parameters:

parent – parent widget, or None.

clear(message: str = 'No search has been run yet.') → None[source]

Empty the view and say why it is empty.

The message is a parameter because “no search yet” and “that search returned nothing” are different situations and a blank panel cannot tell them apart.

Parameters:

message – what to show in place of the points.

contextMenuEvent(event) → None[source]

Offer the appearance editor on right-click.

Parameters:

event – the Qt context-menu event.

mouseMoveEvent(event: PySide6.QtGui.QMouseEvent) → None[source]

Spin the embedding by how far the pointer has moved.

Parameters:

event – the Qt mouse event.

mousePressEvent(event: PySide6.QtGui.QMouseEvent) → None[source]

Begin a spin drag.

Parameters:

event – the Qt mouse event.

mouseReleaseEvent(event: PySide6.QtGui.QMouseEvent) → None[source]

End a spin drag.

Parameters:

event – the Qt mouse event.

open_appearance_editor() → UmapAppearanceDialog[source]

Open the non-modal appearance editor, wired to apply live.

NON-MODAL AND LIVE, because the whole question the dialog answers is what the points look like – an editor that blocked the view it is adjusting would have to be closed to be judged.

Returns:

the dialog, already shown.

paintEvent(_event) → None[source]

Draw the points, or the empty-state message.

Parameters:

_event – the Qt paint event; unused.

reset_view() → None[source]

Put the camera back to where the embedding was first framed.

The way out of a spin or a zoom that has lost the cloud: a 3-D view can be rotated until nothing is on screen, and no amount of further dragging necessarily finds it again.

set_appearance(values: dict) → None[source]

Apply rendering-only changes without changing the embedding.

Parameters:

values – the rendering settings to change, read by the keys marker ("circle", "square", "diamond" or "cross"; anything else raises ValueError), size (clipped to 1-24), alpha (clipped to 0.05-1.0) and cmap (an unknown colour map falls back to "spaCR"). A missing key keeps its current value.

set_embedding(coords: Any, *, labels: Sequence[int] | None = None, caption: str = '', backend: str = '') → None[source]

Show an embedding.

Parameters:
  • coords – an (n, 2) or (n, 3) array of coordinates.

  • labels – one class per point, for colouring.

  • caption – text drawn under the view.

  • backend – which embedder produced this, for the caption.

set_labels(labels: Sequence[int] | None) → None[source]

Recolour the existing points by a new set of classes.

Separate from set_embedding() so a relabelling does not recompute or re-frame the layout the user is looking at.

Parameters:

labels – one class per point, or None to clear the colouring.

wheelEvent(event: PySide6.QtGui.QWheelEvent) → None[source]

Zoom the view; ignored until there is something to zoom.

Parameters:

event – the Qt wheel event.

property appearance: dict[source]

How the points are currently drawn.

Returns:

the marker, size, opacity and colouring as a plain dict.

property coordinates: numpy.ndarray | None[source]

The embedded points.

A COPY, so a caller cannot move this view’s points by writing into the array it was handed.

Returns:

an (n, dimensions) array, or None before a search.

property dimensions: int[source]

Whether the embedding is being shown in 2-D or 3-D.

Returns:

2, 3, or 0 before anything has been embedded.

property labels: numpy.ndarray | None[source]

The class of each point, when the view has been given any.

A copy, for the same reason as coordinates.

Returns:

one label per point, or None.

class spacr.qt.widgets.umap_search_viewer.UmapExplorer(parent: PySide6.QtWidgets.QWidget | None = None)[source]

Bases: PySide6.QtWidgets.QWidget

Small shell around UmapEmbeddingView with a reset control.

Parameters:

parent – parent widget.

Build the embedding view with its reset control above it.

Parameters:

parent – parent widget, or None.

class spacr.qt.widgets.umap_search_viewer.UmapGalleryDialog(trials: Iterable[Any] = (), parent: PySide6.QtWidgets.QWidget | None = None)[source]

Bases: PySide6.QtWidgets.QDialog

All table embeddings on black, with a click returning the real trial.

Parameters:
  • trials – the trials to show. Clicking one emits it through trial_chosen UNCHANGED – the gallery hands back the object it was given rather than an index into a list the caller would have to keep in step.

  • parent – parent widget.

Build the gallery of every embedding produced by a search.

Parameters:
  • trials – the trials to show, newest first is the caller’s choice.

  • parent – parent widget, or None.

set_trials(trials: Iterable[Any]) → None[source]

Show the trials that actually produced an embedding.

FILTERED, NOT ALL. A sweep’s failed or skipped trials have no embedding to show, and a gallery cell for one would be a blank tile the user has to work out the meaning of.

Parameters:

trials – every trial from the sweep.

spacr.qt.widgets.umap_search_viewer.available_colormaps() → List[str][source]

Every installed Matplotlib colour map, plus spaCR’s native palette.

spacr.qt.widgets.umap_search_viewer.axis_frame(coords: Any, width: int, height: int, *, yaw: float = 0.0, pitch: float = 0.0, zoom: float = 1.0) → dict[source]

Return projected grid lines and exactly two or three primary axes.

Parameters:
  • coords – the embedding, an array of shape (n, 2) or (n, 3); a 2-D map gets a zero third axis, and an empty, NaN-holding or otherwise shaped array raises ValueError.

  • width – width of the drawing area, in pixels.

  • height – height of the drawing area, in pixels.

  • yaw – rotation about the vertical axis, in radians.

  • pitch – rotation about the horizontal axis, in radians.

  • zoom – magnification of the fitted view, floored at 0.05.

spacr.qt.widgets.umap_search_viewer.colors_for_labels(labels: Sequence[int] | None, count: int, *, cmap: str = 'spaCR', alpha: float = 0.86) → List[PySide6.QtGui.QColor][source]

One readable colour per point, with HDBSCAN noise in grey.

Parameters:
  • labels – one cluster label per point, or None for no clusters (every point in the plain point colour under "spaCR", otherwise spread along cmap); negative labels are HDBSCAN noise and are drawn grey. Labels whose shape is not (count,) give the plain point colour for all.

  • count – number of points to colour.

  • cmap – a colour map from available_colormaps(); "spaCR" is the native palette.

  • alpha – point opacity, clipped to 0.05-1.0.

spacr.qt.widgets.umap_search_viewer.project_points(coords: Any, width: int, height: int, *, yaw: float = 0.0, pitch: float = 0.0, zoom: float = 1.0) → Tuple[numpy.ndarray, numpy.ndarray][source]

Orthographically project a 2-D/3-D map without distorting its axes.

Parameters:
  • coords – the embedding, an array of shape (n, 2) or (n, 3); a 2-D map gets a zero third axis, and an empty, NaN-holding or otherwise shaped array raises ValueError.

  • width – width of the drawing area, in pixels.

  • height – height of the drawing area, in pixels.

  • yaw – rotation about the vertical axis, in radians.

  • pitch – rotation about the horizontal axis, in radians.

  • zoom – magnification of the fitted view, floored at 0.05.

spacr.qt.widgets.umap_search_viewer.thumbnail_image(coords: Any, labels: Sequence[int] | None = None, *, size: int = 170) → PySide6.QtGui.QImage[source]

Deterministic black-background thumbnail used by the all-map grid.

Parameters:
  • coords – the embedding, an array of shape (n, 2) or (n, 3); a 2-D map gets a zero third axis, and an empty, NaN-holding or otherwise shaped array raises ValueError.

  • labels – one cluster label per point, or None; coloured as colors_for_labels() does.

  • size – side of the square thumbnail in pixels; at least 48.

Nested helpers

axis_frame.projected(points: Sequence[Sequence[float]]) → np.ndarray

Project points into the frame, in PIXEL coordinates.

The vertical is negated because screen y grows downward and the data’s does not – without it the plot is drawn upside down and still looks plausible.

spacr/qt/widgets/umap_search_viewer.py:200