spacr.qt.ortho_view

Orthogonal XY, ZX and YZ views of a volume, with the sliders that move them.

Three panels over one volume: the top view, the view from the side and the view from the end, crossing at a point the user moves with a slider or a click. spacr.layers.OrthoViews is the model — it owns the geometry, including the anisotropic voxel scaling described below — and this module is the widget over it.

The z slider is labelled in world units

Not in slice numbers. A slice number describes the file; a position such as 12.0 µm describes the sample and can be checked against the acquisition settings. The slider steps by the stack’s own voxel size, so dragging it moves one slice at a time and the number it shows is the position of the plane. On a stack with no calibration the unit is px and the step is 1, so the value equals the slice number.

Why the side panels are not one pixel per slice

Because a confocal stack is not isotropic. 0.65 µm in xy and 2 µm in z is an ordinary spaCR stack, and a side view drawn one pixel per slice is three times too thin — a picture that does not look broken, just slightly flat, and every 3-D shape read off it is wrong. spacr.layers.OrthoViews.covering() gives all three panels one world-units-per-pixel scale, so this module never divides anything by a slice count.

Classes

OrthoPanel

One plane of an orthogonal view, with the crosshair drawn on it.

OrthoView

XY, ZX and YZ over one volume, with a slider per extra dimension.

Module Contents

class spacr.qt.ortho_view.OrthoPanel(name: str, parent=None)[source]

Bases: PySide6.QtWidgets.QFrame

One plane of an orthogonal view, with the crosshair drawn on it.

Paints whatever Canvas it is given, at that canvas’s own resolution — the panel does not scale a pixmap, so the side views keep the world scale the model gave them however the widget is sized.

Parameters:
  • name – 'xy', 'zx' or 'yz'; used for the caption and reported with a click.

  • parent – parent widget; ownership only.

Build one of the three orthogonal cuts.

Parameters:
  • name – which cut this is.

  • parent – parent widget.

mousePressEvent(event) → None[source]

Move the crosshair to the clicked voxel.

Moves all three panels: an orthogonal view is three cuts through one point, so clicking in any of them re-cuts the other two.

Parameters:

event – the Qt mouse event.

paintEvent(event) → None[source]

Draw this orthogonal slice.

Parameters:

event – the Qt paint event.

show_canvas(stack: spacr.layers.LayerStack, canvas: spacr.layers.Canvas, crosshair: Dict[str, float] | None = None) → None[source]

Paint stack through canvas, with the crosshair at a point.

Parameters:
  • stack – the layer stack to paint; kept for the next repaint.

  • canvas – the Canvas that maps the stack’s world coordinates onto this panel’s pixels; it also places the crosshair.

property canvas: spacr.layers.Canvas | None[source]

The world window being painted.

property name: str[source]

Which plane this panel shows.

class spacr.qt.ortho_view.OrthoView(stack: spacr.layers.LayerStack | None = None, parent=None, *, width: int = 320, frames: int = 0, axes: Tuple[str, str, str] = OrthoViews.DEFAULT_AXES)[source]

Bases: spacr.qt.linked_selection.LinkedView, PySide6.QtWidgets.QWidget

XY, ZX and YZ over one volume, with a slider per extra dimension.

Parameters:
  • stack – the LayerStack to show. Everything in it is drawn on all three planes, so a labels layer over a z-stack is an outline in the side views too.

  • width – the top panel’s width in pixels; every other panel size follows from the world extents.

  • frames – how many timepoints there are, when the volume is one frame of a series. Adds a t slider whose changes are announced through frame_changed rather than resolved here, because loading the next timepoint is the caller’s job (and often a background one).

  • parent – parent widget; ownership only.

  • axes – the volume’s axis names, slowest first. Defaults to DEFAULT_AXES (z, y, x). These are names, not an order to apply: the array is already in this order, and this names each axis, so a volume stored t-first is described here rather than transposed.

Build the three cuts and the sliders that move them.

Parameters:
  • stack – the layers to cut through.

  • parent – parent widget.

  • width – the view’s width in pixels.

  • frames – how many time points there are.

  • axes – the world axes to cut along.

closeEvent(event) → None[source]

Leave the shared selection when the screen goes.

Parameters:

event – the close event, passed on to the base class after the view leaves the shared selection.

move_to(**coords: float) → None[source]

Move the crosshair: view.move_to(z=12.0).

Each coordinate is snapped to its own voxel grid and held inside the volume, so the crosshair is always on a plane that exists.

on_linked_selection_changed(selection) → None[source]

Move the crosshair onto the object another view selected.

Parameters:

selection – the shared Selection. Only a selection of exactly one key moves the crosshair, onto the centroid of the labels-layer object with that key.

reset_view() → None[source]

Fit the whole volume in all three panels.

set_stack(stack: spacr.layers.LayerStack) → None[source]

Show a different volume, rebuilding the sliders for its extents.

Parameters:

stack – the new layer stack; the view is refitted to it, and a stack with no volume leaves the panels empty with the reason in the status line.

slice_index(axis: str) → int[source]

Which slice the crosshair is on along axis, counting from 0.

Parameters:

axis – the world axis, one of the view’s axis names (z, y or x by default).

wheelEvent(event) → None[source]

Zoom all planes around the image position beneath the pointer.

Parameters:

event – the Qt wheel event.

zoom_in() → None[source]

Every panel one step closer, about the crosshair.

zoom_out() → None[source]

Every panel one step further away.

property stack: spacr.layers.LayerStack[source]

The stack being shown.

property views: spacr.layers.OrthoViews | None[source]

The three canvases, or None when the stack has no volume.