plesty.lib.monitor
Monitor framework: schema-declared live views over streams of measured data.
The contract (Monitor) and the streams that feed it
(plesty.lib.monitor.sources) are toolkit-free — importing this package
pulls in no GUI. Concrete views live in their own modules (for spectroscopy:
plesty-common-monitors); the dockable window that shows them is
plesty.lib.ui.
Submodules
Attributes
Exceptions
Raised when a submitted frame violates the declared |
|
Raised when a monitor's channel or trace declaration is invalid. |
|
Raised when a plot declares something that cannot be drawn. |
|
Raised when an experiment's viewer cannot be loaded in this environment. |
Classes
What |
|
One immutable update delivered to a monitor. |
|
Base class for PLESTY monitors: schema-declared live views. |
|
Renderer that records draw calls instead of drawing them. |
|
Draw target of a monitor — the seam between projection and toolkit. |
|
Drawable payload produced for one trace by |
|
Static declaration of one drawable element of a monitor's view. |
|
Thread-safe buffer of frames pushed in by the producer. |
|
A finished run handed out a few rows at a time, as if it were live. |
|
Frames tailed from the record file of an experiment run. |
|
Frames built from the telemetry events of one or more devices. |
|
The rows a run has committed, and the answers a plot needs from them. |
|
One element of a plot: what to draw, and how it should look. |
|
A plot written as a function — what |
|
A 2-D block of values, drawn as a map with a colour bar. |
|
A curve through |
|
One view of a run: a title, and what to draw from the run's data. |
|
A single number, shown large. |
|
Points at |
|
A line of text placed in the plot — a result, a warning, a caption. |
|
The |
Functions
|
Return the current UTC time as an ISO-8601 string. |
|
Iterate the result records of a finished run, oldest first. |
|
Every field name the rows carry, in the order first seen. |
|
Return the |
Package Contents
- plesty.lib.monitor.COLOR_SCALES: tuple[str, Ellipsis] = ('linear', 'sqrt')
- plesty.lib.monitor.TRACE_KINDS: tuple[str, Ellipsis] = ('line', 'scatter', 'image', 'scalar', 'text')
- class plesty.lib.monitor.DataSource
Bases:
ProtocolWhat
Monitor.pump()needs from a stream.Declared here as a protocol so the ABC module stays free of I/O; the concrete implementations live in
plesty.lib.monitor.sources.
- class plesty.lib.monitor.Frame
One immutable update delivered to a monitor.
- Variables:
values – Channel name → value, validated against
input_schema.seq – Monotonic index within the stream, assigned by the source.
timestamp – UTC ISO-8601 time the update was produced; filled when empty.
source – Identifier of the producing source (run id, device id, …).
context – Extra JSON-serializable context (step id, run status, file paths) carried alongside the channels but never validated.
- values: dict[str, Any]
- seq: int = 0
- timestamp: str = ''
- source: str = ''
- context: dict[str, Any]
- __post_init__() None
Stamp the creation time when the producer left it empty.
- Return type:
None
- __getitem__(channel: str) Any
Return the value of channel.
- Parameters:
channel (str) – Declared channel name.
- Returns:
The channel value.
- Raises:
KeyError – If the frame carries no such channel.
- Return type:
Any
- get(channel: str, default: Any = None) Any
Return the value of channel, or default when it is absent.
- Parameters:
channel (str) – Declared channel name.
default (Any) – Returned when the channel was not delivered.
- Returns:
The channel value, or default.
- Return type:
Any
- exception plesty.lib.monitor.FrameValidationError
Bases:
ValueErrorRaised when a submitted frame violates the declared
input_schema.Initialize self. See help(type(self)) for accurate signature.
- class plesty.lib.monitor.Monitor(source: DataSource | None = None, *, history: int | None = 1, name: str | None = None, **params: Any)
Bases:
abc.ABCBase class for PLESTY monitors: schema-declared live views.
Subclasses declare the channels they consume in
input_schemaand implement exactly two methods —traces()(what is drawn, declared once) andupdate()(what to draw for one frame). Frame validation, history, renderer fan-out, and source draining are base machinery.Channel entries use the dtype vocabulary of device and analyzer schemas (
plesty.lib.data.types.resolve_dtype()) and accept the keysdtype(required),unit,description,shape(arrays only;Nonemarks a free dimension), andrequired(defaultTrue).Initialize the monitor and validate its declarations.
- Parameters:
source (Optional[DataSource]) – Stream to subscribe to; may be attached later with
bind(), or omitted when frames are submitted by hand.history (Optional[int]) – Number of past frames kept in
frames(Nonekeeps all,1keeps only the newest). Accumulating monitors keep their own series and leave this at 1.name (Optional[str]) – Instance name, used by the shell for layout persistence; defaults to the class name.
**params (Any) – View parameters (limits, decimation, calibration), introspectable via
params.
- Raises:
MonitorSchemaError – If
input_schemais invalid ortraces()declares nothing.
- title: ClassVar[str] = ''
Human-readable view title; falls back to the class name.
- input_schema: ClassVar[dict[str, dict[str, Any]]]
name → schema entry.
- Type:
Channels this monitor consumes
- params
- name = 'Monitor'
- source = None
- count = 0
- _specs
- abstractmethod traces() list[TraceSpec]
Declare the drawable elements of this view.
Called once during construction; the result must be stable for the lifetime of the instance, because renderers build their plot items from it when they attach.
- Returns:
The trace specifications, in draw order.
- Return type:
list[TraceSpec]
- abstractmethod update(frame: Frame) dict[str, TraceData]
Project one validated frame onto the declared traces.
Implementations are pure with respect to the outside world: they read the frame and their own accumulated state and return what to draw. They must not touch devices, files, or GUI objects. A trace left out of the result keeps whatever it was showing.
- submit(frame: Frame) dict[str, TraceData]
Validate a frame, project it, and push the result to the renderers.
- Parameters:
frame (Frame) – The update to process.
- Returns:
The projected payloads returned by
update().- Raises:
FrameValidationError – If the frame violates
input_schema, orupdate()returns an undeclared trace key.- Return type:
dict[str, TraceData]
- pump() int
Drain the bound source and submit every pending frame.
Runs on the caller’s clock — a GUI timer, a test loop — so the monitor owns no thread of its own.
- Returns:
The number of frames submitted.
- Return type:
int
- bind(source: DataSource) None
Subscribe this monitor to source.
- Parameters:
source (DataSource) – The stream
pump()will drain.- Return type:
None
- attach(renderer: Renderer) Renderer
Attach a renderer, build its items, and replay the last drawn data.
- detach(renderer: Renderer) None
Remove a previously attached renderer.
- Parameters:
renderer (Renderer) – The draw target to remove; unknown renderers are ignored.
- Return type:
None
- reset() None
Clear history, projected state, and every attached renderer.
Subclasses that accumulate their own series override this, drop that state, and call
super().reset().- Return type:
None
- snapshot() dict[str, TraceData]
Return the most recent payload of every trace drawn so far.
- Returns:
Trace key → payload; empty before the first frame.
- Return type:
dict[str, TraceData]
- property trace_specs: list[TraceSpec]
The declared traces, in draw order.
- Return type:
list[TraceSpec]
- status() str
Return a one-line status shown beside the title in a shell.
The default reports how many frames were consumed; subclasses override it with something the operator cares about (the newest angle, the peak wavelength, the run id).
- Returns:
The status line.
- Return type:
str
- describe() dict[str, Any]
Return a JSON-serializable description of this view.
Shells use it for layout persistence, and reporting tooling to record what was watched during a run.
- Returns:
Monitor identity, parameters, channels, and declared traces.
- Return type:
dict[str, Any]
- _validate_schema() None
Check
input_schemaentry by entry.- Raises:
MonitorSchemaError – On an unknown key, a missing or unresolvable
dtype, or a malformedshape.- Return type:
None
- _conform_values(values: dict[str, Any]) dict[str, Any]
Check frame channels against
input_schema, coercing array-likes.Unlike analyzer inputs, live frames arrive from JSON step records and telemetry events, so array channels are coerced from plain lists here instead of being rejected.
- Parameters:
values (dict[str, Any]) – The raw channel mapping of the frame.
- Returns:
The conformed mapping.
- Raises:
FrameValidationError – On an unknown or missing channel, a wrong dtype, or a shape contradicting the declaration.
- Return type:
dict[str, Any]
- _conform_channel(name: str, value: Any, entry: dict[str, Any]) Any
Conform one channel value to its declared dtype and shape.
- Parameters:
name (str)
value (Any)
entry (dict[str, Any])
- Return type:
Any
- static _conform_array(name: str, value: Any, entry: dict[str, Any]) plesty.lib.data.array.PlestyArray
Coerce an array channel and check it against the declared shape.
- Parameters:
name (str)
value (Any)
entry (dict[str, Any])
- Return type:
- exception plesty.lib.monitor.MonitorSchemaError
Bases:
ValueErrorRaised when a monitor’s channel or trace declaration is invalid.
Initialize self. See help(type(self)) for accurate signature.
- class plesty.lib.monitor.NullRenderer
Bases:
RendererRenderer that records draw calls instead of drawing them.
Used by tests and by headless runs that only need the projected data.
Initialize the empty draw log.
- class plesty.lib.monitor.Renderer
Draw target of a monitor — the seam between projection and toolkit.
The base implementation does nothing, so headless callers and tests use a monitor without any GUI dependency; GUI backends (
plesty.lib.ui) subclass it.- setup(monitor: Monitor) None
Build the drawable items declared by
monitor.traces().- Parameters:
monitor (Monitor) – The monitor this renderer was attached to.
- Return type:
None
- class plesty.lib.monitor.TraceData
Drawable payload produced for one trace by
Monitor.update().- Variables:
x – Sample positions of a
line/scattertrace.y – Sample values of a
line/scattertrace.image – 2-D array of an
imagetrace.value – Number shown by a
scalartrace.text – Text of a
texttrace, or an annotation for any other kind.
- x: Sequence[float] | None = None
- y: Sequence[float] | None = None
- image: Any = None
- value: float | None = None
- text: str | None = None
- class plesty.lib.monitor.TraceSpec
Static declaration of one drawable element of a monitor’s view.
Specs are read when a renderer attaches, to build its plot items; only
TraceDatachanges per frame.- Variables:
key – Identifier used as the key of the
Monitor.update()result.kind – One of
TRACE_KINDS.label – Legend label; falls back to key when empty. A label starting with
_keeps the trace out of the legend, as in matplotlib — for a trace the legend would only repeat, such as a fitted curve drawn in the colour of its points.x_label – Axis label including the unit, e.g.
"Wavelength (nm)".y_label – Axis label including the unit, e.g.
"Power (uW)".color – PLESTY palette token (
"cyan","violet","mint","amber","rose","blue"). The renderer resolves it against the theme, so monitors never hard-code hex values.width – Line width, or marker size for
scatter.marker – Draw point markers on a
linetrace.scale – Colour scale of an
imagetrace, one ofCOLOR_SCALES:"linear", or"sqrt"— colours follow the square root of the value, so lines ten times weaker than the strongest still stand out from the background; the colour bar stays labelled in the image’s own values.
- key: str
- kind: str = 'line'
- label: str = ''
- x_label: str = ''
- y_label: str = ''
- color: str = 'cyan'
- width: float = 1.5
- marker: bool = False
- scale: str = 'linear'
- __post_init__() None
Validate the trace kind and colour scale.
- Raises:
MonitorSchemaError – If
kindorscaleis not a known one.- Return type:
None
- plesty.lib.monitor.utc_timestamp() str
Return the current UTC time as an ISO-8601 string.
- Return type:
str
- plesty.lib.monitor.FrameMapper
- class plesty.lib.monitor.PushSource(name: str = 'push', maxlen: int | None = 10000)
Thread-safe buffer of frames pushed in by the producer.
Producers call
emit()from any thread; the consumer drains the buffer withpoll()on its own thread. When maxlen is set the buffer drops the oldest pending frames instead of growing without bound — a slow consumer never turns into a memory leak.Initialize the buffer.
- Parameters:
name (str) – Identifier stamped onto every frame’s
source.maxlen (Optional[int]) – Maximum number of pending frames;
Nonefor unbounded.
- name = 'push'
- _queue: collections.deque[plesty.lib.monitor.base_monitor.Frame]
- _lock
- _seq = 0
- emit(values: dict[str, Any], **context: Any) plesty.lib.monitor.base_monitor.Frame
Buffer one update.
- Parameters:
values (dict[str, Any]) – Channel name → value.
**context (Any) – Extra context carried on the frame.
- Returns:
The buffered
Frame.- Return type:
- poll() list[plesty.lib.monitor.base_monitor.Frame]
Return and clear the buffered frames.
- Returns:
The pending frames in emission order.
- Return type:
- close() None
Drop everything still buffered.
- Return type:
None
- class plesty.lib.monitor.ReplaySource(run_dir: str | pathlib.Path, *, mapper: FrameMapper | None = None, name: str | None = None, rows_per_poll: int = 1, loop: bool = False)
Bases:
RunSourceA finished run handed out a few rows at a time, as if it were live.
Watching a stored run play back is how a viewer is demonstrated, how a layout is judged before the beam time that needs it, and how a run that went wrong is re-read at the pace it happened rather than as a finished picture. It is the same source as
RunSource— the records are the ones the experiment committed — only rationed.The wall-clock speed is the consumer’s refresh interval times
rows_per_poll: a shell ticking every 500 ms with the default of one row replays two rows per second.The ration counts records, including those the mapper rejects, so every view reaches a record at the same moment of the replay whatever its mapper keeps. A view that uses only the run’s last record — an analysis done after the sweep — shows it when the replay gets there, not on the first poll.
source = ReplaySource(run_dir, mapper=to_channels, rows_per_poll=2) monitor.bind(source) # the run rebuilds itself in the window
Replay a run directory.
- Parameters:
run_dir (str | pathlib.Path) – The run’s checkpoint directory.
mapper (Optional[FrameMapper]) – Turns one record into a view’s channels; see
RunSource.name (Optional[str]) – Identifier stamped onto every frame’s
source.rows_per_poll (int) – Records handed out per
poll(); with the consumer’s refresh interval, this is the replay speed.loop (bool) – Start over once the run is exhausted, instead of stopping at the last row.
- Raises:
ValueError – If rows_per_poll is not positive — a replay that hands out nothing would look like a stalled run.
- rows_per_poll = 1
- loop = False
- _pending: list[plesty.lib.monitor.base_monitor.Frame | None] = []
- poll() list[plesty.lib.monitor.base_monitor.Frame]
Return the frames of the next few records of the run.
- Returns:
The frames among the next
rows_per_pollrecords — fewer, or none, where the mapper rejected a record; empty once the run is exhausted, unlessloopis set.- Return type:
- _pending_records() list[plesty.lib.monitor.base_monitor.Frame | None]
Return one entry per newly committed record: its frame, or
None.- Return type:
list[Optional[plesty.lib.monitor.base_monitor.Frame]]
- property exhausted: bool
Whether every record of a finished run has been handed out.
False while a record is still buffered or still on disk unread, and false for a run that is still measuring — there, the next record is simply not written yet. A looping replay is never exhausted: the next poll starts it over.
- Return type:
bool
- rewind() None
Start the replay over from the first record.
- Return type:
None
- class plesty.lib.monitor.RunSource(run_dir: str | pathlib.Path, *, mapper: FrameMapper | None = None, name: str | None = None)
Frames tailed from the record file of an experiment run.
The experiment appends one line per completed step to
records.jsonl(append_record()), and that line is the commit record: it is complete only once the step is fully persisted. Tailing the file by offset is therefore both safe and cheap — the source reads, never writes, costs one small read per poll however long the run, and can attach to a run that started hours ago and still see every row, including the ones it missed.Records are emitted in write order; a line still being written (no newline yet) waits for the next poll. Runs written by plesty-lib ≤ 0.3.4 (one
data/step_*.jsonper step) are read the old way.source = RunSource("runs/qd_fss_20260804-214826", mapper=lambda rec: {"angle_deg": rec["hwp_deg"]}) monitor.bind(source) monitor.pump() # → submits every row persisted so far
Follow a run directory.
- Parameters:
run_dir (str | pathlib.Path) – The run’s checkpoint directory (the one holding
plan.json,journal.jsonl, andrecords.jsonl).mapper (Optional[FrameMapper]) – Turns one record into the channel mapping a monitor declares; returning
Nonedrops the record (useful for the bookkeeping steps a plan starts with). The default passes the record through unchanged.name (Optional[str]) – Identifier stamped onto every frame’s
source; defaults to the run directory name.
- run_dir
- mapper = None
- name = ''
- _offset = 0
- _seen: set[str]
- _seq = 0
- property legacy: bool
Whether the run is in the per-step-document layout (no record file).
- Return type:
bool
- _new_records() list[tuple[str, dict[str, Any]]]
Return the (label, record) pairs committed since the last call.
- Return type:
list[tuple[str, dict[str, Any]]]
- poll() list[plesty.lib.monitor.base_monitor.Frame]
Return frames for the records committed since last time.
- Returns:
The new frames in write order; empty while the run directory does not exist yet, so a viewer may be started before the experiment.
- Return type:
- _frame(label: str, record: dict[str, Any]) plesty.lib.monitor.base_monitor.Frame | None
Map one record to a frame, or
Nonewhen the mapper rejects it.- Parameters:
label (str)
record (dict[str, Any])
- Return type:
Optional[plesty.lib.monitor.base_monitor.Frame]
- property unread: bool
Whether committed records exist that no poll has returned yet.
- Return type:
bool
- rewind() None
Forget which records were seen, so the next poll replays the run.
- Return type:
None
- property finished: bool
Whether the run reached a terminal state.
A completed, aborted, or canceled run writes no further records, so a viewer can stop polling (and stop recording) on its own.
- Return type:
bool
- status() dict[str, Any]
Return the run status derived from the journal.
- Returns:
The summary of
plesty.lib.experiment.journal.Journal.status()— state, completed and failed step counts, last event.- Return type:
dict[str, Any]
- close() None
Release nothing — the source holds no handle; kept for symmetry.
- Return type:
None
- class plesty.lib.monitor.TelemetrySource(devices: Sequence[Any], *, kinds: Sequence[str] | None = None, names: Sequence[str] | None = None, name: str = 'telemetry', maxlen: int | None = 10000)
Bases:
PushSourceFrames built from the telemetry events of one or more devices.
Registers a hook on every device (see
register_telemetry_hook()) and buffers each event as a frame with the channelsdevice,kind,name,value, andunit, plus the event’s own context. Hooks run on the emitting device’s thread, so buffering is all that happens there.Subscribe to the devices’ telemetry.
- Parameters:
devices (Sequence[Any]) – Devices exposing
register_telemetry_hook.kinds (Optional[Sequence[str]]) – Event kinds to keep (see
TELEMETRY_KINDS);Nonekeeps every kind.names (Optional[Sequence[str]]) – Parameter/metric names to keep;
Nonekeeps all.name (str) – Identifier stamped onto every frame’s
source.maxlen (Optional[int]) – Maximum number of pending frames.
- _devices
- _kinds = None
- _names = None
- _on_event(event: Any) None
Buffer one telemetry event, honouring the kind/name filters.
- Parameters:
event (Any)
- Return type:
None
- close() None
Unregister the hooks and drop the buffered frames.
- Return type:
None
- plesty.lib.monitor.records(run_dir: str | pathlib.Path) Iterable[dict[str, Any]]
Iterate the result records of a finished run, oldest first.
The offline counterpart of
RunSource, for replaying a run into a monitor or feeding an analyzer.- Parameters:
run_dir (str | pathlib.Path) – The run’s checkpoint directory.
- Yields:
One record per readable committed result, in write order.
- Return type:
Iterable[dict[str, Any]]
- plesty.lib.monitor.Reader
- class plesty.lib.monitor.RunData(run: plesty.lib.experiment.runs.Run | str, *, reads: Reader | None = None, rows: Sequence[Mapping[str, Any]] | None = None)
The rows a run has committed, and the answers a plot needs from them.
- Variables:
run – The run being read.
reads – Expands a row into extra columns, or
None.
- Parameters:
run (plesty.lib.experiment.runs.Run | str)
reads (Optional[Reader])
rows (Optional[Sequence[Mapping[str, Any]]])
Read the run at run.
- Parameters:
run (plesty.lib.experiment.runs.Run | str) – The run, or a path to one.
reads (Optional[Reader]) – Called once per row to add columns the records only point at — a spectrum file becomes
wavelengthandcounts. Its answer is cached, so every plot shares one load.rows (Optional[Sequence[Mapping[str, Any]]]) – Rows to start from instead of reading; used by
where()to build a filtered view over rows already read.
- run
- reads = None
- _rows: list[dict[str, Any]]
- _source: Any = None
- _derived
- poll() int
Ingest whatever has committed since the last call.
Cheap however long the run has been going: the records file is read from the byte offset reached last time, so a poll costs one small read and never re-parses what it already holds.
- Returns:
How many rows were added.
- Raises:
RuntimeError – On a filtered view, which reads nothing of its own.
- Return type:
int
- _expand(row: dict[str, Any]) dict[str, Any]
Return row with whatever
readsadds to it.A reader that fails is not allowed to end the watching: a spectrum still being written, or one file of a thousand that is corrupt, costs that row its extra columns and nothing else.
- Parameters:
row (dict[str, Any])
- Return type:
dict[str, Any]
- property rows: list[dict[str, Any]]
Every row committed so far, oldest first.
- Return type:
list[dict[str, Any]]
- property latest: dict[str, Any] | None
The newest committed row, whatever kind of step wrote it.
A plan’s steps are not all alike: a sweep commits a spectrum per angle and then an analysis, and the analysis is the newest row. A view of the spectra wants
last()instead.- Return type:
Optional[dict[str, Any]]
- last(name: str) dict[str, Any] | None
The newest row that carries name, or
None.What “the current spectrum” means when the newest row is the fit that followed it.
- Parameters:
name (str) – The field the row must carry.
- Returns:
The row, or
Nonewhen none has it yet.- Return type:
Optional[dict[str, Any]]
- column(name: str, default: Any = np.nan) numpy.ndarray
One field across every row, as an array.
- Parameters:
name (str) – The field.
default (Any) – Value for a row that does not carry it —
nanby default, so a gap stays a gap instead of shifting the axis.
- Returns:
One entry per row, in commit order.
- Raises:
ValueError – If the field holds arrays rather than single values — naming
stack(), which is what such a field is for. Without this the failure is numpy’s, about inhomogeneous shapes, which says nothing about what to do instead.- Return type:
numpy.ndarray
- stack(name: str) numpy.ndarray
An array field across every row, as one 2-D block.
Rows whose entry is missing or a different length are left out rather than padded: a spectral map with a half-row in it is a lie about what was measured.
- Parameters:
name (str) – The field.
- Returns:
Shape
(rows, samples); empty when nothing usable was found.- Return type:
numpy.ndarray
- stacked(name: str, along: str = '', default: Any = np.nan) tuple[numpy.ndarray, numpy.ndarray | None]
The stack of name, and along for exactly the rows it kept.
Asking for the block and its coordinate separately is a bug waiting to happen:
stack()leaves out rows that carry no array or the wrong width, and those rows are not necessarily at either end — a sweep that ends in an analysis drops its last row. A coordinate taken fromcolumn()would then be one row longer and misaligned, which draws every spectrum against the wrong position. One call decides which rows are usable and answers for both.- Parameters:
name (str) – The array field.
along (str) – Field holding each kept row’s coordinate;
""for none.default (Any) – Coordinate of a kept row that does not carry along.
- Returns:
The block, shape
(rows, samples), and the coordinate of each of its rows — orNonewhen along was not asked for.- Return type:
tuple[numpy.ndarray, Optional[numpy.ndarray]]
- where(**fields: Any) RunData
The same data, narrowed to rows whose fields equal fields.
- Parameters:
**fields (Any) – Field name to required value.
- Returns:
A view over the rows already read — it holds no source and is not polled; poll the data it came from and ask again.
- Return type:
- property config: dict[str, Any]
The configuration frozen into the run’s plan.
- Return type:
dict[str, Any]
- property provenance: dict[str, Any]
What was running when the run started;
{}for an older run.- Return type:
dict[str, Any]
- status() dict[str, Any]
The run’s state and step counts, read from its journal.
- Return type:
dict[str, Any]
- property finished: bool
Whether the run reached a state that produces no more rows.
- Return type:
bool
- __len__() int
How many rows have been committed.
- Return type:
int
- __iter__() Iterator[dict[str, Any]]
Iterate the rows, oldest first.
- Return type:
Iterator[dict[str, Any]]
- __bool__() bool
Whether any row has been committed.
Spelled out because
__len__would otherwise make an empty run falsy in a way a plot guarding onif data:might not intend.- Return type:
bool
- __repr__() str
Return
RunData('<run id>', rows=<n>).- Return type:
str
- plesty.lib.monitor.columns(rows: Iterable[Mapping[str, Any]]) list[str]
Every field name the rows carry, in the order first seen.
- Parameters:
rows (Iterable[Mapping[str, Any]]) – The rows to survey.
- Returns:
The field names — what a generic view offers when it has not been told which fields matter.
- Return type:
list[str]
- plesty.lib.monitor.COLORS: tuple[str, Ellipsis] = ('cyan', 'violet', 'mint', 'amber', 'rose', 'blue')
- plesty.lib.monitor.SCALES: tuple[str, Ellipsis] = ('linear', 'sqrt')
- class plesty.lib.monitor.Drawable
One element of a plot: what to draw, and how it should look.
- Variables:
label – Legend label. One starting with
_stays out of the legend, as in matplotlib — for a trace the legend would only repeat, such as a fitted curve in the colour of its points.color – A token from
COLORS.x_label – Axis label including the unit,
"Wavelength (nm)".y_label – Axis label including the unit.
- kind: ClassVar[str] = 'drawable'
- label: str = ''
- color: str = 'cyan'
- x_label: str = ''
- y_label: str = ''
- plesty.lib.monitor.Drawing
- class plesty.lib.monitor.FunctionPlot(func: DrawFunc, title: str = '', *, name: str = '', weight: float | None = None)
Bases:
PlotA plot written as a function — what
Viz.plot()wraps.Not usually built by hand: decorating a function with
plot()makes one of these.Wrap func as a plot.
- Parameters:
func (DrawFunc) – Takes the run’s data, returns drawables.
title (str) – What the view is called; defaults to the function’s name with underscores as spaces.
name (str) – Layout key.
weight (Optional[float]) – Relative size.
- func
- class plesty.lib.monitor.Image
Bases:
DrawableA 2-D block of values, drawn as a map with a colour bar.
- Variables:
z – The values, shape
(rows, columns).x – Positions of the columns, for the axis.
y – Positions of the rows, for the axis.
scale –
"linear", or"sqrt"— colours follow the square root of the value, so features ten times weaker than the strongest still stand out from the background. The bar stays labelled in the image’s own values.
- kind: ClassVar[str] = 'image'
- z: Any = None
- x: Any = None
- y: Any = None
- scale: str = 'linear'
- class plesty.lib.monitor.Line
Bases:
DrawableA curve through
(x, y).- Variables:
x – Sample positions.
y – Sample values.
width – Line width.
marker – Draw a point marker at every sample as well.
- kind: ClassVar[str] = 'line'
- x: Any = None
- y: Any = None
- width: float = 1.5
- marker: bool = False
- class plesty.lib.monitor.Plot(title: str = '', *, name: str = '', weight: float | None = None, area: str = '')
Bases:
abc.ABCOne view of a run: a title, and what to draw from the run’s data.
Subclass this when a view has to remember something between ticks — a line tracker, a running baseline. For a view that is a pure function of the data,
plot()takes the function directly and there is no class to write.- Variables:
title – What the view is called, on its dock tab.
name – Stable identifier, used as the layout key so an arrangement survives a restart; defaults to the title.
weight – Relative size when the panels are first laid out.
area – Which side of the window it starts on — one of
DOCK_AREAS. Views sharing an area are stacked in one column, so this is how a viewer says which of its plots belong side by side. The operator can drag them anywhere afterwards, and the arrangement is remembered.
- Parameters:
title (str)
name (str)
weight (Optional[float])
area (str)
Name the view.
- Parameters:
title (str) – Overrides the class attribute.
name (str) – Layout key; defaults to the title.
weight (Optional[float]) – Overrides the class attribute.
area (str) – Overrides the class attribute.
- title: str = ''
- name: str = ''
- weight: float = 1.0
- area: str = 'right'
- abstractmethod draw(data: Any) Drawing
Return what to draw, given everything the run has produced.
Called on every tick, on the GUI thread. It should be a projection of the data and nothing else — no device is reachable from here and none should be: watching never disturbs measuring.
- build() Any
Return a widget for this view instead of a plot, or
None.The escape hatch. A view that is not a plot at all — a table of the committed rows, an image browser, a strip of readouts — returns its own widget here and ignores
draw(). Anything Qt can show is allowed; the dock does not care what is inside it.- Returns:
Noneby default, meaning “draw me as a plot”.- Return type:
Any
- __repr__() str
Return
<ClassName 'title'>.- Return type:
str
- exception plesty.lib.monitor.PlotError
Bases:
ValueErrorRaised when a plot declares something that cannot be drawn.
Initialize self. See help(type(self)) for accurate signature.
- class plesty.lib.monitor.Scalar
Bases:
DrawableA single number, shown large.
- Variables:
value – The number.
unit – Shown after it.
- kind: ClassVar[str] = 'scalar'
- value: float | None = None
- unit: str = ''
- class plesty.lib.monitor.Scatter
Bases:
DrawablePoints at
(x, y), drawn without a line between them.- Variables:
x – Sample positions.
y – Sample values.
size – Marker size.
- kind: ClassVar[str] = 'scatter'
- x: Any = None
- y: Any = None
- size: float = 8.0
- class plesty.lib.monitor.Text
Bases:
DrawableA line of text placed in the plot — a result, a warning, a caption.
- Variables:
text – What to show.
- kind: ClassVar[str] = 'text'
- text: str = ''
- class plesty.lib.monitor.Viz(title: str, *, experiment: str | Sequence[str] | None = None, run_root: str | pathlib.Path | None = None, reads: plesty.lib.monitor.data.Reader | None = None)
The
monitor/rendercommand line over one experiment’s panels.Describe the experiment whose runs are watched.
- Parameters:
title (str) – Human title of the experiment, shown in the window title and the command-line description.
experiment (Union[str, Sequence[str], None]) – The experiment name(s) whose runs to look for when
--runis not given — a name or several (an experiment that was renamed still owns its old runs).Nonetakes the newest run of any experiment.run_root (Optional[str | pathlib.Path]) – Where runs are looked for — the experiment’s root, under the shared point (
PLESTY_DATA) when relative;Nonetakes the shared point itself, andrunswithout one.--run-rootoverrides per call.reads (Optional[plesty.lib.monitor.data.Reader]) – Expands one committed row into the columns the plots want — a record names a spectrum file rather than carrying the array, so something has to turn the path into numbers. One per viewer, cached per row, so a map and a fit of the same sweep load each spectrum once between them. An experiment whose records hold their own numbers omits it.
- title
- experiment = None
- run_root = None
- reads = None
- plots: list[plesty.lib.monitor.plots.Plot] = []
- _panels: PanelsFunc | None = None
- add_plot(plot: plesty.lib.monitor.plots.Plot) plesty.lib.monitor.plots.Plot
Add plot to the window; returns it.
- Parameters:
plot (plesty.lib.monitor.plots.Plot) – A
Plot.- Returns:
The plot, so a caller can keep a reference to one it will poke.
- Return type:
- plot(title: str = '', *, name: str = '', weight: float | None = None) Callable[[plesty.lib.monitor.plots.DrawFunc], plesty.lib.monitor.plots.DrawFunc]
Add a plot written as a function. Use as a decorator.
@viz.plot("Spectrum") def spectrum(data): row = data.latest return [Line(row["wavelength"], row["counts"])]
The function is called on every tick with the run’s
RunDataand returns drawables. It is handed the whole store rather than declared channels, so a plot that starts wanting one more field needs no second declaration to keep in step.- Parameters:
title (str) – What the view is called; defaults to the function’s name.
name (str) – Layout key, so an arrangement survives a rename of the title; defaults to the title.
weight (Optional[float]) – Relative size when the panels are first laid out.
- Returns:
The decorator, which returns the function unchanged so it stays callable and testable on its own.
- Return type:
Callable[[plesty.lib.monitor.plots.DrawFunc], plesty.lib.monitor.plots.DrawFunc]
- panels(func: PanelsFunc) PanelsFunc
Register a function that turns a
Runinto panels directly.Superseded by
plot(), and kept for viewers written against the older shape. A viewer that registers plots does not need this; one that registers both shows the panels and then the plots.- Parameters:
func (PanelsFunc)
- Return type:
- data(run: plesty.lib.experiment.runs.Run) plesty.lib.monitor.data.RunData
Return the store this viewer’s plots read.
- Parameters:
run (plesty.lib.experiment.runs.Run) – The run to read.
- Returns:
- Return type:
- build_parser() argparse.ArgumentParser
Return the argument parser: shared options plus the two subcommands.
- Return type:
argparse.ArgumentParser
- view(run: plesty.lib.experiment.runs.Run, *, interval_ms: int = 500, remember_layout: bool = True, title: str | None = None) Any
Compose this experiment’s panels over run, without showing them.
This is the whole of what an experiment’s viewer is: the panels its
panels()function yields, docked together and ticking. What is done with the result is the caller’s business —main()gives it a window of its own, and a host application puts the same object in a layout, because a shell is a widget before it is a window.So an experiment writes its views once and they are embeddable wherever the module can be imported, with no second composition to keep in step and nothing serialized between them. A console that does not have the module installed cannot call this at all, and opens the window instead — that is the only difference between the two.
- Parameters:
run (plesty.lib.experiment.runs.Run) – The run to watch.
interval_ms (int) – How often the panels are pumped.
remember_layout (bool) – Restore and save the arrangement. A host that embeds the view usually says
False: the arrangement of a pane inside another window is not the arrangement of the experiment’s own window.title (Optional[str]) – Window title and layout key;
Nonenames the experiment and the run.
- Returns:
A
Shellholding the panels, not yet started — the caller callsstart()when it is in place.- Raises:
RuntimeError – If the viewer declares neither plots nor panels.
ValueError – If nothing came of them; an empty view says less than the reason it is empty.
- Return type:
Any
- resolve_run(args: argparse.Namespace) plesty.lib.experiment.runs.Run
Return the
Runthe arguments name, configured for the subcommand.- Raises:
SystemExit – If no run exists yet — a viewer opened before its experiment is a mistake worth naming, not an empty window.
- Parameters:
args (argparse.Namespace)
- Return type:
- main(argv: Sequence[str] | None = None) int
Run the command line and return the exit code.
- Parameters:
argv (Optional[Sequence[str]]) – Argument list;
Noneusessys.argv.- Raises:
RuntimeError – If no panels function was registered.
SystemExit – If no run exists, or the panels function yields nothing.
- Return type:
int
- exception plesty.lib.monitor.VizNotAvailable
Bases:
RuntimeErrorRaised when an experiment’s viewer cannot be loaded in this environment.
Initialize self. See help(type(self)) for accurate signature.
- plesty.lib.monitor.load_viz(module: str) Viz
Return the
Vizan experiment’s viewer module declares.A host application — a console managing several experiments — embeds an experiment’s own views by importing its viewer here and calling
Viz.view(). That works exactly when the module is installed alongside the host, which is the condition, and the honest failure when it is not: the host then opens the viewer as its own process instead.The module is expected to hold exactly one
Vizat module level, which is how every viewer is written —viz = Viz("…")beside the panels function it decorates.- Parameters:
module (str) – Import path of the viewer,
plesty.pol_pl.viz.- Returns:
The viewer’s
Viz.- Raises:
VizNotAvailable – If the module cannot be imported here — usually because the experiment is not installed in this environment — or does not declare exactly one
Viz.- Return type: