neu_draw.backends.legend¶
The legend: a clickable strip drawn in the canvas beside the scene, so it is part of every snapshot and saved figure.
One row per label (a plate, a glyph for the kind of drawable, and the text); a row may
stand for many drawables. Left-click a row to hide or show it, right-click to highlight
it. Hidden rows are dimmed, not removed, and a partly hidden group has a third look. The
highlight is a display override: drawable.color is never changed.
How it works:
A second render pass into the strip’s rect (
render(..., rect=, flush=False)) after the main scene. Legend materials usedepth_test=False.Picking: the second pass writes pick ids inside the strip, so a click there hits the legend. Only the plate writes them, so the whole row is the click target.
The camera controller is bound to a viewport covering the main rect, so a click on the legend does not also rotate the camera.
Both rects are computed from the renderer’s current size (
_Part), so resizing needs no handler.
Sizes are logical pixels: one world unit is one pixel. Label widths are measured from
pygfx.Text’s laid-out bounding box, so the strip fits the longest label in one pass.
When entries do not fit, the legend adds columns up to a width budget, then shrinks
rather than clipping.
Attributes¶
Classes¶
One legend row and every drawable it stands for: those sharing a |
|
The legend for one |
Functions¶
|
|
Module Contents¶
- class neu_draw.backends.legend.LegendEntry(label: str, indices: Sequence[int], drawables: Sequence[Any], world_objects: Sequence[pygfx.WorldObject | None], spec: neu_draw.scene.Legend, is_group: bool = False)¶
One legend row and every drawable it stands for: those sharing a
label_of(), or a declared group.Holds the drawables (whose
visibleandcolorare authoritative) and theWorldObjectbuilt for each, paired by position, so a toggle updates both.- layout(column: int, row: int, column_width: float) None¶
Place this entry at
(column, row)of a grid whose columns are that wide.Rows run downward from y = 0 (
yis minus the pixels from the top); columns run rightward fromx = PAD.
- refresh(lit: set | None = None) None¶
Push this entry’s state onto the objects: colour, highlight, visibility.
litis the set of scene indices to highlight, computed by the overlay over every row, since a drawable can be on its own row and on group rows;Noneuses this row’s own flag. The highlight only changes the drawn material, neverdrawable.color, so recolouring a highlighted row takes effect when the highlight comes off. Everything is recomputed on each call.
- toggle() bool¶
Hide the whole group, or show it. Returns whether it is now visible.
If anything is showing, hide all; if nothing is, show all (rather than inverting each member).
- toggle_highlight() bool¶
- drawables¶
- glyph¶
- group¶
- highlighted = False¶
- indices¶
- is_group = False¶
- property kinds: set[str]¶
- label¶
- property label_width: float¶
The label’s laid-out width in px, available before any draw.
- property names: list[str]¶
The member drawables’ names.
- plate¶
- property row_text: str¶
The label, with a member count when the row stands for more than one drawable.
- spec¶
- text = ''¶
- property visibility: str¶
"all","some"or"none"of the members are showing.A group can be partly shown, for instance after hiding one member by name.
- world_objects¶
- class neu_draw.backends.legend.LegendOverlay(scene: neu_draw.scene.Scene, group: pygfx.Group, renderer: Any)¶
The legend for one
Scene, bound to one renderer.One row per distinct
label_of(), in first-appearance order; a drawable with neither label nor name gets no row. Drawables are paired with their world objects by position (build()makes one per drawable, in order), not by name, since a drawable may have a label and no name.- build_entries(strict: bool = True) None¶
(Re)group the scene’s drawables into rows, discarding any rows there were.
Relabelling can merge and split rows, so every label change rebuilds them here. Highlights carry over by member: a rebuilt row is lit if every member was, so a split keeps both halves lit and a lit row merged into an unlit one goes dark.
Group rows (
Legend.groups) come first, carry their highlight over by text, and resolve members by name. Withstrict, an unknown member or a group text that collides with a label row raises;sync()passesFalse, since it runs inside a draw, and warns and skips instead.
- clear_highlights() LegendOverlay¶
- draw(renderer: Any = None, rect: Sequence[float] | None = None, flush: bool = True) None¶
Render the strip.
rendererdefaults to the one this was built against.Pass a renderer for an offscreen snapshot. Re-reads the scene first (
sync()) and re-lays out only when the column count changes.
- entry(label: str) LegendEntry¶
- highlight(*labels: str, exclusive: bool = False) LegendOverlay¶
Draw these rows in the highlight colour, leaving their real colours alone.
exclusive=Trueclears other highlights first; by default highlights accumulate, as right-clicking several rows does.
- layout() None¶
Re-measure and re-place at the current column count. Idempotent.
- measure() None¶
Re-read the label widths, which the grid is derived from. Independent of the canvas size, unlike
relayout().
- plan(size: Sequence[float]) tuple[int, float]¶
(columns, strip_width)for a canvas ofsize.As many columns as the entries need to fit the height, up to what the width budget allows; any remainder is shrunk to fit. (A single tall column shrunk to fit would leave tiny text beside empty margin.) An explicit
Legend.widthfixes the strip, and the column count follows.
- recolor(label: str, color: Any) LegendOverlay¶
Recolour every drawable on a row. On a highlighted row the new colour appears when the highlight comes off.
- rects_for(size: Sequence[float]) tuple[tuple, tuple]¶
- refresh() LegendOverlay¶
Rebuild the rows from the scene, including their text, for changes made to the scene directly (such as
scene.rename).
- relabel(labels: str | Mapping[str, str], new: str | None = None) LegendOverlay¶
Change rows’ text, keyed on their current label. Mapping or
(old, new).Giving two rows the same new label merges them:
view.legend.relabel({"1401 mesh": "Tm2", "1402 mesh": "Tm2"})
Sets the members’
labeland leaves their names alone, soscene.get("1401 mesh")still works.
- relayout(columns: int) None¶
Place every entry into a grid
columnswide, filling each column top-down.
- set_visible(label: str, visible: bool) LegendOverlay¶
Show or hide a whole row, by label.
- sync() bool¶
Catch up with the scene if it changed since the last draw; cheap when it did not.
Called from
draw(), so direct field edits such asscene.get("a").label = "Tm2"show up, in snapshots too. A changed structure rebuilds the rows; a changed appearance only reassigns materials. Returns whether anything was done.
- toggle(label: str) bool¶
- toggle_highlight(label: str) bool¶
What right-clicking a row does.
- unhighlight(*labels: str) LegendOverlay¶
Put these rows back to their own colours. No labels means all of them.
- backdrop¶
- camera¶
- columns = 1¶
- entries: list[LegendEntry] = []¶
- group¶
- property highlighted: list[str]¶
The row labels currently drawn in the highlight colour.
- property labels: list[str]¶
This legend’s rows, in order. The methods here take these labels, not drawable names.
- main¶
- renderer¶
- scene¶
- scene_data¶
- spec¶
- viewport¶
- property width: float¶
The strip’s width for the renderer it is attached to, in px.
- neu_draw.backends.legend.split_rects(size: Sequence[float], location: str, width: float) tuple[tuple, tuple]¶
(main_rect, strip_rect)for a canvas ofsize, both(x, y, w, h).Docked beside the scene rather than over it, so it never hides the data.
- neu_draw.backends.legend.CAMERA_Z = 100.0¶
- neu_draw.backends.legend.DEFAULT_PANEL: neu_draw.colors.RGBA = (0.07, 0.07, 0.09, 1.0)¶
- neu_draw.backends.legend.DIM = 0.35¶
- neu_draw.backends.legend.GAP = 7.0¶
- neu_draw.backends.legend.GLYPH_WIDTH = 1.5¶
- neu_draw.backends.legend.HIGHLIGHT_ROW_ALPHA = 0.38¶
- neu_draw.backends.legend.MAX_WIDTH_FRACTION = 0.45¶
- neu_draw.backends.legend.MIN_WIDTH = 80.0¶
- neu_draw.backends.legend.PAD = 9.0¶
- neu_draw.backends.legend.ROW_HEIGHT = 1.95¶