CellierController¶
The top-level entry point for building and driving a cellier scene.
cellier.CellierController ¶
The main class for constructing and controlling a cellier visualization.
Wraps a ViewerModel (model layer) and a RenderManager (render layer) and performs the synchronization between both.
incoming_events
property
¶
Incoming event bus for GUI-driven model mutations.
Emit AppearanceUpdateEvent, DimsUpdateEvent,
AABBUpdateEvent or BackgroundUpdateEvent onto this bus to
request model changes.
The controller dispatches each event to the corresponding
update_* method, preserving source_id end-to-end.
canvas_ids
property
¶
IDs of every canvas registered with this controller, across scenes.
Scene-scoped callers want :meth:get_canvas_ids; this is for code that
must find canvases without knowing which scene they belong to -- the Qt
window composite in
:func:~cellier.convenience.screenshot_window walks this to discover
which canvases live inside a given window.
camera_reslice_enabled
property
writable
¶
camera_reslice_enabled: bool
Whether camera movement triggers automatic reslicing.
While False the camera trackers still run and still emit
CameraInteractionEvent; only the reslices at a motion's end and
at a programmatic jump are skipped.
render_config
property
¶
render_config: RenderManagerConfig
Live rendering configuration.
Mutating a field here changes the model but not the GPU state, and
notifies no widget. :meth:update_render_config_field and the
dedicated properties (ambient_occlusion_power and friends) do all three in
one step, and are what a GUI should drive.
render_manager
property
¶
render_manager: RenderManager
The render manager owning the canvases and the GPU-side state.
outline_enabled
property
writable
¶
outline_enabled: bool
Whether the screen-space outline pass is active.
outline_boundaries_enabled
property
writable
¶
outline_boundaries_enabled: bool
Whether the boundaries layer (every outlined region) draws.
outline_selection_enabled
property
writable
¶
outline_selection_enabled: bool
Whether the selection layer (regions with a palette slot) draws.
ambient_occlusion_enabled
property
writable
¶
ambient_occlusion_enabled: bool
Whether the screen-space ambient occlusion pass is active.
Ambient occlusion darkens creases by sampling the depth buffer, and is the cheapest shape cue available for cellier's default unlit isosurfaces. It runs in 3D only.
ambient_occlusion_radius
property
writable
¶
ambient_occlusion_radius: float | None
Occlusion hemisphere radius in scene units, or None for auto.
None derives the radius from the scene bounding box diagonal
(:attr:ambient_occlusion_auto_radius_fraction, 2 percent by default), which is
the only default that means anything across cellier's coordinate
systems. :attr:ambient_occlusion_effective_radius reports what that came to.
ambient_occlusion_auto_radius_fraction
property
writable
¶
ambient_occlusion_auto_radius_fraction: float
Fraction of the scene bounding box diagonal used when radius is auto.
ambient_occlusion_effective_radius
property
¶
ambient_occlusion_effective_radius: float | None
The occlusion radius actually in use, in scene units.
The explicit :attr:ambient_occlusion_radius when one is set, otherwise the
auto-derived value. Read-only, and the number worth showing next to
the radius control: a radius means nothing until it can be compared
with the scale of the thing being rendered. None when there is
no canvas to ask.
ambient_occlusion_strength
property
writable
¶
ambient_occlusion_strength: float
How far the occlusion is applied, 0 (off) to 1 (full).
ambient_occlusion_power
property
writable
¶
ambient_occlusion_power: float
Contrast exponent applied to the occlusion before the multiply.
ambient_occlusion_bias
property
writable
¶
ambient_occlusion_bias: float
Depth-comparison bias, as a fraction of the effective radius.
Dimensionless on purpose: an absolute bias tuned for one coordinate system self-occludes a flat plane in another.
ambient_occlusion_n_samples
property
writable
¶
ambient_occlusion_n_samples: int
Hemisphere samples per pixel. Changing this recompiles the shader.
ambient_occlusion_blur_radius
property
writable
¶
ambient_occlusion_blur_radius: int
Occlusion box-blur half-width in internal pixels. Recompiles.
temporal_enabled
property
writable
¶
temporal_enabled: bool
Whether the temporal accumulation pass is active.
The pass averages successive jittered frames, which is what lets the volume raymarcher and the occlusion kernel use few samples per frame and still settle to a clean image when the camera stops. It is off in 2D whatever this says.
temporal_blend_weight
property
writable
¶
temporal_blend_weight: float
Minimum EMA blend weight for the current frame, in (0, 1].
Lower values give a smoother settled image and take longer to get there after a camera move.
camera_settle_threshold_s
property
writable
¶
camera_settle_threshold_s: float
Stillness, in seconds, after which a camera motion ends.
CameraConfig.settle_threshold_s: the camera tracker's stillness
time. A motion driven by the camera controller normally ends sooner,
when the controller stops driving the camera.
set_widget_parent ¶
set_widget_parent(parent: object) -> None
Set the Qt parent for subsequently created canvas widgets.
Only meaningful when self._gui == "qt"; the anywidget gui ignores
the parent (notebook canvases are not laid out by a Qt parent).
from_model
classmethod
¶
from_model(model: ViewerModel, widget_parent: QWidget | None = None, render_config: RenderManagerConfig | None = None) -> CellierController
Construct a controller from a serialized ViewerModel.
Iteratively adds all data stores, scenes, visuals, and canvases through the public API. The order is:
- Data stores — registered before visuals reference them.
- Scenes — registered with render_modes and lighting from model.
- Visuals — added per scene; data stores must already be present.
- Canvases — restored with camera state from model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
ViewerModel
|
A ViewerModel loaded from disk or constructed programmatically. |
required |
widget_parent
|
QWidget or None
|
Qt parent for canvas widgets. Defaults to None. |
None
|
render_config
|
RenderManagerConfig or None
|
Render pipeline configuration. Defaults to None (uses defaults). |
None
|
Returns:
| Type | Description |
|---|---|
CellierController
|
|
from_file
classmethod
¶
from_file(path: str | Path, widget_parent: QWidget | None = None, render_config: RenderManagerConfig | None = None) -> CellierController
Deserialize a ViewerModel from disk and construct a controller.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str or Path
|
Path to a JSON file previously written by |
required |
widget_parent
|
QWidget or None
|
Qt parent for canvas widgets. |
None
|
render_config
|
RenderManagerConfig or None
|
Render pipeline configuration. |
None
|
Returns:
| Type | Description |
|---|---|
CellierController
|
|
add_scene_model ¶
Register a pre-built Scene model with the controller.
Used by from_model to restore scenes from a serialized
ViewerModel, and called internally by add_scene.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene
|
Scene
|
Pre-built scene model. |
required |
Returns:
| Type | Description |
|---|---|
Scene
|
The same object passed in. |
add_scene ¶
add_scene(*, name: str = 'scene', dim: Literal['2d', '3d'] = '3d', coordinate_system: WorldAxesLike | None = None, render_modes: set[Literal['2d', '3d']] | None = None, lighting: Literal['none', 'default'] = 'none', background: BackgroundAppearance | None = None) -> Scene
Create a Scene from keyword arguments and register it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Human-readable scene name. |
'scene'
|
dim
|
'2d' or '3d'
|
Initial display dimensionality. |
'3d'
|
coordinate_system
|
WorldAxesLike or None
|
The scene's world axes: a |
None
|
render_modes
|
set or None
|
Which rendering modes visuals should support. Defaults to
|
None
|
lighting
|
'none' or 'default'
|
Pass |
'none'
|
background
|
BackgroundAppearance or None
|
Background appearance for the scene. |
None
|
Returns:
| Type | Description |
|---|---|
Scene
|
The newly created and registered Scene. |
add_data_store ¶
Register a data store and return it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data_store
|
BaseDataStore
|
The store to register. |
required |
Returns:
| Type | Description |
|---|---|
BaseDataStore
|
The same object passed in. |
add_visual ¶
add_visual(scene_id: UUID, visual_model: VisualType, data_store: BaseDataStore | None = None) -> VisualType
Register a pre-built visual model with a scene.
This is the canonical construction path used by from_model.
All typed convenience methods (add_image, add_mesh, etc.)
delegate to this method internally.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
ID of an existing scene. |
required |
visual_model
|
VisualType
|
Pre-built visual model. Its |
required |
data_store
|
BaseDataStore or None
|
If provided, register the store first (no-op if already present),
then use it. If |
None
|
Returns:
| Type | Description |
|---|---|
VisualType
|
The same visual_model passed in. |
Raises:
| Type | Description |
|---|---|
KeyError
|
If |
TypeError
|
If the visual type is not recognized. |
add_image ¶
add_image(data: ImageMemoryStore, scene_id: UUID, appearance: InMemoryImageAppearance | None = None, name: str = 'image', *, single: InMemoryImageSingleAppearance | None = None, channel_axis: int | None = None, composite: bool = False, channels: dict[int, InMemoryImageChannelAppearance] | None = None, max_channels: int = 4, transform: AffineTransform | None = None, outline: VisualOutline | None = None, ambient_occlusion: bool | None = None, pick_write: bool = True, clipping_planes: Sequence[ClippingPlane] = (), render_planes: Sequence[RenderPlane] = ()) -> ImageVisual
Add an in-memory image visual to a scene.
One visual draws the image single-channel or composited
(unified image design 3.1): composite picks the mode, single
is the appearance single mode draws with, and channels the
per-channel appearances composite mode draws with.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
ImageMemoryStore
|
The backing data store. |
required |
scene_id
|
UUID
|
ID of an existing scene. |
required |
appearance
|
InMemoryImageAppearance or None
|
Shared by both modes. |
None
|
name
|
str
|
Human-readable label. Default |
'image'
|
single
|
InMemoryImageSingleAppearance or None
|
Single mode's appearance. |
None
|
channel_axis
|
int or None
|
The data axis a composite draws channels along. It must map to a
world axis. |
None
|
composite
|
bool
|
Start in composite mode. Requires channel_axis. |
False
|
channels
|
dict[int, InMemoryImageChannelAppearance] or None
|
Composite mode's per-channel appearances. |
None
|
max_channels
|
int
|
The most channels the visual may hold. Default 4. |
4
|
transform
|
AffineTransform or None
|
The |
None
|
outline
|
VisualOutline or None
|
Screen-space outline assignment. |
None
|
ambient_occlusion
|
bool or None
|
Whether this visual receives ambient occlusion. |
None
|
pick_write
|
bool
|
Whether the visual writes to the pick buffer. Default |
True
|
clipping_planes
|
Sequence[ClippingPlane]
|
Clipping planes, in the store's level-0 data coordinates: the
visual is drawn only on the kept side of every enabled plane.
Build them from |
()
|
render_planes
|
Sequence[RenderPlane]
|
The planes the visual draws its data on in a 3D view while its
render mode is |
()
|
Returns:
| Type | Description |
|---|---|
ImageVisual
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If composite is set without channel_axis, if channel_axis maps to no world axis, if the composited axis is displayed, or if channels has more than max_channels entries. |
add_labels ¶
add_labels(data: LabelMemoryStore, scene_id: UUID, appearance: BaseLabelsAppearance | None = None, name: str = 'labels', transform: AffineTransform | None = None, outline: VisualOutline | None = None, ambient_occlusion: bool | None = None, pick_write: bool = True, outline_selected_labels: dict[int, int] | None = None, outline_mode: OutlineMode = 'per_label', clipping_planes: Sequence[ClippingPlane] = (), render_planes: Sequence[RenderPlane] = ()) -> LabelMemoryVisual
Add an in-memory label visual to a scene.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
LabelMemoryStore
|
Backing int32 label store. |
required |
scene_id
|
UUID
|
ID of an existing scene. |
required |
appearance
|
BaseLabelsAppearance or None
|
Appearance parameters. Defaults to InMemoryLabelsAppearance(). |
None
|
name
|
str
|
Human-readable label. Default |
'labels'
|
transform
|
AffineTransform or None
|
Data-to-world transform. Defaults to identity when None. |
None
|
outline
|
VisualOutline or None
|
Screen-space outline assignment. |
None
|
ambient_occlusion
|
bool or None
|
Whether this visual receives ambient occlusion. |
None
|
pick_write
|
bool
|
Whether the visual writes to the pick buffer. |
True
|
outline_selected_labels
|
dict[int, int] or None
|
Maps a label value to the palette slot the selection layer
draws it in. |
None
|
outline_mode
|
('per_label', 'whole_object', 'all_boundaries')
|
How the labels are outlined. |
"per_label"
|
clipping_planes
|
Sequence[ClippingPlane]
|
Clipping planes, in the store's level-0 data coordinates: the
visual is drawn only on the kept side of every enabled plane.
Build them from |
()
|
render_planes
|
Sequence[RenderPlane]
|
The planes the visual draws its data on in a 3D view while its
render mode is |
()
|
Returns:
| Type | Description |
|---|---|
LabelMemoryVisual
|
|
add_mesh ¶
add_mesh(data: MeshMemoryStore, scene_id: UUID, appearance: MeshAppearance, name: str = 'mesh', transform: AffineTransform | None = None, outline: VisualOutline | None = None, ambient_occlusion: bool | None = None, pick_write: bool = True, section: MeshSectionConfig | None = None, clipping_planes: Sequence[ClippingPlane] = ()) -> MeshVisual
Add a mesh visual to a scene.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
MeshMemoryStore
|
In-memory mesh. Normals are auto-computed if not supplied; indices are coerced to int32. |
required |
scene_id
|
UUID
|
ID of an existing scene. |
required |
appearance
|
MeshFlatAppearance | MeshPhongAppearance
|
Appearance. Use MeshPhongAppearance with |
required |
name
|
str
|
Human-readable label. Default |
'mesh'
|
transform
|
AffineTransform or None
|
Data-to-world transform for this visual. Defaults to identity when
|
None
|
outline
|
VisualOutline or None
|
Screen-space outline assignment. |
None
|
ambient_occlusion
|
bool or None
|
Whether this visual receives ambient occlusion. |
None
|
pick_write
|
bool
|
Whether the visual writes to the pick buffer. |
True
|
section
|
MeshSectionConfig or None
|
How the mesh is drawn in a 2D view: the outline and fill of its
cross-section, and whether the cut is the slice plane
( |
None
|
clipping_planes
|
Sequence[ClippingPlane]
|
Clipping planes, in the store's level-0 data coordinates: the
visual is drawn only on the kept side of every enabled plane.
Build them from |
()
|
Returns:
| Type | Description |
|---|---|
MeshVisual
|
|
add_multiscale_mesh ¶
add_multiscale_mesh(data: MultiscaleMeshStore, scene_id: UUID, appearance: MeshAppearance, name: str = 'mesh', transform: AffineTransform | None = None, outline: VisualOutline | None = None, ambient_occlusion: bool | None = None, pick_write: bool = True, section: MeshSectionConfig | None = None, lod: GeometryLodConfig | None = None, clipping_planes: Sequence[ClippingPlane] = ()) -> MultiscaleMeshVisual
Add a mesh with levels of detail to a scene.
Two levels are kept loaded: the finest, and one coarse level. When
the position changes the coarse level is read first, so the mesh is
back on screen sooner, and the finest replaces it when it has
loaded. A pick reports which level was drawn
(MeshPickInfo.level, 0 the finest). The bounding box and a
camera fit use the finest level's extent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
MultiscaleMeshStore
|
The mesh's levels, finest first. A store of one level loads as a plain mesh. |
required |
scene_id
|
UUID
|
ID of an existing scene. |
required |
appearance
|
MeshFlatAppearance | MeshPhongAppearance
|
Appearance, shared by both levels. Use MeshPhongAppearance with
|
required |
name
|
str
|
Human-readable label. Default |
'mesh'
|
transform
|
AffineTransform or None
|
Data-to-world transform for this visual. Defaults to identity when
|
None
|
outline
|
VisualOutline or None
|
Screen-space outline assignment; see :meth: |
None
|
ambient_occlusion
|
bool or None
|
Whether this visual receives ambient occlusion; see
:meth: |
None
|
pick_write
|
bool
|
Whether the visual writes to the pick buffer; see
:meth: |
True
|
section
|
MeshSectionConfig or None
|
How the mesh is drawn in a 2D view; see :meth: |
None
|
lod
|
GeometryLodConfig or None
|
Which coarse level is kept ( |
None
|
clipping_planes
|
Sequence[ClippingPlane]
|
Clipping planes, in the store's level-0 data coordinates: the
visual is drawn only on the kept side of every enabled plane.
Build them from |
()
|
Returns:
| Type | Description |
|---|---|
MultiscaleMeshVisual
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
add_points ¶
add_points(data: PointsMemoryStore, scene_id: UUID, appearance: PointsMarkerAppearance | None = None, name: str = 'points', transform: AffineTransform | None = None, outline: VisualOutline | None = None, ambient_occlusion: bool | None = None, pick_write: bool = True, clipping_planes: Sequence[ClippingPlane] = ()) -> PointsVisual
Add a points visual backed by a PointsMemoryStore.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
PointsMemoryStore
|
The backing data store. |
required |
scene_id
|
UUID
|
ID of the target scene. |
required |
appearance
|
PointsMarkerAppearance or None
|
Appearance model. Defaults to PointsMarkerAppearance() if None. |
None
|
name
|
str
|
Human-readable label for the visual. |
'points'
|
transform
|
AffineTransform or None
|
Data-to-world transform for this visual. Defaults to identity when
|
None
|
outline
|
VisualOutline or None
|
Screen-space outline assignment. |
None
|
ambient_occlusion
|
bool or None
|
Whether this visual receives ambient occlusion. |
None
|
pick_write
|
bool
|
Whether the visual writes to the pick buffer. |
True
|
clipping_planes
|
Sequence[ClippingPlane]
|
Clipping planes, in the store's level-0 data coordinates: the
visual is drawn only on the kept side of every enabled plane.
Build them from |
()
|
Returns:
| Type | Description |
|---|---|
PointsVisual
|
|
add_lines ¶
add_lines(data: LinesMemoryStore, scene_id: UUID, appearance: LinesMemoryAppearance | None = None, name: str = 'lines', transform: AffineTransform | None = None, outline: VisualOutline | None = None, ambient_occlusion: bool | None = None, pick_write: bool = True, clipping_planes: Sequence[ClippingPlane] = ()) -> LinesVisual
Add a lines visual backed by a LinesMemoryStore.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
LinesMemoryStore
|
The backing data store. |
required |
scene_id
|
UUID
|
ID of the target scene. |
required |
appearance
|
LinesMemoryAppearance or None
|
Appearance model. Defaults to LinesMemoryAppearance() if None. |
None
|
name
|
str
|
Human-readable label for the visual. |
'lines'
|
transform
|
AffineTransform or None
|
Data-to-world transform for this visual. Defaults to identity when
|
None
|
outline
|
VisualOutline or None
|
Screen-space outline assignment. |
None
|
ambient_occlusion
|
bool or None
|
Whether this visual receives ambient occlusion. |
None
|
pick_write
|
bool
|
Whether the visual writes to the pick buffer. |
True
|
clipping_planes
|
Sequence[ClippingPlane]
|
Clipping planes, in the store's level-0 data coordinates: the
visual is drawn only on the kept side of every enabled plane.
Build them from |
()
|
Returns:
| Type | Description |
|---|---|
LinesVisual
|
|
add_graph ¶
add_graph(data: GraphMemoryStore, scene_id: UUID, appearance: GraphAppearance | None = None, name: str = 'graph', transform: AffineTransform | None = None, trail: dict[int, TrailConfig] | None = None, outline: VisualOutline | None = None, ambient_occlusion: bool | None = None, pick_write: bool = True, clipping_planes: Sequence[ClippingPlane] = ()) -> GraphVisual
Add a spatial-graph visual backed by a GraphMemoryStore.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
GraphMemoryStore
|
The backing data store. |
required |
scene_id
|
UUID
|
ID of the target scene. |
required |
appearance
|
GraphAppearance or None
|
Appearance model. Defaults to |
None
|
name
|
str
|
Human-readable label for the visual. |
'graph'
|
transform
|
AffineTransform or None
|
Data-to-world transform for this visual. When |
None
|
trail
|
dict[int, TrailConfig] or None
|
Axis index -> window configuration. Keys are validated against
the store's |
None
|
outline
|
VisualOutline or None
|
Screen-space outline assignment. |
None
|
ambient_occlusion
|
bool or None
|
Whether this visual receives ambient occlusion. |
None
|
pick_write
|
bool
|
Whether the visual writes to the pick buffer. |
True
|
clipping_planes
|
Sequence[ClippingPlane]
|
Clipping planes, in the store's level-0 data coordinates: the
visual is drawn only on the kept side of every enabled plane.
Build them from |
()
|
Returns:
| Type | Description |
|---|---|
GraphVisual
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If any |
add_image_multiscale ¶
add_image_multiscale(data: BaseDataStore, scene_id: UUID, appearance: MultiscaleImageAppearance | None = None, name: str = 'image', render_config: MultiscaleImageRenderConfig | None = None, transform: AffineTransform | None = None, *, single: MultiscaleImageSingleAppearance | None = None, channel_axis: int | None = None, composite: bool = False, channels: dict[int, MultiscaleImageChannelAppearance] | None = None, max_channels: int = 4, outline: VisualOutline | None = None, ambient_occlusion: bool | None = None, pick_write: bool = True, clipping_planes: Sequence[ClippingPlane] = (), render_planes: Sequence[RenderPlane] = ()) -> MultiscaleImageVisual
Add a multiscale image visual to a scene.
The multiscale twin of :meth:add_image; see it for the two modes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
BaseDataStore
|
The backing multiscale data store. |
required |
scene_id
|
UUID
|
ID of an existing scene. |
required |
appearance
|
MultiscaleImageAppearance or None
|
Shared by both modes, including the LOD settings. |
None
|
name
|
str
|
Human-readable label. Default |
'image'
|
render_config
|
MultiscaleImageRenderConfig or None
|
GPU cache configuration. The budget is split evenly between the
visual's slots: one without a channel axis, |
None
|
transform
|
AffineTransform or None
|
Data-to-world transform. Defaults to identity when None. |
None
|
single
|
MultiscaleImageSingleAppearance or None
|
Single mode's appearance. |
None
|
channel_axis
|
int or None
|
The data axis a composite draws channels along. |
None
|
composite
|
bool
|
Start in composite mode. Requires channel_axis. |
False
|
channels
|
dict[int, MultiscaleImageChannelAppearance] or None
|
Composite mode's per-channel appearances. |
None
|
max_channels
|
int
|
The most channels the visual may hold. Default 4. |
4
|
outline
|
VisualOutline or None
|
Screen-space outline assignment. |
None
|
ambient_occlusion
|
bool or None
|
Whether this visual receives ambient occlusion. |
None
|
pick_write
|
bool
|
Whether the visual writes to the pick buffer. Default |
True
|
clipping_planes
|
Sequence[ClippingPlane]
|
Clipping planes, in the store's level-0 data coordinates: the
visual is drawn only on the kept side of every enabled plane.
Build them from |
()
|
render_planes
|
Sequence[RenderPlane]
|
The planes the visual draws its data on in a 3D view while its
render mode is |
()
|
Returns:
| Type | Description |
|---|---|
MultiscaleImageVisual
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
As :meth: |
add_labels_multiscale ¶
add_labels_multiscale(data: BaseDataStore, scene_id: UUID, appearance: MultiscaleLabelsAppearance, name: str = 'labels', render_config: MultiscaleLabelRenderConfig | None = None, transform: AffineTransform | None = None, outline: VisualOutline | None = None, ambient_occlusion: bool | None = None, pick_write: bool = True, outline_selected_labels: dict[int, int] | None = None, outline_mode: OutlineMode = 'per_label', clipping_planes: Sequence[ClippingPlane] = (), render_planes: Sequence[RenderPlane] = ()) -> MultiscaleLabelVisual
Add a multiscale label visual to a scene.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
BaseDataStore
|
The backing label data store (e.g. |
required |
scene_id
|
UUID
|
ID of an existing scene. |
required |
appearance
|
MultiscaleLabelsAppearance
|
Visual appearance parameters. |
required |
name
|
str
|
Human-readable label. Default |
'labels'
|
render_config
|
MultiscaleLabelRenderConfig or None
|
Render-layer configuration. Defaults to
|
None
|
transform
|
AffineTransform or None
|
Data-to-world transform. Defaults to identity when None. |
None
|
outline
|
VisualOutline or None
|
Screen-space outline assignment. |
None
|
ambient_occlusion
|
bool or None
|
Whether this visual receives ambient occlusion. |
None
|
pick_write
|
bool
|
Whether the visual writes to the pick buffer. |
True
|
outline_selected_labels
|
dict[int, int] or None
|
Maps a label value to the palette slot the selection layer
draws it in. |
None
|
outline_mode
|
('per_label', 'whole_object', 'all_boundaries')
|
How the labels are outlined. |
"per_label"
|
clipping_planes
|
Sequence[ClippingPlane]
|
Clipping planes, in the store's level-0 data coordinates: the
visual is drawn only on the kept side of every enabled plane.
Build them from |
()
|
render_planes
|
Sequence[RenderPlane]
|
The planes the visual draws its data on in a 3D view while its
render mode is |
()
|
Returns:
| Type | Description |
|---|---|
MultiscaleLabelVisual
|
|
add_channel ¶
add_channel(visual_id: UUID, channel_index: int, appearance: InMemoryImageChannelAppearance | MultiscaleImageChannelAppearance) -> None
Add a channel to an image visual's composite channels.
The channels bridge reslices the visual, so a composite draws the
new channel straight away.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
ID of an |
required |
channel_index
|
int
|
Index along the visual's |
required |
appearance
|
channel appearance
|
The channel's appearance, of the visual's own family. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the visual has no |
remove_channel ¶
Remove a channel from an image visual's composite channels.
Any channel may be removed, including the last (D35); an empty
composite draws nothing. The channels bridge reslices.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
ID of an |
required |
channel_index
|
int
|
Index of the channel to remove. |
required |
Raises:
| Type | Description |
|---|---|
KeyError
|
If channel_index is not in visual.channels. |
add_canvas_overlay ¶
add_canvas_overlay(canvas_id: UUID, overlay: CanvasOverlay) -> CanvasOverlay
Attach a screen-space overlay to a specific canvas.
The overlay is rendered as a post-pass on top of the main scene each
frame. It does not participate in reslicing, has no world-space
transform, and is not added to scene.visuals. It is stored in the
Canvas.overlays list of canvas_id, making it part of the
serializable model, and its fields are live: assign to them directly
or through :meth:update_overlay_field.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_id
|
UUID
|
ID of the canvas that should display the overlay. Use
:meth: |
required |
overlay
|
CanvasOverlay
|
Model-layer overlay description, e.g. a
:class: |
required |
Returns:
| Type | Description |
|---|---|
CanvasOverlay
|
The same overlay object passed in (for ID access or chaining). |
Raises:
| Type | Description |
|---|---|
KeyError
|
If canvas_id is not registered. |
ValueError
|
If an overlay with the same id is already registered. |
add_scene_overlay ¶
add_scene_overlay(scene_id: UUID, overlay: SceneOverlay) -> SceneOverlay
Attach a world-space overlay to a scene.
The overlay is drawn in the scene's world by the scene camera, in the
main pass, on every canvas showing the scene. Its geometry follows
the scene: it is rebuilt when visuals are added or removed, a
transform is replaced, the displayed axes change, or a store changes
(signalled by :meth:reslice_visual). It is stored in
Scene.overlays, and its fields are live.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
ID of the scene that should hold the overlay. |
required |
overlay
|
SceneOverlay
|
Model-layer overlay description, e.g. a
:class: |
required |
Returns:
| Type | Description |
|---|---|
SceneOverlay
|
The same overlay object passed in. |
Raises:
| Type | Description |
|---|---|
KeyError
|
If scene_id is not registered. |
ValueError
|
If an overlay with the same id is already registered. |
NotImplementedError
|
If the scene's selection is not axis aligned. |
get_overlay ¶
get_overlay(overlay_id: UUID) -> CanvasOverlay | SceneOverlay
Return the overlay model registered under overlay_id.
Raises:
| Type | Description |
|---|---|
KeyError
|
If no overlay with that id is registered. |
remove_overlay ¶
remove_overlay(overlay_id: UUID) -> None
Remove an overlay of either category.
Disconnects its bridge, detaches it from the render layer, and removes
it from Canvas.overlays / Scene.overlays.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
overlay_id
|
UUID
|
ID of the overlay to remove. |
required |
Raises:
| Type | Description |
|---|---|
KeyError
|
If no overlay with that id is registered. |
update_overlay_field ¶
update_overlay_field(overlay_id: UUID, field: str, value: Any, *, source_id: UUID | None = None) -> None
Set one field on an overlay model.
Tags the emitted OverlayChangedEvent with source_id. GUI
widgets should pass source_id=self._id so their own subscription
can ignore the echo.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
overlay_id
|
UUID
|
Target overlay, of either category. |
required |
field
|
str
|
Dotted path on the overlay model: |
required |
value
|
Any
|
New value for the field. |
required |
source_id
|
UUID or None
|
UUID to stamp on the emitted event. Defaults to the controller's own ID. |
None
|
Raises:
| Type | Description |
|---|---|
KeyError
|
If no overlay with that id is registered. |
set_overlay_visible ¶
Show or hide an overlay of either category.
Equivalent to update_overlay_field(overlay_id, "visible", visible).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
overlay_id
|
UUID
|
ID of the overlay. |
required |
visible
|
bool
|
|
required |
source_id
|
UUID or None
|
UUID to stamp on the emitted |
None
|
Raises:
| Type | Description |
|---|---|
KeyError
|
If no overlay with |
add_canvas ¶
add_canvas(scene_id: UUID, render_modes: set[str] | None = None, initial_dim: str | None = None, fov: float = 70.0, depth_range_3d: tuple[float, float] = (1.0, 8000.0), depth_range_2d: tuple[float, float] = (-500.0, 500.0), canvas_size: tuple[int, int] | None = None) -> QWidget
Create a canvas attached to a scene and return its embeddable widget.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
ID of an existing scene. |
required |
render_modes
|
set[str] or None
|
Which camera modes to prepare on the canvas. Each entry must be
|
None
|
initial_dim
|
str or None
|
Which mode is active when the canvas first appears. Must be a
member of |
None
|
fov
|
float
|
Vertical field of view in degrees for the 3D perspective camera.
Ignored when |
70.0
|
depth_range_3d
|
tuple[float, float]
|
|
(1.0, 8000.0)
|
depth_range_2d
|
tuple[float, float]
|
|
(-500.0, 500.0)
|
canvas_size
|
tuple[int, int] or None
|
Initial CSS pixel size for the anywidget canvas. Ignored for the
Qt gui (which is sized by its parent layout). Defaults to
|
None
|
Returns:
| Type | Description |
|---|---|
QWidget
|
The render widget. Embed with |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
add_canvas_model ¶
add_canvas_model(scene_id: UUID, canvas_model: Canvas, initial_dim: str | None = None, canvas_size: tuple[int, int] | None = None) -> QWidget
Register a pre-built Canvas model with a scene.
Used by from_model to restore canvases from a serialized
ViewerModel, and called internally by add_canvas. Camera state
(position, rotation, fov, depth range) is read from the camera models
stored in canvas_model.cameras.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
ID of an existing scene. |
required |
canvas_model
|
Canvas
|
Pre-built canvas model. Must have at least one entry in
|
required |
initial_dim
|
str or None
|
Which dim to activate first. When |
None
|
canvas_size
|
tuple[int, int] or None
|
Initial CSS pixel size for the anywidget canvas. Ignored for the
Qt gui. Defaults to |
None
|
Returns:
| Type | Description |
|---|---|
QWidget
|
The render widget. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
get_visual_scene_id ¶
fit_camera ¶
Fit the camera to the current scene bounding box.
Safe to call immediately after add_image / add_image_multiscale
and transform assignment — the node matrix is set at construction time
so no chunk data needs to be loaded first.
The move is a jump: camera-sensitive visuals (multiscale image
and labels) reslice at once for the fitted view, and a camera motion
in progress on the canvas ends. A fit that leaves the camera where
it is does nothing. See :meth:set_camera_state for interactive.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
ID of the scene whose camera should be fitted. |
required |
canvas_id
|
UUID or None
|
If provided, fit only that canvas. When |
None
|
interactive
|
bool
|
Whether the move is a tick of a camera motion instead of a jump. |
False
|
get_scene_by_name ¶
Return the live Scene model for the given name.
Raises KeyError if no scene with that name exists.
get_canvas_ids ¶
get_canvas_view ¶
get_canvas_view(canvas_id: UUID) -> CanvasView
Return the render-layer CanvasView for canvas_id.
Provides access to the rendering backend (camera, widget, overlays)
for a canvas registered via :meth:add_canvas or
:meth:add_canvas_model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_id
|
UUID
|
ID of a registered canvas. |
required |
Returns:
| Type | Description |
|---|---|
CanvasView
|
|
Raises:
| Type | Description |
|---|---|
KeyError
|
If canvas_id is not registered. |
get_camera_state ¶
get_camera_state(canvas_id: UUID) -> CameraState
Return a snapshot of the current camera state for canvas_id.
Useful for seeding downstream widgets (e.g. orientation overlays)
with the post-fit camera state without constructing a synthetic
CameraChangedEvent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_id
|
UUID
|
ID of a registered canvas. |
required |
Returns:
| Type | Description |
|---|---|
CameraState
|
|
Raises:
| Type | Description |
|---|---|
KeyError
|
If canvas_id is not registered. |
screenshot ¶
screenshot(canvas_id: UUID, size: tuple[int, int] | None = None, scale: float = 1.0, *, frames: int | Literal['converged'] = 1, **capture_kwargs) -> ndarray
Capture a reproducible screenshot as an RGBA uint8 array.
The frame is rendered on a dedicated offscreen canvas built on the same scene, not read back from the canvas on screen. Two captures of the same viewer state therefore produce byte-identical arrays (on the same machine and GPU driver), at exactly the size asked for, whether or not anything is on screen and whichever GUI toolkit is in use.
canvas_id selects a viewpoint, not a surface: the capture copies
that canvas's camera, dimensionality and depth range, then renders its
own frame. Use :meth:screenshot_scene to capture a scene that has
no canvas at all.
What the capture shows is the data currently resident on the GPU.
It does not reslice, so a multiscale scene is captured at the level of
detail already loaded; a higher scale enlarges that level rather
than fetching a finer one. Call :meth:on_scene_ready (or use the
convenience launchers' on_ready) before capturing if a load may
still be in flight.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_id
|
UUID
|
ID of a registered canvas, whose viewpoint the capture copies. |
required |
size
|
tuple[int, int] or None
|
Target |
None
|
scale
|
float
|
Multiplier applied to size. |
1.0
|
frames
|
int or 'converged'
|
|
1
|
**capture_kwargs
|
Forwarded to the capture helper ( |
{}
|
Returns:
| Type | Description |
|---|---|
ndarray
|
RGBA uint8 array of shape |
Raises:
| Type | Description |
|---|---|
KeyError
|
If canvas_id is not registered. |
RuntimeError
|
If |
screenshot_scene ¶
screenshot_scene(scene_id: UUID, size: tuple[int, int] | None = None, scale: float = 1.0, *, frames: int | Literal['converged'] = 1, dim: str | None = None, **capture_kwargs) -> ndarray
Capture scene_id without needing a canvas to exist.
The same offscreen capture as :meth:screenshot, but with the camera
fitted to the scene rather than copied from a canvas -- so a scene can
be captured with no window, no widget and no event loop.
A scene with no canvas has no data. Slice requests are planned
per canvas, from its camera, size and frustum, so reslice_all on a
scene with no canvas requests nothing and this returns a correct
picture of an empty scene. Add a canvas (add_canvas) and let the
reslice complete before capturing; cellier.convenience.capture does exactly
that. This method's own fit is for the case where a canvas exists but
its viewpoint is not the one you want.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
ID of the scene to render. |
required |
size
|
tuple[int, int] or None
|
Target |
None
|
scale
|
float
|
Multiplier applied to size. |
1.0
|
frames
|
int or 'converged'
|
See :meth: |
1
|
dim
|
str or None
|
|
None
|
**capture_kwargs
|
Forwarded to the capture helper. |
{}
|
Returns:
| Type | Description |
|---|---|
ndarray
|
RGBA uint8 array of shape |
get_visual_model ¶
get_visual_model(visual_id: UUID) -> MultiscaleImageVisual
Return the live visual model for visual_id.
Searches all scenes. Raises KeyError if not found.
coordinate_system ¶
coordinate_system(system_id: UUID) -> CoordinateSystemType
Return the coordinate system with system_id.
Three transform methods -- map_bounding_box, then and
validate_against -- take coordinate system objects while a
transform stores only their ids, so composing anything needs this
lookup. It is a plain dict: no edges, no path finding and no
automatic composition (D15).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
system_id
|
UUID
|
The system's id. |
required |
Returns:
| Type | Description |
|---|---|
CoordinateSystemType
|
The registered system. |
Raises:
| Type | Description |
|---|---|
KeyError
|
If no system with that id is registered. A stored transform naming an unregistered system usually means it outlived the scene or store that owned its endpoint. |
render_spaces ¶
render_spaces(visual_id: UUID) -> RenderSpaces | None
The systems a visual's render-layer counterpart places geometry with.
None when the visual is not placeable yet -- its store has no
coordinate systems, or the scene has no canvas and so no rendered
system.
visuals_outlined_beyond ¶
Return (name, slot) for visuals outlined past n_slots.
The slots a palette of n_slots entries cannot colour. Useful to a GUI before it shrinks the palette, and to the palette route after.
slot_usage ¶
Return {slot: how many visuals use it}, for slots 1 and up.
What lets a palette editor show that slot 2 is three visuals rather than leaving the user to hold it in their head.
update_visual_render_field ¶
update_visual_render_field(visual_id: UUID, field: str, value: Any, *, source_id: UUID | None = None) -> None
Set one screen-space render field on a visual.
The seam a GUI drives, and the twin of
:meth:update_render_config_field for the per-visual half. Writes
the model; the psygnal bridge does the rest.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
Target visual. |
required |
field
|
str
|
|
required |
value
|
Any
|
New value for the field. |
required |
source_id
|
UUID | None
|
UUID to stamp on the emitted |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If field is not a settable per-visual render field. |
set_loading_config ¶
set_loading_config(visual_id: UUID, *, source_id: UUID | None = None, **fields: Any) -> ProgressiveLoadingConfig
Change how a multiscale visual loads, while it is shown.
Merges fields into the visual's current
render_config.loading and applies the result at once: the visual
replans with the new settings and keeps what it has loaded. Emits
LoadingConfigChangedEvent. Nothing happens when the merged
config equals the current one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
A multiscale image or labels visual. |
required |
source_id
|
UUID | None
|
UUID to stamp on the emitted |
None
|
**fields
|
Any
|
|
{}
|
Returns:
| Type | Description |
|---|---|
ProgressiveLoadingConfig
|
The visual's config after the call. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If the visual is not a multiscale image or labels visual. |
ValueError
|
If a field name is unknown, or the merged config is invalid
(e.g. |
update_visual_trail ¶
update_visual_trail(visual_id: UUID, axis: int, config: TrailConfig | None, *, source_id: UUID | None = None) -> None
Set or clear the trail window on one axis of a graph visual.
The seam a GUI drives. An axis that already has a window is edited
in place, one field event per field that differs, so nudging one spin
box reslices once rather than rebuilding the whole trail. Adding or
removing an axis replaces visual.trail, which is what rewires the
per-config handlers (see :meth:_wire_trail).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
Target graph visual. |
required |
axis
|
int
|
The data-axis index the window is keyed by. |
required |
config
|
TrailConfig | None
|
The complete window for axis, or |
required |
source_id
|
UUID | None
|
UUID to stamp on the emitted |
None
|
Raises:
| Type | Description |
|---|---|
TypeError
|
If the visual is not a graph visual. |
ValueError
|
If axis is out of range for the graph's store. |
reslice_scene ¶
reslice_scene(scene_id: UUID, *, on_ready: Callable[[], None] | None = None, owner_id: UUID | None = None) -> None
Trigger a data load for all visuals in one scene.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
ID of the scene to reslice. |
required |
on_ready
|
Callable[[], None] or None
|
If provided, a zero-argument callback fired exactly once after
all visuals loaded by this reslice have committed to the GPU
(across every canvas attached to the scene). Visuals with no data
in the current view (culled, empty, or hidden) do not delay it.
Works uniformly for in-memory, multiscale, multichannel, and
geometry visuals. See :meth: The callback tracks this reslice generation. If a superseding reslice (e.g. a camera-motion reload) cancels these in-flight reads before they commit, the cancelled visual never reports completion and the callback may not fire. Callers that need a guaranteed startup signal should suppress camera-driven reslicing during the load (the convenience launchers do this automatically). |
None
|
owner_id
|
UUID or None
|
Owner under which the temporary |
None
|
reslice_visual ¶
reslice_visual(visual_id: UUID) -> None
Trigger a data load for one visual.
Not needed after changing a store: stores announce their own changes
(reassigning a data field, or store.notify_changed) and the
controller reslices every visual reading them.
suppress_reslice ¶
suppress_reslice() -> Generator[None, None, None]
Context manager that blocks reslice_scene inside transform handlers.
Use this when updating a visual's transform without needing to reload its underlying data — for example, repositioning a static-geometry mesh by translation only.
.. warning::
_suppress_reslice is a flat boolean. Nested calls or concurrent
async tasks that mutate transforms inside overlapping
suppress_reslice blocks will interfere. Replace with a depth
counter if that becomes necessary.
data_to_world ¶
data_to_world(scene_id: UUID, data_store: Any, scale: Sequence[float] | None = None, translation: Sequence[float] | None = None) -> AffineTransform
Build a data -> world transform from a per-axis scale and offset.
A transform names the two coordinate systems it maps between, and only the viewer knows both: the store's level-0 system and the scene's world. This is the short way to say "this dataset is 4 um in z and sits 10 um along it" without assembling an axis map by hand.
Before Phase 8 the same thing was said with a bare
v1 AffineTransform, which stated the numbers and
named nothing; add_* accepted one and attached the endpoints
itself. That went with v1, and this replaces it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
The scene whose world the transform maps into. |
required |
data_store
|
Any
|
The store whose voxel space it maps from. Given its coordinate systems if it does not have them. |
required |
scale
|
Sequence[float] or None
|
Per-data-axis scale. |
None
|
translation
|
Sequence[float] or None
|
Per-data-axis offset, in world units. |
None
|
Returns:
| Type | Description |
|---|---|
AffineTransform
|
Ready to hand to any |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the store and the world disagree about how many axes they
have: the correspondence here is positional, so there is nothing
to infer. Use |
set_visual_transform ¶
set_visual_transform(visual_id: UUID, transform: AffineTransform, *, reslice: bool = True) -> None
Update the data-to-world transform of a visual.
Assigns transform to the live visual model, which fires its psygnal field event and propagates the change to the render layer via the event bus.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
ID of the visual to update. |
required |
transform
|
AffineTransform
|
New data-to-world transform. |
required |
reslice
|
bool
|
If True (default), a full reslice is triggered after the transform is applied — required for image visuals where the transform changes which data falls in the current slab. Pass False for static-geometry visuals (mesh, points, lines) where the transform only repositions the node and the underlying data is unchanged. |
True
|
begin_dims_interaction ¶
Open a dims interaction scope on a scene.
While any scope is open, every slice-position change on the scene is
a scrub tick, whatever its interactive flag: visuals that opted
in plan coarse, and plan in full when the scrub ends. Opening a
scope starts nothing by itself; the first tick does. Holding still
for SchedulerConfig.dims_settle_s still ends a scrub, and the
next tick starts a new one.
A slider calls this when it is pressed. Scripts normally use
:meth:dims_interaction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
The scene whose dims are about to be scrubbed. |
required |
source_id
|
UUID
|
Who holds the scope. One scope is counted per source. |
required |
Raises:
| Type | Description |
|---|---|
KeyError
|
If scene_id is not registered. |
end_dims_interaction ¶
Close a dims interaction scope opened by source_id.
Closing the last open scope ends a scrub at once ("release"):
the visuals that planned coarse plan in full without waiting for the
stillness time. Closing a scope that is not open does nothing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
The scene the scope was opened on. |
required |
source_id
|
UUID
|
The source that opened it. |
required |
dims_interaction ¶
Scrub a scene's dims for the length of a with block.
Every :meth:update_slice_indices inside the block is a scrub tick,
so a player or a scripted sweep loads coarse while it runs and in
full when the block exits::
with controller.dims_interaction(scene_id):
for t in frames:
controller.update_slice_indices(scene_id, {0: t})
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
The scene to scrub. |
required |
dims_interaction_state ¶
Whether scene_id's dims are being scrubbed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
The scene to query. |
required |
Returns:
| Type | Description |
|---|---|
{'idle', 'active'}
|
|
update_slice_indices ¶
update_slice_indices(scene_id: UUID, slice_indices: Mapping[int, float], *, source_id: UUID | None = None, interactive: bool = False) -> None
Move the slice position of one or more world axes on a scene.
Merges into the scene's positions: axes absent from slice_indices keep theirs. Every world axis has a position whether or not it is displayed (D36), so this never adds or removes one.
Tags the emitted bus event with source_id.
GUI widgets should pass source_id=self._id so their own
DimsChangedEvent subscription can ignore the echo.
By default the move is a jump: every visual plans in full at
once, and a scrub in progress on the scene ends. With
interactive=True, or inside an open scope
(:meth:dims_interaction), it is a tick of a scrub: visuals
that opted in (coarsest_while_moving_3d or _2d) plan coarse, and plan in
full when the scrub ends, on release or after
SchedulerConfig.dims_settle_s of stillness. A call that moves no
sliced axis is neither.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
Target scene. |
required |
slice_indices
|
Mapping[int, float]
|
Mapping of world axis index -> world slice position. |
required |
source_id
|
UUID | None
|
UUID to stamp on the emitted |
None
|
interactive
|
bool
|
Whether the move is a tick of a scrub. Sliders pass |
False
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If a key is not an axis of the scene's world. Nothing is changed. |
update_thickness ¶
update_thickness(scene_id: UUID, thickness: Mapping[int, float], *, source_id: UUID | None = None) -> None
Replace a scene's per-axis half-thicknesses.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
Target scene. |
required |
thickness
|
Mapping[int, float]
|
World axis index -> half-thickness in world units. An axis absent from the mapping slices a plane. |
required |
source_id
|
UUID | None
|
UUID to stamp on the emitted |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If a key is not an axis of the scene's world. |
set_slider_override ¶
set_slider_override(scene_id: UUID, axis: int, value: bool | None, *, source_id: UUID | None = None) -> None
Force a world axis's slider shown or hidden, or return it to automatic.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
Target scene. |
required |
axis
|
int
|
World axis index. |
required |
value
|
bool | None
|
|
required |
source_id
|
UUID | None
|
UUID to stamp on the |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If axis is not an axis of the scene's world. |
update_appearance_field ¶
update_appearance_field(visual_id: UUID, field: str, value: Any, *, source_id: UUID | None = None) -> None
Set one field on a visual's appearance model.
Tags the emitted bus event with source_id.
GUI widgets should pass source_id=self._id so their own
AppearanceChangedEvent subscription can ignore the echo.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
Target visual. |
required |
field
|
str
|
Attribute name on the appearance model, e.g. |
required |
value
|
Any
|
New value for the field. |
required |
source_id
|
UUID | None
|
UUID to stamp on the emitted |
None
|
update_background_field ¶
update_background_field(scene_id: UUID, field: str, value: Any, *, source_id: UUID | None = None) -> None
Set one field on a scene's background appearance model.
Tags the emitted bus event with source_id. GUI widgets should pass
source_id=self._id so their own BackgroundChangedEvent
subscription can ignore the echo.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
Target scene. |
required |
field
|
str
|
Attribute name on the background model, e.g. |
required |
value
|
Any
|
New value for the field. |
required |
source_id
|
UUID | None
|
UUID to stamp on the emitted |
None
|
set_background ¶
set_background(scene_id: UUID, background: BackgroundAppearance, *, source_id: UUID | None = None) -> None
Replace a scene's background appearance model wholesale.
Emits a single BackgroundChangedEvent with field_name=None.
Assigning scene.background directly does the same thing; this
method exists to stamp a source_id on the resulting event.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
Target scene. |
required |
background
|
BackgroundAppearance
|
The background appearance to apply. |
required |
source_id
|
UUID | None
|
UUID to stamp on the emitted |
None
|
update_appearance_group_field ¶
update_appearance_group_field(visual_ids: list[UUID], field: str, value: Any, *, source_id: UUID | None = None) -> None
Set one appearance field across a group of visuals in lock-step.
Fan-out over :meth:update_appearance_field so every visual in the
group -- the per-panel visuals of an OrthoViewer, say -- receives
the same change. This is the programmatic write-side companion to the
widget subscribe-to-all read side, matching
:meth:update_channel_group_field.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_ids
|
list[UUID]
|
Target visuals, kept equal. |
required |
field
|
str
|
Attribute name on each appearance model, e.g. |
required |
value
|
Any
|
New value for the field. |
required |
source_id
|
UUID | None
|
UUID to stamp on each emitted event. Defaults to the controller's own ID. |
None
|
update_aabb_group_field ¶
update_aabb_group_field(visual_ids: list[UUID], field: str, value: Any, *, source_id: UUID | None = None) -> None
Set one AABB field across a group of visuals in lock-step.
The AABB is not an appearance field: it lives on visual.aabb
and travels on AABBChangedEvent, so it needs its own group helper
rather than riding on :meth:update_appearance_group_field.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_ids
|
list[UUID]
|
Target visuals, kept equal. |
required |
field
|
str
|
Attribute name on each AABB model, e.g. |
required |
value
|
Any
|
New value for the field. |
required |
source_id
|
UUID | None
|
UUID to stamp on each emitted |
None
|
update_channel_appearance_field ¶
update_channel_appearance_field(visual_id: UUID, channel_index: int, field: str, value: Any, *, source_id: UUID | None = None) -> None
Set one field on one channel of an image visual.
Tags the emitted bus event with source_id. GUI widgets should pass
source_id=self._id so their own ChannelAppearanceChangedEvent
subscription can ignore the echo.
This mutates a single visual only. When a channel is shared in
lock-step across several panels (e.g. an OrthoViewer), calling this
on one panel's visual leaves the sibling panels unequal until they are
written too; use update_channel_group_field to keep the group in
lock-step.
A pydantic.ValidationError from a malformed value is allowed to
propagate (matching update_appearance_field).
render_mode is the exception to "one channel": every channel of
an image has the same render mode, so setting it here sets it on all
of them, as :meth:set_image_render_mode does. source_id is
stamped on this channel's event only; the other channels' events
carry the controller's id, so the caller's echo filter lets them
through.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
Target visual. |
required |
channel_index
|
int
|
Index into |
required |
field
|
str
|
Attribute name on the channel appearance model, e.g. |
required |
value
|
Any
|
New value for the field. |
required |
source_id
|
UUID | None
|
UUID to stamp on the emitted |
None
|
update_channel_group_field ¶
update_channel_group_field(visual_ids: list[UUID], channel_index: int, field: str, value: Any, *, source_id: UUID | None = None) -> None
Set one channel field across a group of visuals in lock-step.
Fan-out over update_channel_appearance_field so every visual in the
group (e.g. the per-panel visuals of an OrthoViewer) receives the
same channel change. This is the programmatic write-side companion to
the widget subscribe-to-all read side.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_ids
|
list[UUID]
|
Target visuals sharing the channel set. |
required |
channel_index
|
int
|
Index into each visual's |
required |
field
|
str
|
Attribute name on the channel appearance model. |
required |
value
|
Any
|
New value for the field. |
required |
source_id
|
UUID | None
|
UUID to stamp on each emitted |
None
|
update_single_appearance_field ¶
update_single_appearance_field(visual_id: UUID, field: str, value: Any, *, source_id: UUID | None = None) -> None
Set one field on an image visual's single-mode appearance.
A pydantic.ValidationError from a malformed value propagates.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
Target image visual. |
required |
field
|
str
|
Attribute name on |
required |
value
|
Any
|
New value for the field. |
required |
source_id
|
UUID | None
|
UUID to stamp on the emitted |
None
|
update_single_group_field ¶
update_single_group_field(visual_ids: list[UUID], field: str, value: Any, *, source_id: UUID | None = None) -> None
Set one single-mode field across a group of image visuals in lock-step.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_ids
|
list[UUID]
|
Target visuals, kept equal -- an |
required |
field
|
str
|
Attribute name on each |
required |
value
|
Any
|
New value for the field. |
required |
source_id
|
UUID | None
|
UUID to stamp on each emitted event. |
None
|
set_image_render_mode ¶
Set the render mode of every channel of an image visual.
Every entry of visual.channels has the same render_mode, so
the mode is set here, on all of them at once. Assigning it to one
channel of several is refused. single.render_mode, which single
mode draws with, is separate and is not touched.
One ChannelAppearanceChangedEvent is emitted per channel whose
mode changed. Entering or leaving "plane" mode reslices the
visual once.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
Target visual: an image visual. |
required |
render_mode
|
str
|
The new mode, e.g. |
required |
source_id
|
UUID | None
|
UUID to stamp on the emitted events. Defaults to the controller's own ID. |
None
|
Raises:
| Type | Description |
|---|---|
TypeError
|
If the visual is not an image visual. |
ValidationError
|
If render_mode is not a mode of the visual's channels. Nothing is changed. |
set_image_composite ¶
Switch an image visual between single and composite mode.
Validates, then assigns. The reslice, ImageCompositeChangedEvent
and any SliderAxesChangedEvent come from the composite model
bridge, so a direct visual.composite = ... gets them too -- but a
direct assignment skips the checks below (design 3.4).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
Target image visual. |
required |
composite
|
bool
|
|
required |
source_id
|
UUID | None
|
UUID to stamp on the emitted |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If composite is |
set_image_composite_group ¶
set_image_composite_group(visual_ids: list[UUID], composite: bool, *, source_id: UUID | None = None) -> None
Switch a group of image visuals' mode in lock-step.
Every visual is validated before any is changed, so the group is never left split between the two modes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_ids
|
list[UUID]
|
Target visuals -- an |
required |
composite
|
bool
|
|
required |
source_id
|
UUID | None
|
UUID to stamp on each emitted event. |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
As :meth: |
update_section_field ¶
update_section_field(visual_id: UUID, field: str, value: Any, *, source_id: UUID | None = None) -> None
Set one field of a mesh visual's 2D section config.
mode, outline and fill change what the mesh reads, so
the mesh loads again and is not drawn until it has;
outline_width applies at once.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
Target mesh visual. |
required |
field
|
str
|
Attribute name on |
required |
value
|
Any
|
New value for the field. |
required |
source_id
|
UUID | None
|
UUID to stamp on the emitted |
None
|
Raises:
| Type | Description |
|---|---|
TypeError
|
If the visual is not a mesh. |
set_lod_config ¶
set_lod_config(visual_id: UUID, *, source_id: UUID | None = None, **fields: Any) -> GeometryLodConfig
Change the level-of-detail settings of a multiscale mesh.
dims_drag_draw and camera_motion choose among the levels
already loaded: they apply in the next frame, with nothing read.
dims_drag decides what the next dims scrub loads. Emits
LodConfigChangedEvent. Nothing happens when the merged config
equals the current one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
Target visual. |
required |
source_id
|
UUID | None
|
UUID to stamp on the emitted |
None
|
**fields
|
Any
|
|
{}
|
Returns:
| Type | Description |
|---|---|
GeometryLodConfig
|
The visual's new config. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If the visual has no levels of detail. |
ValueError
|
If a field is unknown or its value invalid, or if
|
set_clipping_planes ¶
set_clipping_planes(visual_id: UUID, clipping_planes: Sequence[ClippingPlane], *, source_id: UUID | None = None) -> tuple[ClippingPlane, ...]
Replace a visual's clipping planes.
The same as assigning visual.clipping_planes, with the check
made before anything changes and a source_id for echo filtering.
Emits ClippingPlanesChangedEvent; nothing happens when the tuple
equals the current one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
Target visual. |
required |
clipping_planes
|
Sequence[ClippingPlane]
|
The complete new sequence of |
required |
source_id
|
UUID | None
|
UUID to stamp on the emitted |
None
|
Returns:
| Type | Description |
|---|---|
tuple[ClippingPlane, ...]
|
The visual's new planes. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If a plane is not in the visual's data coordinate system or has the wrong number of components. |
get_clipping_plane ¶
get_clipping_plane(visual_id: UUID, plane_id: UUID) -> ClippingPlane
Return one clipping plane of a visual, by the plane's id.
Raises:
| Type | Description |
|---|---|
KeyError
|
If the visual has no plane with that id. |
set_clipping_plane ¶
set_clipping_plane(visual_id: UUID, plane_id: UUID, plane: Plane, *, source_id: UUID | None = None) -> ClippingPlane
Move one clipping plane of a visual; the others stay.
The plane keeps its id, its place in the tuple and its enabled
flag. Goes through :meth:set_clipping_planes, so it emits
ClippingPlanesChangedEvent and does nothing for an equal plane.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
Target visual. |
required |
plane_id
|
UUID
|
The |
required |
plane
|
Plane
|
Its new plane, in the visual's level-0 data coordinates. |
required |
source_id
|
UUID | None
|
UUID to stamp on the emitted |
None
|
Returns:
| Type | Description |
|---|---|
ClippingPlane
|
The moved plane. |
Raises:
| Type | Description |
|---|---|
KeyError
|
If the visual has no plane with that id. |
ValueError
|
If plane is not in the visual's data coordinate system or has the wrong number of components. |
set_render_planes ¶
set_render_planes(visual_id: UUID, render_planes: Sequence[RenderPlane], *, source_id: UUID | None = None) -> tuple[RenderPlane, ...]
Replace an image or labels visual's render planes.
The same as assigning visual.render_planes, with the check made
before anything changes and a source_id for echo filtering. Emits
RenderPlanesChangedEvent; nothing happens when the tuple equals
the current one.
The planes are drawn only in a 3D view, and only while the visual's
render mode is "plane"; otherwise the tuple is stored and
announced and nothing else happens. Inside
:meth:plane_interaction the change is a tick of a drag.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
Target visual: an image or labels visual. |
required |
render_planes
|
Sequence[RenderPlane]
|
The complete new sequence of |
required |
source_id
|
UUID | None
|
UUID to stamp on the emitted |
None
|
Returns:
| Type | Description |
|---|---|
tuple[RenderPlane, ...]
|
The visual's new planes. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If the visual is not an image or labels visual. |
ValueError
|
If there are more than four planes, two share an id, a plane is not on three axes of the scene's world coordinate system, or the visual's transform does not map a plane's axes by a scale and a translation per axis. |
get_render_plane ¶
get_render_plane(visual_id: UUID, plane_id: UUID) -> RenderPlane
Return one render plane of a visual, by the plane's id.
Raises:
| Type | Description |
|---|---|
KeyError
|
If the visual has no render plane with that id. |
visual_world_extent ¶
The box a visual's data occupies, per world axis of its scene.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual. |
required |
Returns:
| Type | Description |
|---|---|
list[tuple[float, float]]
|
|
Raises:
| Type | Description |
|---|---|
KeyError
|
If visual_id is not registered. |
default_render_plane ¶
default_render_plane(visual_id: UUID) -> RenderPlane
A new render plane for a visual: centred, unbounded.
The plane a control adds: through the centre of the visual's data box, on the three world axes the scene displays, facing the first of them, unbounded on every side.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual the plane is for. It is not given the plane. |
required |
Returns:
| Type | Description |
|---|---|
RenderPlane
|
|
Raises:
| Type | Description |
|---|---|
KeyError
|
If visual_id is not registered. |
ValueError
|
If the visual's scene does not display three axes. |
render_planes_blocked ¶
Why a visual's render planes are not drawn now, or "" if they are.
A sentence a control can show: the visual is not in the "plane"
render mode, or its scene is shown in 2D (where a visual in plane
mode shows its normal slice).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual. |
required |
Returns:
| Type | Description |
|---|---|
str
|
|
set_render_plane ¶
set_render_plane(visual_id: UUID, plane_id: UUID, plane: RenderPlane, *, source_id: UUID | None = None) -> RenderPlane
Replace one render plane of a visual; the others stay.
The plane keeps its id and its place in the tuple; its pose, extents
and enabled flag are taken from plane. Goes through
:meth:set_render_planes, so it emits RenderPlanesChangedEvent
and does nothing for an equal plane.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
Target visual. |
required |
plane_id
|
UUID
|
The |
required |
plane
|
RenderPlane
|
Its new state. Its own |
required |
source_id
|
UUID | None
|
UUID to stamp on the emitted |
None
|
Returns:
| Type | Description |
|---|---|
RenderPlane
|
The plane now in the tuple. |
Raises:
| Type | Description |
|---|---|
KeyError
|
If the visual has no render plane with that id. |
ValueError
|
As :meth: |
begin_plane_interaction ¶
Open a plane interaction scope on a visual.
While any scope is open, every change of the visual's
clipping_planes, or of its render_planes while a 3D view
draws them, is a tick of one drag, announced by a
PlaneInteractionEvent at its start and its end. Opening a
scope starts nothing by itself; the first change does. Holding
still for SchedulerConfig.dims_settle_s ends a drag, and the
next change starts a new one.
A multiscale image or labels visual in a 3D view with
appearance.coarsest_while_moving_3d on (the default) plans
nothing during a drag: it keeps drawing the bricks it has, and the
backstop where the planes reveal more. Its target is planned when
the drag ends, once its scene's dims and cameras are still too.
With the setting off, and for every other visual, a plane change
inside a drag plans as it does outside one.
A plane gizmo calls this when a handle is grabbed.
Scripts normally use :meth:plane_interaction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual whose planes are about to be dragged. |
required |
source_id
|
UUID
|
Who holds the scope. One scope is counted per source. |
required |
Raises:
| Type | Description |
|---|---|
KeyError
|
If visual_id is not registered. |
end_plane_interaction ¶
Close a plane interaction scope opened by source_id.
Closing the last open scope ends a drag at once ("release").
Closing a scope that is not open does nothing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual the scope was opened on. |
required |
source_id
|
UUID
|
The source that opened it. |
required |
plane_interaction ¶
Drag a visual's planes for the length of a with block.
Every change of clipping_planes or render_planes inside the
block belongs to one drag::
with controller.plane_interaction(visual.id):
for offset in offsets:
controller.set_clipping_plane(visual.id, plane_id, ...)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual whose planes are dragged. |
required |
plane_interaction_state ¶
Whether visual_id's clipping or render planes are being dragged.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual to query. |
required |
Returns:
| Type | Description |
|---|---|
{'idle', 'active'}
|
|
add_clipping_plane_gizmo ¶
add_clipping_plane_gizmo(visual_id: UUID, canvas_id: UUID, plane_id: UUID, *, source_id: UUID | None = None, screen_size: float = 100.0) -> ClippingPlaneGizmoController
Put a gizmo on one clipping plane of a visual, in a 3D canvas.
Dragging the gizmo moves and tilts the plane; a plane changed from anywhere else moves the gizmo. A canvas has one gizmo at a time: the one it had is closed. The gizmo closes itself when its plane or its visual is removed, when the canvas leaves 3D, and when the plane gains a component on an axis the view does not show.
The canvas's one gizmo serves both kinds of plane: a gizmo on a
render plane (:meth:add_render_plane_gizmo) is closed too.
Emits PlaneGizmoChangedEvent with kind="clipping".
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual the plane belongs to. |
required |
canvas_id
|
UUID
|
A 3D canvas of the visual's scene. |
required |
plane_id
|
UUID
|
The |
required |
source_id
|
UUID or None
|
Stamped on the emitted |
None
|
screen_size
|
float
|
The gizmo's size on screen, in logical pixels. |
100.0
|
Returns:
| Type | Description |
|---|---|
ClippingPlaneGizmoController
|
The session. |
Raises:
| Type | Description |
|---|---|
KeyError
|
If the canvas or the visual is not registered, or the visual has no plane with that id. |
ValueError
|
If the canvas is in 2D, the visual is not in the canvas's scene, or the plane has a component on an axis the view does not show. The canvas keeps the gizmo it had. |
add_render_plane_gizmo ¶
add_render_plane_gizmo(visual_id: UUID, canvas_id: UUID, plane_id: UUID, *, source_id: UUID | None = None, screen_size: float = 100.0) -> RenderPlaneGizmoController
Put a gizmo on one render plane of a visual, in a 3D canvas.
The gizmo carries the plane's whole pose. Dragging a translate
handle moves the plane's origin, a rotation ring turns its
in-plane axes, and a scale handle on an in-plane axis multiplies
that axis's extent about the origin (an axis with an unbounded side
has no scale handle). A plane changed from anywhere else moves the
gizmo. Each drag is one plane interaction on the visual.
A canvas has one gizmo at a time, whatever the kind of plane: the
one it had is closed. The gizmo closes itself when its plane or
its visual is removed, when the canvas leaves 3D, when the visual
leaves the "plane" render mode, and when the plane's axes stop
being the displayed ones.
Emits PlaneGizmoChangedEvent with kind="render".
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual the plane belongs to. It must be in the
|
required |
canvas_id
|
UUID
|
A 3D canvas of the visual's scene. |
required |
plane_id
|
UUID
|
The |
required |
source_id
|
UUID or None
|
Stamped on the emitted |
None
|
screen_size
|
float
|
The gizmo's size on screen, in logical pixels. |
100.0
|
Returns:
| Type | Description |
|---|---|
RenderPlaneGizmoController
|
The session. |
Raises:
| Type | Description |
|---|---|
KeyError
|
If the canvas or the visual is not registered, or the visual has no render plane with that id. |
ValueError
|
If the canvas is in 2D, the visual is not in the canvas's scene
or not in the |
clipping_plane_gizmo_blocked ¶
Why a plane cannot have a gizmo in a canvas now, or "" if it can.
What :meth:add_clipping_plane_gizmo would refuse, as a sentence a
control can show: the canvas is in 2D, or the plane has a component
on an axis the 3D view does not show.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual the plane belongs to. |
required |
canvas_id
|
UUID
|
The canvas the gizmo would be drawn in. |
required |
plane_id
|
UUID
|
The |
required |
Returns:
| Type | Description |
|---|---|
str
|
|
render_plane_gizmo_blocked ¶
Why a render plane cannot have a gizmo in a canvas now, or "".
What :meth:add_render_plane_gizmo would refuse, as a sentence a
control can show: the canvas is in 2D, the visual is not in the
"plane" render mode, or the plane's axes are not the displayed
ones.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual the plane belongs to. |
required |
canvas_id
|
UUID
|
The canvas the gizmo would be drawn in. |
required |
plane_id
|
UUID
|
The |
required |
Returns:
| Type | Description |
|---|---|
str
|
|
get_plane_gizmo ¶
get_plane_gizmo(canvas_id: UUID) -> PlaneGizmoController | None
The plane gizmo of a canvas, or None if it has none.
Its kind is "clipping" or "render".
remove_plane_gizmo ¶
Close a canvas's plane gizmo, of either kind; nothing if it has none.
Emits PlaneGizmoChangedEvent stamped with source_id.
update_aabb_field ¶
update_aabb_field(visual_id: UUID, field: str, value: Any, *, source_id: UUID | None = None) -> None
Set one field on a visual's AABB params model.
Tags the emitted bus event with source_id.
GUI widgets should pass source_id=self._id so their own
AABBChangedEvent subscription can ignore the echo.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
Target visual. |
required |
field
|
str
|
Attribute name on the AABB model, e.g. |
required |
value
|
Any
|
New value for the field. |
required |
source_id
|
UUID | None
|
UUID to stamp on the emitted |
None
|
update_displayed_axes ¶
update_displayed_axes(scene_id: UUID, displayed_axes: tuple[int, ...], *, source_id: UUID | None = None) -> None
Set displayed_axes on a scene's dims.
Tags the emitted bus event with source_id.
GUI widgets should pass source_id=self._id so their own
DimsChangedEvent subscription can ignore the echo.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
Target scene. |
required |
displayed_axes
|
tuple[int, ...]
|
Tuple of axis indices to display; length 2 for 2D, 3 for 3D. |
required |
source_id
|
UUID | None
|
UUID to stamp on the emitted |
None
|
set_displayed_axes ¶
set_displayed_axes(scene_id: UUID, displayed_axes: tuple[int, ...], *, source_id: UUID | None = None) -> None
Set displayed axes on a scene's dims (preferred public API).
Equivalent to :meth:update_displayed_axes. The controller's
psygnal bridge fires _rebuild_visuals_geometry and
_switch_canvas_cameras automatically when the model field changes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
Target scene. |
required |
displayed_axes
|
tuple[int, ...]
|
Tuple of axis indices to display; length 2 for 2D, 3 for 3D. |
required |
source_id
|
UUID | None
|
UUID stamped on the emitted |
None
|
update_render_config_field ¶
update_render_config_field(section: str, field: str, value: Any, *, source_id: UUID | None = None) -> None
Set one field of the render configuration and apply it.
The single seam every render-config write goes through: it updates
the model, pushes the change to the GPU by whichever route that
field needs, and emits a RenderConfigChangedEvent so subscribed
widgets follow along. Which fields recompile a shader and which are
plain uniforms is a property of the field, recorded once in
:data:_RENDER_CONFIG_ROUTES, so no caller has to know.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
section
|
str
|
|
required |
field
|
str
|
Dotted attribute path within the section, e.g. |
required |
value
|
Any
|
New value for the field. |
required |
source_id
|
UUID | None
|
UUID to stamp on the emitted |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If section or field is not a settable render-config field. |
reset_temporal_accumulation ¶
Discard the accumulated history on every canvas.
The next frame is shown raw and accumulation restarts from it. Cellier already does this on every camera and content change; this is for a caller who has changed something cellier cannot see.
apply_ambient_occlusion_config ¶
Push render_config.ambient_occlusion onto every canvas's occlusion pass.
Needed after mutating the config model in place. n_samples and
blur_radius are shader template vars, so changing them
recompiles; the rest are uniforms and do not.
apply_outline_config ¶
Push render_config.outline onto every canvas's outline pass.
Call this after mutating thicknesses or colours in place. Changing a thickness recompiles the outline shader; enables, colours and the palette do not.
begin_camera_interaction ¶
Open a camera interaction scope on a canvas.
While any scope is open, every camera move on the canvas is a tick
of a motion, programmatic ones included: nothing is resliced until
the motion ends. Opening a scope starts nothing by itself; the
first move does. Holding still for CameraConfig.settle_threshold_s
still ends a motion, and the next move starts a new one.
The canvas's own camera controller holds a scope while it drives the
camera. Scripts normally use :meth:camera_interaction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_id
|
UUID
|
The canvas whose camera is about to move. |
required |
source_id
|
UUID
|
Who holds the scope. One scope is counted per source. |
required |
Raises:
| Type | Description |
|---|---|
KeyError
|
If canvas_id is not registered. |
end_camera_interaction ¶
Close a camera interaction scope opened by source_id.
Closing the last open scope ends a motion at once ("release"):
the scene's camera-sensitive visuals reslice without waiting for the
stillness time. Closing a scope that is not open does nothing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_id
|
UUID
|
The canvas the scope was opened on. |
required |
source_id
|
UUID
|
The source that opened it. |
required |
camera_interaction ¶
Move a canvas's camera as one motion for the length of a with block.
Every programmatic move inside the block is a tick of a motion, so a fly-through reslices once, when the block exits, instead of at every pose::
with controller.camera_interaction(canvas_id):
for pose in path:
controller.set_camera_state(canvas_id, pose)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_id
|
UUID
|
The canvas whose camera moves. |
required |
camera_interaction_state ¶
Whether canvas_id's camera is in motion.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_id
|
UUID
|
The canvas to query. |
required |
Returns:
| Type | Description |
|---|---|
{'idle', 'active'}
|
|
set_camera_state ¶
Move a canvas's camera to state.
By default the move is a jump: the scene's camera-sensitive
visuals (multiscale image and labels) reslice at once, and a motion
in progress on the canvas ends. With interactive=True, or inside
:meth:camera_interaction, it is a tick of a motion: nothing is
resliced until the motion ends, on release or after
CameraConfig.settle_threshold_s of stillness. A state equal to
the camera's current one does nothing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_id
|
UUID
|
ID of a registered canvas. |
required |
state
|
CameraState
|
The state to apply; :meth: |
required |
interactive
|
bool
|
Whether the move is a tick of a motion. |
False
|
Raises:
| Type | Description |
|---|---|
KeyError
|
If canvas_id is not registered. |
ValueError
|
If state is for the other kind of camera. |
look_at_visual ¶
look_at_visual(visual_id: UUID, canvas_id: UUID, view_direction: tuple[float, float, float] = (-1, -1, -1), up: tuple[float, float, float] = (0, 0, 1), *, interactive: bool = False) -> None
Fit the camera to a visual's bounding box.
A jump, like :meth:fit_camera: camera-sensitive visuals
reslice at once for the new view.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
ID of the target visual. |
required |
canvas_id
|
UUID
|
ID of the canvas whose camera should be fitted. |
required |
view_direction
|
tuple[float, float, float]
|
Camera look direction vector (need not be normalized). |
(-1, -1, -1)
|
up
|
tuple[float, float, float]
|
Camera up vector. |
(0, 0, 1)
|
interactive
|
bool
|
Whether the move is a tick of a camera motion instead of a jump;
see :meth: |
False
|
set_camera_depth_range ¶
set_camera_depth_range(canvas_id: UUID, depth_range: tuple[float, float], *, interactive: bool = False) -> None
Set the near/far clip distances for a canvas camera.
A jump, like :meth:fit_camera.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_id
|
UUID
|
ID of the target canvas. |
required |
depth_range
|
tuple[float, float]
|
|
required |
interactive
|
bool
|
Whether the move is a tick of a camera motion instead of a jump;
see :meth: |
False
|
add_paint_controller ¶
add_paint_controller(visual_id: UUID, canvas_id: UUID, brush_value: int = 1, brush_radius_voxels: float = 2.0, history_depth: int = 100, autosave_interval_s: float | None = None)
Create and wire a paint controller for a labels visual.
Only labels can be painted. The controller is chosen by the visual's
type -- a LabelMemoryVisual gets a SyncPaintController and a
MultiscaleLabelVisual a MultiscalePaintController -- rather
than by its store, because a multiscale labels visual may be backed
by a generic MultiscaleZarrDataStore. Image visuals raise.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
Visual to paint on. |
required |
canvas_id
|
UUID
|
Canvas to bind to. Its camera controller is disabled for
the session. Pass |
required |
brush_value
|
int
|
Integer label ID written to every painted voxel. |
1
|
brush_radius_voxels
|
float
|
Brush radius in level-0 voxel units. |
2.0
|
history_depth
|
int
|
Maximum undoable strokes. |
100
|
autosave_interval_s
|
float | None
|
Seconds between automatic flushes for |
None
|
Returns:
| Type | Description |
|---|---|
AbstractPaintController
|
Fully wired; caller owns the object. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If the visual type has no registered paint controller. |
remove_scene ¶
remove_scene(scene_id: UUID) -> None
Remove a scene and all its visuals and canvases.
Teardown order mirrors remove_visual for each child visual, then
cleans up the scene-level maps and render layer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
ID of the scene to remove. |
required |
Raises:
| Type | Description |
|---|---|
KeyError
|
If |
remove_canvas ¶
remove_canvas(canvas_id: UUID) -> None
Remove a canvas from its scene, disconnecting all wiring.
Teardown order mirrors remove_scene for the canvas-level steps:
1. Drop the canvas's camera motion state.
2. Remove bus subscriptions owned by this canvas.
3. Update controller lookup maps.
4. Remove from the model layer.
5. Render-layer teardown (drops widget and GPU references).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_id
|
UUID
|
ID of the canvas to remove. |
required |
Raises:
| Type | Description |
|---|---|
KeyError
|
If |
remove_visual ¶
remove_visual(visual_id: UUID) -> None
Remove a visual from its scene, disconnecting all wiring.
Teardown order:
1. Psygnal bridge handlers disconnected first — prevents the
bridge closures from firing during any subsequent model access.
2. Bus subscriptions removed — prevents dangling GFX-layer handlers
from receiving events after the node is gone from the scene graph.
3. Render-layer removal — drops scene-graph node and GPU references.
4. VisualRemovedEvent emitted for external observers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
ID of the visual to remove. |
required |
Raises:
| Type | Description |
|---|---|
KeyError
|
If |
remove_data_store ¶
remove_data_store(data_store_id: UUID) -> None
Remove a data store from the model.
Raises ValueError if any live visual still references the store.
Call remove_visual for each referencing visual first.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data_store_id
|
UUID
|
ID of the data store to remove. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If one or more visuals still reference the store. The error message names each visual so the caller can identify them. |
KeyError
|
If |
on_dims_changed ¶
on_dims_changed(scene_id: UUID, callback: Callable[[DimsChangedEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired whenever the dims for scene_id change.
The callback receives the full DimsChangedEvent, which includes
source_id for echo-filtering and dims_state for the new state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
The scene to watch. |
required |
callback
|
Callable[[DimsChangedEvent], None]
|
Called with the |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered. Pass the
caller's own UUID so |
required |
weak
|
bool
|
If True, hold only a weak reference to callback. Use for transient widgets that may be destroyed outside the controller's teardown path. Cannot be used with lambdas. |
False
|
Returns:
| Type | Description |
|---|---|
SubscriptionHandle
|
Pass to |
on_dims_interaction ¶
on_dims_interaction(scene_id: UUID, callback: Callable[[DimsInteractionEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired when a dims scrub starts or ends.
The callback receives a DimsInteractionEvent. The start is
emitted before the scrub's first tick changes the dims model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
The scene to watch. |
required |
callback
|
Callable[[DimsInteractionEvent], None]
|
Called with the |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered. Pass the
caller's own UUID so |
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
Returns:
| Type | Description |
|---|---|
SubscriptionHandle
|
|
on_camera_changed ¶
on_camera_changed(scene_id: UUID, callback: Callable[[CameraChangedEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired whenever the camera for scene_id changes.
The callback receives a CameraChangedEvent carrying the latest
CameraState, including extent (width, height) for
OrthographicCamera scenes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
The scene to watch. |
required |
callback
|
Callable[[CameraChangedEvent], None]
|
Called with the |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered. Pass the
caller's own UUID so |
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
Returns:
| Type | Description |
|---|---|
SubscriptionHandle
|
|
on_camera_interaction ¶
on_camera_interaction(scene_id: UUID, callback: Callable[[CameraInteractionEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired when a camera motion starts or ends.
The callback receives a CameraInteractionEvent for every canvas
of scene_id; its canvas_id says which.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
The scene to watch. |
required |
callback
|
Callable[[CameraInteractionEvent], None]
|
Called with the |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered. Pass the
caller's own UUID so |
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
Returns:
| Type | Description |
|---|---|
SubscriptionHandle
|
|
unsubscribe_mouse ¶
Remove a subscription created by an on_mouse_* method.
Mouse subscriptions do not gate pick details; this is
EventBus.unsubscribe, kept so a handle from on_pick passed
here by mistake still updates the pick counters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
handle
|
SubscriptionHandle
|
A handle returned by one of the |
required |
on_pick ¶
on_pick(canvas_id: UUID, event_type: type, callback: Callable[[Any], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired when a visual of one kind is picked.
Mouse events say that something was hit; pick events say what
(unified image design 3.7). A pick event follows the mouse event for
the same pointer event, carries the same gesture_id, action,
button, buttons and modifiers, and is emitted only for hits. Image
and labels events carry the values under the pointer; for multiscale
visuals those are read asynchronously, so match events by
gesture_id and action rather than by arrival order.
Pick details are extracted while the canvas has any pick subscriber, and image and labels values are read only while that event type has one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_id
|
UUID
|
The canvas to watch. |
required |
event_type
|
type
|
One of :data: |
required |
callback
|
Callable
|
Called with each pick event. |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered for bulk removal
via |
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
Returns:
| Type | Description |
|---|---|
SubscriptionHandle
|
Pass it to :meth: |
Raises:
| Type | Description |
|---|---|
TypeError
|
If event_type is not a pick event type. |
unsubscribe_pick ¶
Remove a subscription created by :meth:on_pick.
Keeps the per-canvas and per-type subscriber counts accurate: the last subscriber for a type stops its value reads, and the last for a canvas disables pick-detail extraction there.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
handle
|
SubscriptionHandle
|
A handle returned by :meth: |
required |
on_mouse_press_2d ¶
on_mouse_press_2d(canvas_id: UUID, callback: Callable[[CanvasMousePress2DEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired on every pointer-down event on a 2D canvas.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_id
|
UUID
|
The canvas to watch. |
required |
callback
|
Callable[[CanvasMousePress2DEvent], None]
|
Called with the CanvasMousePress2DEvent on each press. |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered for bulk removal via unsubscribe_all(owner_id). |
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
on_mouse_move_2d ¶
on_mouse_move_2d(canvas_id: UUID, callback: Callable[[CanvasMouseMove2DEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired on every pointer-move event on a 2D canvas.
on_mouse_release_2d ¶
on_mouse_release_2d(canvas_id: UUID, callback: Callable[[CanvasMouseRelease2DEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired on every pointer-up event on a 2D canvas.
on_mouse_press_3d ¶
on_mouse_press_3d(canvas_id: UUID, callback: Callable[[CanvasMousePress3DEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired on every pointer-down event on a 3D canvas.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_id
|
UUID
|
The canvas to watch. |
required |
callback
|
Callable[[CanvasMousePress3DEvent], None]
|
Called with the CanvasMousePress3DEvent on each press. |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered for bulk removal via unsubscribe_all(owner_id). |
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
on_mouse_move_3d ¶
on_mouse_move_3d(canvas_id: UUID, callback: Callable[[CanvasMouseMove3DEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired on every pointer-move event on a 3D canvas.
on_mouse_release_3d ¶
on_mouse_release_3d(canvas_id: UUID, callback: Callable[[CanvasMouseRelease3DEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired on every pointer-up event on a 3D canvas.
set_camera_controller_enabled ¶
Enable or disable the camera controller for one canvas.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_id
|
UUID
|
The canvas whose controller state should change. |
required |
enabled
|
bool
|
False disables the controller (paint session active). True restores normal camera interaction (session ended). |
required |
on_appearance_changed ¶
on_appearance_changed(visual_id: UUID, callback: Callable[[AppearanceChangedEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired whenever the appearance of visual_id changes.
The callback receives the full AppearanceChangedEvent, which
includes source_id for echo-filtering, field_name, and
new_value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual to watch. |
required |
callback
|
Callable[[AppearanceChangedEvent], None]
|
Called with the |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered. Pass the
caller's own UUID so |
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
Returns:
| Type | Description |
|---|---|
SubscriptionHandle
|
|
on_visual_changed ¶
on_visual_changed(visual_id: UUID, callback: Callable[[AppearanceChangedEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Deprecated. Use on_appearance_changed instead.
on_visibility_changed ¶
on_visibility_changed(visual_id: UUID, callback: Callable[[VisualVisibilityChangedEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired whenever the visibility of visual_id changes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual to watch. |
required |
callback
|
Callable[[VisualVisibilityChangedEvent], None]
|
Called with the |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered. |
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
Returns:
| Type | Description |
|---|---|
SubscriptionHandle
|
|
set_visual_visible ¶
set_visual_outline ¶
Outline a visual with a screen-space contour.
Requires render_config.outline.enabled (or
controller.render_manager.outline_enabled = True); the outline
pass is off by default.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
Target visual. |
required |
slot
|
int
|
|
1
|
placement
|
str | None
|
|
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If slot or placement is out of range. |
Notes
A nonzero slot sets pick_write = True on the visual, since
outlines are derived from the pick buffer. This also enables
mouse picking for that visual, which is a side effect worth
knowing about if you had deliberately turned picking off.
On a labels visual what slot means depends on
outline_mode, and the default mode is "per_label": there
the visual is outlined per label rather than as one silhouette, and
the colour comes from the label, not from slot -- a nonzero
slot only makes the visual eligible for the boundaries layer, and
:meth:set_label_selection is what puts a palette colour on
individual labels. In "whole_object" and "all_boundaries"
mode slot is the colour, exactly as on every other visual. Per
label keys need the canvas to have been built with outlines
enabled; without that the visual falls back to a silhouette.
set_visual_ambient_occlusion ¶
Choose whether one visual receives ambient occlusion.
Requires render_config.ambient_occlusion.enabled (or
controller.ambient_occlusion_enabled = True); the occlusion pass is off by
default, and off in 2D always.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
Target visual. |
required |
enabled
|
bool | None
|
|
None
|
Notes
A MIP-family mode writes the depth of the brightest sample along
the ray rather than of a surface, and that depth jumps between
neighbouring pixels, so occlusion computed from it shimmers. That
is what the automatic rule exists for; an explicit True is
available for anyone who wants it anyway.
Excluding a visual sets pick_write = True on it, because the
occlusion pass identifies pixels through the pick buffer -- the
same side effect :meth:set_visual_outline has, and worth knowing
if you had deliberately turned picking off. The automatic rule
needs picking too: a MIP visual with pick_write = False
cannot be identified per pixel, so it receives occlusion despite
the default.
This controls whether the visual receives occlusion, not whether it casts it: the occlusion loop reads raw depth, so an excluded visual's depth still darkens its neighbours.
get_visual_ambient_occlusion ¶
get_visual_outline ¶
set_label_selection ¶
Choose which label values the selection layer outlines.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
A labels visual, already given an outline with
:meth: |
required |
selection
|
dict[int, int]
|
|
required |
Notes
Selection is exact: the label key is range-partitioned, with
1..15 reserved for selected labels and everything above for
unselected ones, so an unselected label can never be mistaken for a
selected one.
Requires a canvas built with outlines enabled -- the per-label key lives in a render target that is only allocated then. Without it the visual still gets a whole-object silhouette.
on_scene_added ¶
on_scene_added(scene_id: UUID, callback: Callable[[SceneAddedEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired when scene_id is added.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
The scene to watch. |
required |
callback
|
Callable[[SceneAddedEvent], None]
|
Called with the |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered. |
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
Returns:
| Type | Description |
|---|---|
SubscriptionHandle
|
|
on_scene_removed ¶
on_scene_removed(scene_id: UUID, callback: Callable[[SceneRemovedEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired when scene_id is removed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
The scene to watch. |
required |
callback
|
Callable[[SceneRemovedEvent], None]
|
Called with the |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered. |
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
Returns:
| Type | Description |
|---|---|
SubscriptionHandle
|
|
on_visual_added ¶
on_visual_added(visual_id: UUID, callback: Callable[[VisualAddedEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired when visual_id is added.
The bus routes this event by scene, so the subscription filters on
the event's visual_id field instead.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual to watch. |
required |
callback
|
Callable[[VisualAddedEvent], None]
|
Called with the |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered. |
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
Returns:
| Type | Description |
|---|---|
SubscriptionHandle
|
|
on_visual_removed ¶
on_visual_removed(visual_id: UUID, callback: Callable[[VisualRemovedEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired when visual_id is removed.
The bus routes this event by scene, so the subscription filters on
the event's visual_id field instead.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual to watch. |
required |
callback
|
Callable[[VisualRemovedEvent], None]
|
Called with the |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered. |
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
Returns:
| Type | Description |
|---|---|
SubscriptionHandle
|
|
cancel_pending_slices ¶
cancel_pending_slices(scene_id: UUID) -> None
Cancel all in-flight slice requests for scene_id.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
ID of the scene whose pending slices to cancel. |
required |
close ¶
Cancel in-flight slices and close every canvas this viewer owns.
Releases the render surfaces and GPU resources held by the controller.
Closing is explicit because the canvases are owned by the GUI backend,
not by Python refcounting, so dropping the controller alone leaks them
(see :meth:CanvasView.close).
Cancels the interaction timers, the queued camera reslices and every
in-flight slice task -- including the ones the slice coordinator no
longer tracks -- so a closed controller holds no live asyncio.Task.
Also disconnects the psygnal bridges from the model and clears the
event buses. Those hold the
controller's own handlers, and psygnal keeps them strongly, so a
closed-but-connected controller stays reachable from the models it was
watching -- and keeps reacting to them. remove_visual and
remove_scene already do this for what they remove; this does it for
whatever is left.
Safe to call more than once; the controller must not be used afterwards.
on_section_changed ¶
on_section_changed(visual_id: UUID, callback: Callable[[MeshSectionChangedEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired when a mesh's section config changes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The mesh visual to watch. |
required |
callback
|
Callable[[MeshSectionChangedEvent], None]
|
Called with the |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered. |
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
Returns:
| Type | Description |
|---|---|
SubscriptionHandle
|
|
on_plane_gizmo_changed ¶
on_plane_gizmo_changed(canvas_id: UUID, callback: Callable[[PlaneGizmoChangedEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired when a canvas's plane gizmo changes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_id
|
UUID
|
The canvas to watch. |
required |
callback
|
Callable[[PlaneGizmoChangedEvent], None]
|
Called with the |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered. |
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
Returns:
| Type | Description |
|---|---|
SubscriptionHandle
|
|
on_plane_interaction ¶
on_plane_interaction(visual_id: UUID, callback: Callable[[PlaneInteractionEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired when a clipping plane drag starts or ends.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual to watch. |
required |
callback
|
Callable[[PlaneInteractionEvent], None]
|
Called with the |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered. |
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
Returns:
| Type | Description |
|---|---|
SubscriptionHandle
|
|
on_clipping_planes_changed ¶
on_clipping_planes_changed(visual_id: UUID, callback: Callable[[ClippingPlanesChangedEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired when a visual's clipping planes change.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual to watch. |
required |
callback
|
Callable[[ClippingPlanesChangedEvent], None]
|
Called with the |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered. |
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
Returns:
| Type | Description |
|---|---|
SubscriptionHandle
|
|
on_render_planes_changed ¶
on_render_planes_changed(visual_id: UUID, callback: Callable[[RenderPlanesChangedEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired when a visual's render planes change.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual to watch. |
required |
callback
|
Callable[[RenderPlanesChangedEvent], None]
|
Called with the |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered. |
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
Returns:
| Type | Description |
|---|---|
SubscriptionHandle
|
|
on_lod_config_changed ¶
on_lod_config_changed(visual_id: UUID, callback: Callable[[LodConfigChangedEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired when a multiscale mesh's lod config changes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The multiscale mesh visual to watch. |
required |
callback
|
Callable[[LodConfigChangedEvent], None]
|
Called with the |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered. |
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
Returns:
| Type | Description |
|---|---|
SubscriptionHandle
|
|
on_aabb_changed ¶
on_aabb_changed(visual_id: UUID, callback: Callable[[AABBChangedEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired whenever the AABB params of visual_id change.
The callback receives the full AABBChangedEvent, which includes
source_id for echo-filtering, field_name, and new_value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual to watch. |
required |
callback
|
Callable[[AABBChangedEvent], None]
|
Called with the |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered. Pass the
caller's own UUID so |
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
Returns:
| Type | Description |
|---|---|
SubscriptionHandle
|
|
on_reslice_started ¶
on_reslice_started(scene_id: UUID, callback: Callable[[ResliceStartedEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired when a reslice cycle begins for scene_id.
Useful for showing a loading indicator. Fired once per reslice submission, before any async data fetching starts.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
The scene to watch. |
required |
callback
|
Callable[[ResliceStartedEvent], None]
|
Called with the |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered. Pass the
caller's own UUID so |
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
Returns:
| Type | Description |
|---|---|
SubscriptionHandle
|
|
on_reslice_completed ¶
on_reslice_completed(visual_id: UUID, callback: Callable[[ResliceCompletedEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired when a reslice cycle completes for visual_id.
Useful for hiding a loading indicator. Fired once per visual per reslice cycle, after all bricks/tiles in the batch are committed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual to watch. |
required |
callback
|
Callable[[ResliceCompletedEvent], None]
|
Called with the |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered. Pass the
caller's own UUID so |
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
Returns:
| Type | Description |
|---|---|
SubscriptionHandle
|
|
on_reslice_progress ¶
on_reslice_progress(visual_id: UUID, callback: Callable[[ResliceProgressEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired as a multiscale visual's data loads.
Fired at most once per event-loop iteration: after each plan, each
frame that commits the visual's data, a read given up, or an
invalidation. event.progress is a
:class:~cellier.events.LoadingProgress. Only multiscale visuals
load progressively; others never fire it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual to watch. |
required |
callback
|
Callable[[ResliceProgressEvent], None]
|
Called with the |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered, for
|
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
Returns:
| Type | Description |
|---|---|
SubscriptionHandle
|
|
on_backstop_complete ¶
on_backstop_complete(visual_id: UUID, callback: Callable[[BackstopCompleteEvent], None], *, owner_id: UUID, weak: bool = False) -> SubscriptionHandle
Register a callback fired when a multiscale visual's backstop is loaded.
From then on the view shows the current slice everywhere, possibly blurry, while finer data keeps loading. Fired once per plan.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual to watch. |
required |
callback
|
Callable[[BackstopCompleteEvent], None]
|
Called with the |
required |
owner_id
|
UUID
|
UUID under which this subscription is registered, for
|
required |
weak
|
bool
|
If True, hold only a weak reference to callback. |
False
|
Returns:
| Type | Description |
|---|---|
SubscriptionHandle
|
|
loading_progress ¶
loading_progress(visual_id: UUID) -> LoadingProgress | None
A multiscale visual's current loading progress.
The same counts the latest ResliceProgressEvent carried, read
now. None for a visual that is not multiscale, or that has not
been planned yet (or draws nothing).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visual_id
|
UUID
|
The visual. |
required |
Returns:
| Type | Description |
|---|---|
LoadingProgress or None
|
|
on_scene_ready ¶
on_scene_ready(scene_id: UUID, callback: Callable[[], None], *, owner_id: UUID | None = None) -> None
Reslice scene_id and fire callback once all its data is on the GPU.
This triggers a reslice of every visual in the scene and invokes callback exactly once, after all visuals loaded by that reslice have committed to the GPU across every attached canvas. Visuals with no data in the current view (frustum-culled, empty slab, or hidden) do not delay the callback.
Unlike :meth:on_reslice_completed (which fires per-visual on every
cycle), this is a scene-level, one-shot readiness signal — the right
hook for fitting the camera or hiding a startup spinner once a mixed
scene of multiscale images, in-memory images, and geometry has fully
loaded.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scene_id
|
UUID
|
ID of the scene to reslice and watch. |
required |
callback
|
Callable[[], None]
|
Zero-argument callback fired once the scene's data is resident. |
required |
owner_id
|
UUID or None
|
Owner under which the temporary subscriptions are registered. Defaults to the controller's own id. |
None
|
on_canvas_connected ¶
on_canvas_connected(canvas_id: UUID, callback: Callable[[], None], *, owner_id: UUID | None = None) -> None
Fire callback once canvas_id's front end is live and able to draw.
The weaker, earlier sibling of :meth:on_canvas_first_frame: it says
the canvas can render, not that it has. On Qt the two nearly
coincide; on the anywidget backend the canvas exists in Python long
before the browser mounts it, and a frame may never arrive at all --
so work that only needs a usable canvas should wait on this instead.
Fires immediately if the canvas has already connected.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_id
|
UUID
|
ID of the canvas to watch. |
required |
callback
|
Callable[[], None]
|
Zero-argument callback, fired once. |
required |
owner_id
|
UUID or None
|
Owner for the temporary subscription. Defaults to the controller's own id. |
None
|
on_canvas_first_frame ¶
on_canvas_first_frame(canvas_id: UUID, callback: Callable[[], None], *, owner_id: UUID | None = None) -> None
Fire callback once canvas_id has rendered its first frame.
The first rendered frame guarantees the canvas has reached its final
logical size and its camera matrix has been applied — the precondition
for fitting the camera and computing view-dependent (multiscale) slice
requests at the correct level of detail. This is a timer-free
replacement for deferring startup work with QTimer.singleShot(0).
A draw is requested immediately so the frame is guaranteed to arrive whether or not the event loop is already running.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
canvas_id
|
UUID
|
ID of the canvas to watch. |
required |
callback
|
Callable[[], None]
|
Zero-argument callback fired once, on the first frame. |
required |
owner_id
|
UUID or None
|
Owner under which the temporary subscription is registered. Defaults to the controller's own id. |
None
|
unsubscribe_owner ¶
unsubscribe_owner(owner_id: UUID) -> None
Remove all event subscriptions registered under owner_id.
GUI widgets should call this from their Qt closeEvent or
destroyed signal handler to deterministically clean up their
bus subscriptions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
owner_id
|
UUID
|
The UUID used as |
required |
connect_widget ¶
connect_widget(widget: WidgetView, *, subscription_specs: list[SubscriptionSpec] | None = None) -> None
Wire a widget's psygnal signals to the bus and register subscriptions.
Widgets declare their intent through two psygnal signals and an optional
list of SubscriptionSpec objects, so they never import or hold a
reference to CellierController.
The caller is responsible for constructing the widget and passing the
specs — typically obtained from widget.subscription_specs().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
widget
|
WidgetView
|
Any object exposing:
|
required |
subscription_specs
|
list[SubscriptionSpec] | None
|
Optional list of |
None
|