plesty.lib.ui.plot_panel

The dockable panel that shows one Plot.

This is the whole of what the shallow design costs on the drawing side: a panel that, on every tick, polls the shared data once for all panels, asks its plot what to draw, and hands the answer to the renderer that already exists.

Two things are worth knowing about how it does that.

The data is polled once, not once per panel. Every panel of a viewer holds the same RunData, and whichever ticks first ingests what has committed; the rest read what is already there. That is what replaces the old rule that each view needed a source of its own.

Items are reused by position. A drawing is a list, not a keyed mapping, so this keeps the shape it last built — the kinds, labels, colours and scales in order — and rebuilds only when that changes. A plot whose trace count grows as lines are found pays a rebuild on the tick it grows, and nothing otherwise.

Attributes

_DRAWING

Classes

_Traces

What a renderer asks about a drawing: its specs, and one by key.

PlotPanel

Sub-window showing one plot of a run.

Functions

_drawer(→ concurrent.futures.ThreadPoolExecutor)

The drawing thread, started on first use.

_key(→ str)

The key a drawable is addressed by: where it sits in the drawing.

_spec(→ plesty.lib.monitor.base_monitor.TraceSpec)

Return the renderer's declaration of item.

_payload(→ plesty.lib.monitor.base_monitor.TraceData)

Return the renderer's payload for item — its values, without its style.

_text_of(→ Optional[str])

Return the text a drawable shows, with a scalar's unit appended.

Module Contents

plesty.lib.ui.plot_panel._DRAWING: concurrent.futures.ThreadPoolExecutor | None = None
plesty.lib.ui.plot_panel._drawer() → concurrent.futures.ThreadPoolExecutor

The drawing thread, started on first use.

Built lazily so importing this module still costs nothing and starts nothing — the same reason Qt is imported where it is used rather than at the top of the file.

Return type:

concurrent.futures.ThreadPoolExecutor

class plesty.lib.ui.plot_panel._Traces(drawing: Sequence[plesty.lib.monitor.plots.Drawable])

What a renderer asks about a drawing: its specs, and one by key.

The renderer was written against a monitor and reads only these two things from it, so this is the whole of what it needs — and the specs it reads are derived from the drawables rather than declared beside them.

Derive the specs of drawing, keyed by position.

Parameters:

drawing (Sequence[plesty.lib.monitor.plots.Drawable])

_specs
_by_key
property trace_specs: list[plesty.lib.monitor.base_monitor.TraceSpec]

Every trace, in drawing order.

Return type:

list[plesty.lib.monitor.base_monitor.TraceSpec]

trace_spec(key: str) → plesty.lib.monitor.base_monitor.TraceSpec

The spec of one trace.

Parameters:

key (str) – Its positional key.

Raises:

KeyError – If the drawing changed shape without a rebuild.

Return type:

plesty.lib.monitor.base_monitor.TraceSpec

plesty.lib.ui.plot_panel._key(index: int) → str

The key a drawable is addressed by: where it sits in the drawing.

Parameters:

index (int)

Return type:

str

plesty.lib.ui.plot_panel._spec(index: int, item: plesty.lib.monitor.plots.Drawable) → plesty.lib.monitor.base_monitor.TraceSpec

Return the renderer’s declaration of item.

Parameters:
Returns:

The spec, carrying the style the drawable brought with it.

Return type:

plesty.lib.monitor.base_monitor.TraceSpec

plesty.lib.ui.plot_panel._payload(item: plesty.lib.monitor.plots.Drawable) → plesty.lib.monitor.base_monitor.TraceData

Return the renderer’s payload for item — its values, without its style.

Parameters:

item (plesty.lib.monitor.plots.Drawable)

Return type:

plesty.lib.monitor.base_monitor.TraceData

plesty.lib.ui.plot_panel._text_of(item: plesty.lib.monitor.plots.Drawable) → str | None

Return the text a drawable shows, with a scalar’s unit appended.

Parameters:

item (plesty.lib.monitor.plots.Drawable)

Return type:

Optional[str]

class plesty.lib.ui.plot_panel.PlotPanel(plot: plesty.lib.monitor.plots.Plot, data: Any, *, theme: plesty.lib.ui.theme.Theme | None = None, **kwargs: Any)

Bases: plesty.lib.ui.panel.Panel

Sub-window showing one plot of a run.

Toolkit-free until it is built, like every panel: constructing and describing it needs no GUI, which is what lets a headless test cover a viewer’s composition.

Show plot over data.

Parameters:
kind = 'plot'

Panel category, used for layout keys and styling hooks.

plot
data
theme = None
renderer: Any = None
_traces: _Traces | None = None
_shape: tuple[Any, Ellipsis] = ()
_own_widget: Any = None
_failure = ''
_drawing: concurrent.futures.Future[list[plesty.lib.monitor.plots.Drawable]] | None = None
build(parent: Any = None) → Any

Create the widget this panel shows.

A plot that overrides build() supplies its own widget and is never drawn as a plot — the escape hatch for a view that is a table or an image browser rather than a curve.

Parameters:

parent (Any) – The parent widget provided by the shell.

Returns:

The widget.

Return type:

Any

tick() → None

Show what the last draw produced, and set the next one going.

The work a draw does is not this thread’s to do. Reading what has committed and asking the plot what to draw are a file read and, for a view that fits its lines, a least-squares solve per spectrum — and this runs on the thread that answers clicks and repaints. Done here it stopped a console following a live run for seconds at a time, which is a window that looks hung while the measurement it is showing is perfectly fine.

So a tick renders whatever the drawing thread has finished and then asks it for the next, and the window is never inside a draw. A panel has at most one in flight: ticks that arrive while one is running start nothing, which is also what keeps a slow plot from queueing up work it will never catch up with. The cost is that a drawing appears on the tick after the one that asked for it — a poll interval late, on a view that is watching a measurement unfold.

Return type:

None

_begin_drawing() → None

Ask the drawing thread for the next drawing, if it is free of this panel.

Return type:

None

_compute_drawing() → list[plesty.lib.monitor.plots.Drawable]

Poll the data and ask the plot what to draw. Runs off the GUI thread.

The poll is shared: whichever panel gets here first brings the store up to date and the rest find it already so, which is why one run is read once however many plots watch it.

Return type:

list[plesty.lib.monitor.plots.Drawable]

_show_finished_drawing() → None

Render the drawing the thread has finished, if it has finished one.

Return type:

None

status() → str

Return what the title bar shows beside the plot’s name.

Returns:

How far the run has got, which is the same question for every plot of it, so no plot has to answer it — or why this view stopped drawing, which is the one thing only this panel knows.

Return type:

str

close() → None

Drop the renderer; the store is shared and is not closed here.

Return type:

None

describe() → dict[str, Any]

Return the panel’s placement plus what it draws.

Returns:

The panel description, with the plot’s title and class.

Return type:

dict[str, Any]