plesty.fss.monitor
The fine-structure views, for the viewer of any experiment that runs a sweep.
Two views follow the emission lines of a polarization sweep, each line with the
same number and colour in both — line 0 is the shortest wavelength:
LineSpectrumView— the newest spectrum, with a marker on every line.FineStructureView— every line’s position as a photon-energy shift in µeV from its mean position, against the rotator angle.
Both fill in two stages:
During the sweep — a
LineTrackerfinds the lines the way the analysis does, in the spectra measured so far, and fits each spectrum as it arrives. Early in a sweep a line can still appear or disappear, and the numbering follows.After the sweep — an experiment that runs
plesty.fss.FineStructureand saves itsfine_structureandfitoutputs withsave_resultrecords where it saved them. That record replaces the running estimate with the analysis: the fits of the whole sweep, each line’s fitted sine, and its splitting and polarization axis written in the line’s colour — or that the line has no valid splitting.
An experiment adds them to its Viz by name. It
says which of its record fields hold the sweep; nothing else is configured:
from plesty.lib.monitor import Viz
from plesty.fss.monitor import FineStructureView, LineSpectrumView, LineTracking
viz = Viz("Polarization PL", experiment="pol_pl", reads=read_spectrum)
lines = LineTracking(angle="hwp_deg", label="qd")
viz.add_plot(LineSpectrumView(lines, weight=3.0))
viz.add_plot(FineStructureView(lines, angle_label="HWP angle (deg)", weight=3.0))
One LineTracking is shared by both views on purpose: it fits each
spectrum once and answers both from that one fit.
These views draw lines, points and text, so they have no error bars and no
residual panel; plesty.fss.plot.plot_fine_structure() draws both for
reports.
Attributes
Classes
Find and fit the lines of a sweep while it is measured. |
|
Follows a run's emission lines while the sweep is being measured. |
|
The lines of a sweep as a |
|
The newest spectrum, with a marker on every line the fine structure follows. |
|
Energy shift of every line against the rotator angle, with its fit and result. |
Functions
|
The colour of the index-th line, counting from the shortest wavelength. |
|
One analysed line: its measured shifts as points, and its fitted sine. |
|
Compute what the view draws from the analyzer's |
Module Contents
- class plesty.fss.monitor.LineTracker(fit_options: Mapping[str, Any])
Find and fit the lines of a sweep while it is measured.
Lines are found the way
SpectrumFitfinds them for the analysis: in the average of the spectra — so far — with the sameprominence,distanceandaverage(use"median": in the mean of a few spectra a cosmic ray passes as a line). Givenpeaks, those positions are the lines and nothing is searched.Each new spectrum is fitted with the analysis’s other fit options, starting from the previous spectrum’s positions. When the lines found change — a line appears or disappears — the positions fitted so far are kept for the lines that remain, so the numbering by wavelength can shift but no spectrum is refitted. A line whose position moves by up to
SAME_LINE_PIXELSpixels is the same line.One tracker serves both views of a run: each spectrum is fitted once, and a view that reads a spectrum later than the other gets the same answer. A spectrum with a different label starts a new sweep.
Validate the fit options.
- Parameters:
fit_options (Mapping[str, Any]) –
SpectrumFitoptions, with either the line positions inpeaksor aprominenceto find them.- Raises:
ValueError – If neither
peaksnorprominenceis given, or an option is invalid.
- fixed: numpy.ndarray | None = None
- prominence
- distance
- average = ''
- fit_options
- fits = 0
- _seen: dict[str, SweepSoFar]
- _label: str | None = None
- _wavelength: numpy.ndarray | None = None
- _spectra: list[numpy.ndarray] = []
- _angles: list[float] = []
- _rows: list[numpy.ndarray] = []
- _positions: numpy.ndarray
- observe(channels: Mapping[str, Any]) SweepSoFar
Add one spectrum and return the sweep so far.
- Parameters:
channels (Mapping[str, Any]) – One spectrum’s
wavelengthin nm andcounts, withrow(the rotator angle in degrees) andlabelwhen known.- Returns:
The lines and their positions after this spectrum.
- Return type:
- _reset(label: str | None) None
Start a new sweep.
- Parameters:
label (Optional[str])
- Return type:
None
- _update_lines() None
Find the lines in the spectra so far; keep the columns of the lines that remain.
- Return type:
None
- _fit(counts: numpy.ndarray) numpy.ndarray
Fit the lines in one spectrum, from the previous spectrum’s positions.
- Parameters:
counts (numpy.ndarray)
- Return type:
numpy.ndarray
- class plesty.fss.monitor.LineTracking(options: Mapping[str, Any] | None = None, *, at: Sequence[str] = ('analysis', 'fit_options'), counts: str = 'counts', wavelength: str = 'wavelength', angle: str = '', label: str = '', fit_key: str = 'line_fit_document', budget: int = 4)
Follows a run’s emission lines while the sweep is being measured.
Hand the same instance to both views. A tracker fits each spectrum once and answers from its own record afterwards, so two views cost one fit per spectrum rather than two.
The fit options are the analysis’s own, so the lines followed during the sweep are the lines reported after it. Without line positions (
peaks) or aprominenceto find them nothing is tracked: every bump of the noise would otherwise be a line, and the views simply show none.- Variables:
options – The fit options, or
Noneto read them from each run’s own configuration.- Parameters:
options (Optional[Mapping[str, Any]])
at (Sequence[str])
counts (str)
wavelength (str)
angle (str)
label (str)
fit_key (str)
budget (int)
Say where the sweep is in the records, and how its lines are found.
- Parameters:
options (Optional[Mapping[str, Any]]) –
SpectrumFitoptions, orNoneto take them from the run’s frozen configuration.at (Sequence[str]) – Keys leading to the fit options in that configuration, used only when options is
None. The default is where an experiment that configures aplesty.fss.FineStructureunderanalysiskeeps them.counts (str) – Record field holding each spectrum’s counts.
wavelength (str) – Record field holding its wavelength axis, in nm.
angle (str) – Record field holding the rotator angle in degrees;
""when the run does not record one.label (str) – Record field labelling the sweep — the quantum dot, say. A spectrum with a different label starts a new sweep.
fit_key (str) – Record field naming the analysis’s saved line fit. Once a run has written one there is nothing left to track: the analysis fitted every spectrum of the sweep already, and its answer is the one the run reports. Reading it costs one file instead of re-fitting the whole sweep.
budget (int) – How many spectra one
sweep()may fit. Fitting happens inside a view’s draw, on the thread that answers the window, so an unbounded call is a window that stops answering for as long as the backlog takes. The rest are fitted on the calls that follow.0removes the bound, for a caller that is not drawing — a script, or a test that wants the whole sweep in one go.
- options = None
- at = ('analysis', 'fit_options')
- counts = 'counts'
- wavelength = 'wavelength'
- angle = ''
- label = ''
- fit_key = 'line_fit_document'
- budget = 4
- _analysed: dict[str, SweepSoFar | None]
- _trackers: dict[str, LineTracker | None]
- tracker(data: Any) LineTracker | None
The tracker that finds this run’s lines, built once per run.
- Parameters:
data (Any) – The run’s data.
- Returns:
The tracker, or
Nonewhen this run gives it nothing to find lines by.- Return type:
Optional[LineTracker]
- _configured(data: Any) dict[str, Any]
Return the fit options the run’s own configuration carries at
at.- Parameters:
data (Any)
- Return type:
dict[str, Any]
- sweep(data: Any) SweepSoFar | None
The lines of the current sweep, as far as it has been measured.
While the sweep runs, every spectrum committed so far is handed to the tracker in order; it fits each one once and answers from its own record afterwards, so calling this from both views costs one fit per spectrum.
Once the analysis has written its line fit there is nothing left to track, and the tracker is not used at all. That matters for opening a finished run: re-fitting ninety spectra to draw a marker on one of them took seconds before the first frame appeared, and produced a worse answer than the analysis had already saved beside it.
- Parameters:
data (Any) – The run’s data.
- Returns:
The sweep so far, or
Nonewhen nothing is tracked or no spectrum has been committed.- Return type:
Optional[SweepSoFar]
- _analysis(data: Any) SweepSoFar | None
The sweep as the analysis fitted it, or
Nonebefore it wrote one.Read once per run and kept: a view redrawn twice a second must not re-parse the document each tick.
- Parameters:
data (Any) – The run’s data.
- Returns:
The fitted positions of every line in every spectrum of the sweep.
- Return type:
Optional[SweepSoFar]
- class plesty.fss.monitor.SweepSoFar
The lines of a sweep as a
LineTrackerknows them after one spectrum.- Variables:
label – Label of the sweep, e.g. the quantum dot, or
None.positions – Position of each line in nm, shortest wavelength first.
angles – Rotator angle of every spectrum so far, in degrees (
nanif unknown).centers – Fitted position of each line in each spectrum so far, (spectra, lines),
nanwhere the fit failed or the line was not yet found.
- label: str | None
- positions: numpy.ndarray
- angles: numpy.ndarray
- centers: numpy.ndarray
- property latest: numpy.ndarray
Fitted position of each line in the newest spectrum.
- Return type:
numpy.ndarray
- plesty.fss.monitor.LINE_COLORS: tuple[str, ...] = ('cyan', 'amber', 'violet', 'mint', 'rose', 'blue', 'text_bright', 'slate')
- plesty.fss.monitor.line_color(index: int) str
The colour of the index-th line, counting from the shortest wavelength.
- Parameters:
index (int) – Which line.
- Returns:
A palette token; the palette repeats for a sweep with more lines than it has colours, which is better than refusing to draw them.
- Return type:
str
- class plesty.fss.monitor.LineSpectrumView(tracking: plesty.fss.tracking.LineTracking, **kwargs: Any)
Bases:
plesty.lib.monitor.common.SpectrumThe newest spectrum, with a marker on every line the fine structure follows.
Each line keeps its colour and its number —
line 0,line 1, … — fromFineStructureView, so a marker here and a point series there are the same line. A marker sits on the spectrum at the line’s fitted position; a line whose fit failed in this spectrum has none.Every count is drawn as recorded. This is the library’s
Spectrumwith the markers added, so everything it takes — which fields hold the axis and the values, the axis labels, the colour of the curve — it takes here too.Mark the lines tracking follows on the spectrum.
- Parameters:
tracking (plesty.fss.tracking.LineTracking) – The run’s line tracking, shared with the fine-structure view so each spectrum is fitted once.
**kwargs (Any) – Forwarded to
Spectrum.
- title = 'Spectrum'
- tracking
- draw(data: Any) plesty.lib.monitor.Drawing
Draw the newest spectrum, then mark each fitted line on it.
- Parameters:
data (Any) – The run’s data.
- Returns:
The curve, and one marker per line whose fit succeeded.
- Return type:
plesty.lib.monitor.Drawing
- class plesty.fss.monitor.FineStructureView(tracking: plesty.fss.tracking.LineTracking | None = None, *, fine_structure_key: str = 'fine_structure_document', fit_key: str = 'line_fit_document', angle_label: str = 'Rotator angle (deg)', title: str = '', name: str = '', weight: float | None = None, area: str = '')
Bases:
plesty.lib.monitor.PlotEnergy shift of every line against the rotator angle, with its fit and result.
A splitting is an energy, and the wavelengths it separates differ in the fourth decimal: drawn in nanometres it is a flat line, drawn as a shift from each line’s mean position in µeV it is the measurement.
While the sweep runs the shift is measured from the mean so far, which moves as spectra arrive; once the analysis has written its result, its own fits, sines and splittings replace the running estimate. The text under the plot gives each line’s result in the line’s colour.
A class rather than a function because it remembers which analysis document it has already read — loading it on every tick would re-parse the same file twice a second for the rest of the run.
Draw the sweep tracking follows, and the analysis of it when there is one.
- Parameters:
tracking (Optional[plesty.fss.tracking.LineTracking]) – The run’s line tracking, shared with the spectrum view;
Noneshows nothing until the analysis is written.fine_structure_key (str) – Record field naming the saved
fine_structureresult, relative to the run directory.fit_key (str) – Record field naming the saved
fitresult.angle_label (str) – Label of the angle axis, including the unit.
title (str) – What the view is called.
name (str) – Layout key.
weight (Optional[float]) – Relative size.
area (str) – Which side of the window it starts on.
- title = 'Fine structure'
- tracking = None
- fine_structure_key = 'fine_structure_document'
- fit_key = 'line_fit_document'
- angle_label = 'Rotator angle (deg)'
- _channels: dict[str, Any] | None = None
- _loaded_from: tuple[str, str] = ('', '')
- analysis(data: Any) dict[str, Any] | None
What the analysis made of the sweep, or
Nonebefore it has written it.- Parameters:
data (Any) – The run’s data.
- Returns:
The channels of
sweep_channels(), read once per document.- Return type:
Optional[dict[str, Any]]
- draw(data: Any) plesty.lib.monitor.Drawing
Draw the analysis when there is one, else the sweep so far.
- Parameters:
data (Any) – The run’s data.
- Returns:
One point series per line, its fitted sine once analysed, and one line of result text per line.
- Return type:
plesty.lib.monitor.Drawing
- _draw_sweep(data: Any) plesty.lib.monitor.Drawing
Each line’s shift from its mean so far, without fitted sines.
- Parameters:
data (Any)
- Return type:
plesty.lib.monitor.Drawing
- _draw_analysis(channels: dict[str, Any]) plesty.lib.monitor.Drawing
The analysis’s own fits, sines and results.
- Parameters:
channels (dict[str, Any])
- Return type:
plesty.lib.monitor.Drawing
- plesty.fss.monitor.line_drawing(channels: dict[str, Any], index: int, angle_label: str, label: str = '') list[Any]
One analysed line: its measured shifts as points, and its fitted sine.
Shared by
FineStructureViewand the analysis report (plesty.fss.report), so the figure in a report is the view on screen.- Parameters:
channels (dict[str, Any]) – What
sweep_channels()computed.index (int) – Which line.
angle_label (str) – Label of the angle axis, including the unit.
label (str) – Legend label;
line <index>by default.
- Returns:
A
Scatterof the points and aLineof the sine, in the line’s colour.- Return type:
list[Any]
- plesty.fss.monitor.sweep_channels(fine_structure: plesty.fss.data.FineStructureData, fit: Any) dict[str, Any]
Compute what the view draws from the analyzer’s
fine_structureandfitoutputs.- Parameters:
fine_structure (plesty.fss.data.FineStructureData) – The analyzer’s
fine_structureoutput.fit (Any) – The analyzer’s
fitoutput (SpectrumFitData).
- Returns:
angle_deg(points),shift_ueV(lines × points,nanwhere a frame’s fit failed),curve_angle_deg,curve_ueV(lines × curve points) andsummary: the result of each line on its own text line, in line order.- Raises:
ValueError – If the fit carries no rotator angle or the two outputs describe different lines.
- Return type:
dict[str, Any]