plesty.lib.data.spectrum
Spectra: the flagship ExperimentData type.
A SpectrumData is a wavelength axis and the intensity measured on
it — one spectrum, or a stack of frames taken on the same axis. It reads
LightField .spe files and LightField’s CSV export, writes and reads every
native format, and carries the processing a PL analysis starts with. Fitting
is analysis and lives in plesty.lib.analyzer.SpectrumFit.
Every processing method returns a new spectrum and appends what it did
to metadata["processing"], so a saved result says how it was derived.
from plesty.lib.data import SpectrumData
spectrum = SpectrumData.load("qd1.spe")
prepared = spectrum.crop(770, 780).subtract_background("median")
prepared.find_peaks(prominence=100)
The raw .spe content — every region, the calibration, the XML footer —
is available through SpeFile.read() when a spectrum is not the whole story.
An SPE 3.0 file is a 4100-byte binary header, the frame data, and an XML footer. The footer is authoritative: it declares the pixel format, the frame and region layout, and the wavelength calibration, and the legacy binary header fields may be zero. Only the footer offset (bytes 678–685) and the file version (bytes 1992–1995) are read from the header. Older WinSpec (SPE 2.x) files carry no XML footer and are refused rather than guessed at.
Attributes
Classes
The content of one LightField SPE 3.0 file; |
|
A wavelength axis and the intensity measured on it. |
|
Line-shape fit results of a spectrum: one row per fitted frame, one column per line. |
Functions
|
Coerce value to a |
|
Return the unit a coordinate's name ends in, e.g. |
|
Validate per-frame coordinates and give plain arrays their name and unit. |
|
Return the |
|
Return whether line opens a frame block ( |
|
Parse |
|
Return whether the flat run starting at start is followed by a drop. |
|
Return the topographic prominence of the peak at index. |
Module Contents
- plesty.lib.data.spectrum.HC_EV_NM = 1239.841984
- plesty.lib.data.spectrum.COORDINATE_PREFIX = 'coordinate_'
- plesty.lib.data.spectrum.COORDINATE_UNITS: dict[str, str]
- class plesty.lib.data.spectrum.SpeFile
The content of one LightField SPE 3.0 file;
read()builds it.- Variables:
version – File format version from the header (
3.0).regions – One array per region of interest, each shaped
(frames, height, width).wavelength – Wavelength in nm of each pixel column of the first region, or
Nonewhen the file has no calibration.metadata – Acquisition context read from the XML footer — only the keys found are present (
exposure_time_ms,center_wavelength_nm,grating,sensor_temperature_c,created,software,camera,spectrometer).xml – The raw XML footer, for anything
metadataomits.
- HEADER_SIZE: ClassVar[int] = 4100
Size of the binary header preceding the frame data.
- XML_OFFSET_POS: ClassVar[int] = 678
Header position of the XML footer offset (uint64).
- VERSION_POS: ClassVar[int] = 1992
Header position of the file version (float32).
- PIXEL_FORMATS: ClassVar[dict[str, str]]
Footer pixel formats this reader decodes, mapped to NumPy dtypes.
- version: float
- regions: tuple[numpy.ndarray, Ellipsis]
- wavelength: numpy.ndarray | None
- metadata: dict[str, Any]
- xml: str = ''
- classmethod read(path: str | pathlib.Path) Self
Read a LightField SPE 3.0 file.
- Parameters:
path (str | pathlib.Path) – The
.spefile.- Returns:
The file’s regions, wavelength calibration and metadata.
- Raises:
ValueError – If the file is not SPE 3.0, is truncated, or uses a pixel format this reader does not know.
- Return type:
Self
- classmethod _wavelength(root: xml.etree.ElementTree.Element, width: int) numpy.ndarray | None
Return the per-pixel wavelength of a region width pixels wide.
The calibration covers the sensor; a region cropped or binned on the sensor is mapped through
SensorMapping(x offset, width, x binning).- Parameters:
root (xml.etree.ElementTree.Element)
width (int)
- Return type:
numpy.ndarray | None
- classmethod _metadata(root: xml.etree.ElementTree.Element) dict[str, Any]
Collect the acquisition settings a spectrum report needs from the footer.
- Parameters:
root (xml.etree.ElementTree.Element)
- Return type:
dict[str, Any]
- static _local(element: xml.etree.ElementTree.Element) str
Return an element’s tag without its XML namespace.
- Parameters:
element (xml.etree.ElementTree.Element)
- Return type:
str
- classmethod _find(root: xml.etree.ElementTree.Element, *names: str) xml.etree.ElementTree.Element | None
Find the first element reached by descending through names, at any depth.
- Parameters:
root (xml.etree.ElementTree.Element)
names (str)
- Return type:
xml.etree.ElementTree.Element | None
- classmethod _text(root: xml.etree.ElementTree.Element, *names: str) str | None
Return the stripped text of the element at names, or
None.- Parameters:
root (xml.etree.ElementTree.Element)
names (str)
- Return type:
str | None
- classmethod _float(root: xml.etree.ElementTree.Element, *names: str) float | None
Return the element at names parsed as a float, or
None.- Parameters:
root (xml.etree.ElementTree.Element)
names (str)
- Return type:
float | None
- plesty.lib.data.spectrum._WAVELENGTH_DESCRIPTION = 'Wavelength of each detector pixel.'
- plesty.lib.data.spectrum._INTENSITY_DESCRIPTION = 'Detected intensity per pixel; one row per frame when stacked.'
- plesty.lib.data.spectrum._as_array(value: numpy.typing.ArrayLike, name: str, unit: str, description: str) plesty.lib.data.array.PlestyArray
Coerce value to a
PlestyArray, filling metadata it lacks.- Parameters:
value (numpy.typing.ArrayLike)
name (str)
unit (str)
description (str)
- Return type:
- class plesty.lib.data.spectrum.SpectrumData(wavelength: numpy.typing.ArrayLike, intensity: numpy.typing.ArrayLike, metadata: dict[str, Any] | None = None, provenance: dict[str, Any] | None = None, coordinates: Mapping[str, numpy.typing.ArrayLike] | None = None)
Bases:
plesty.lib.data.experiment_data.ExperimentDataA wavelength axis and the intensity measured on it.
- Variables:
wavelength – 1-D axis, one value per pixel (default unit
nm).intensity –
(pixels,)for one spectrum or(frames, pixels)for a stack (default unitcounts).coordinates – Per-frame values of the sweep the frames were taken over, by name — e.g.
hwp_degorpower_w— each 1-D with one value per frame. Empty for a spectrum that is no sweep.
- Parameters:
wavelength (numpy.typing.ArrayLike)
intensity (numpy.typing.ArrayLike)
metadata (dict[str, Any] | None)
provenance (dict[str, Any] | None)
coordinates (Mapping[str, numpy.typing.ArrayLike] | None)
Validate and store the axis, the intensity and the frame coordinates.
- Parameters:
wavelength (numpy.typing.ArrayLike) – 1-D axis; a plain array gets unit
nm.intensity (numpy.typing.ArrayLike) – 1-D spectrum or 2-D
(frames, pixels)stack; a plain array gets unitcounts.metadata (dict[str, Any] | None) – Acquisition context.
provenance (dict[str, Any] | None) – Origin of the data.
coordinates (Mapping[str, numpy.typing.ArrayLike] | None) – Per-frame sweep values by name; a plain array gets the unit its name ends in (
_deg,_w,_nm, …).
- Raises:
ValueError – If the shapes do not describe a spectrum on the axis, or a coordinate does not have one value per frame.
- kind = 'spectrum'
Registry key and schema dtype token, e.g.
"spectrum".
- schema_version = 1
Version of the array layout this class writes and reads.
- wavelength: plesty.lib.data.array.PlestyArray
- intensity: plesty.lib.data.array.PlestyArray
- coordinates: dict[str, plesty.lib.data.array.PlestyArray]
- to_arrays() dict[str, plesty.lib.data.array.PlestyArray]
Return
wavelength,intensityand eachcoordinate_<name>.- Return type:
dict[str, plesty.lib.data.array.PlestyArray]
- classmethod from_arrays(arrays: dict[str, plesty.lib.data.array.PlestyArray], metadata: dict[str, Any], provenance: dict[str, Any]) Self
Rebuild a spectrum from
wavelength,intensityand its coordinates.- Parameters:
arrays (dict[str, plesty.lib.data.array.PlestyArray]) – Must hold
wavelengthandintensity; everycoordinate_<name>becomes a coordinate.metadata (dict[str, Any]) – The saved metadata.
provenance (dict[str, Any]) – The saved provenance.
- Return type:
Self
- classmethod example() Self
Return a 101-pixel spectrum with one Lorentzian line at 775 nm.
- Return type:
Self
- classmethod from_text(lines: list[str], delimiter: str | None) Self
Build a spectrum from a text export, in blocks or as one table.
A file in which a
Frame …line opens each frame — followed bywavelength intensityrows, whitespace-separated, where a comma may be the decimal separator — is read block by block. Anything else is a table, seefrom_table().- Parameters:
lines (list[str]) – The file’s non-empty lines,
#comments removed.delimiter (str | None) –
","for.csv;Nonefor.txt.
- Raises:
ValueError – If the blocks hold no data or frames of different lengths.
- Return type:
Self
- classmethod from_table(columns: list[numpy.ndarray], names: list[str] | None) Self
Build a spectrum from a plain table.
Two layouts are understood:
LightField’s CSV export — columns
Frame,Wavelength,Intensity(andRowfor multi-row regions, summed per pixel); one line per pixel.Wide — the first column is the wavelength, every further column one frame of intensity.
- Parameters:
columns (list[numpy.ndarray]) – The table’s columns.
names (list[str] | None) – The header row, when the file had one.
- Raises:
ValueError – If the table has fewer than two columns.
- Return type:
Self
- classmethod _from_lightfield_table(columns: list[numpy.ndarray], lowered: list[str]) Self
Rebuild frames from LightField’s one-line-per-pixel CSV export.
- Parameters:
columns (list[numpy.ndarray])
lowered (list[str])
- Return type:
Self
- classmethod from_spe(path: str | pathlib.Path, region: int = 0, wavelength: numpy.typing.ArrayLike | None = None) Self
Read a LightField SPE 3.0 file.
Rows of a multi-row region are summed per pixel (full vertical binning); a single frame becomes a 1-D spectrum, several a stack.
- Parameters:
path (str | pathlib.Path) – The
.spefile.region (int) – Index of the region of interest to read.
wavelength (numpy.typing.ArrayLike | None) – Axis to use when the file has no calibration, or to override it.
- Returns:
The spectrum, with the file’s acquisition settings in
metadataand its name undermetadata["source"].- Raises:
ValueError – If the file has no such region, or no calibration and none was given.
- Return type:
Self
- classmethod from_run(run: Any, file_key: str = 'data_file', coordinates: Sequence[str] = (), where: Mapping[str, Any] | None = None, wavelength: numpy.typing.ArrayLike | None = None) Self
Stack the spectra an experiment run recorded, in record order.
Each record holding file_key names the raw file a device wrote for that step; the path is translated to this machine through the run’s data paths (a relative path is taken from the run directory). A
.spefile is read withfrom_spe(); a.npyframe, which carries no axis, needs wavelength, and its rows are summed per pixel; any other file goes throughload(). A record whose value is itself aSpectrumDatais used as it is.- Parameters:
run (Any) – A
Runor a run directory.file_key (str) – Record field naming the raw file.
coordinates (Sequence[str]) – Record fields to keep per frame, e.g.
("hwp_deg", "power_w").where (Mapping[str, Any] | None) – Only records whose fields equal these values, e.g.
{"qd": "QD-004"}.wavelength (numpy.typing.ArrayLike | None) – Axis for files without a calibration.
- Returns:
One frame per recorded frame, with the requested coordinates;
metadatanames the run andprovenancethe run and experiment.- Raises:
ValueError – If no record matches, a record lacks a coordinate, or the files do not share one wavelength axis.
- Return type:
Self
- classmethod _read_raw(reader: Any, host_path: str, wavelength: numpy.typing.ArrayLike | None) SpectrumData
Read one raw device file named by a record.
- Parameters:
reader (Any)
host_path (str)
wavelength (numpy.typing.ArrayLike | None)
- Return type:
- property is_stack: bool
Whether the intensity holds several frames.
- Return type:
bool
- property n_frames: int
Number of frames (
1for a single spectrum).- Return type:
int
- property n_pixels: int
Number of pixels on the wavelength axis.
- Return type:
int
- frame(index: int) Self
Return one frame as a single spectrum.
- Parameters:
index (int) – Frame index; negative indices count from the end.
- Raises:
IndexError – If there is no such frame.
- Return type:
Self
- combine(method: Literal['mean', 'sum'] = 'mean') Self
Collapse a stack into one spectrum; the frame coordinates are dropped.
- Parameters:
method (Literal['mean', 'sum']) –
"mean"or"sum"over the frames.- Raises:
ValueError – If method is unknown.
- Return type:
Self
- crop(start: float, stop: float) Self
Keep the pixels whose wavelength lies in
[start, stop].- Parameters:
start (float) – Lower bound, in the wavelength’s unit.
stop (float) – Upper bound, in the wavelength’s unit.
- Raises:
ValueError – If no pixel lies in the range.
- Return type:
Self
- subtract_background(background: float | Literal['min', 'median'] | numpy.typing.ArrayLike = 'median') Self
Subtract a background from every frame.
- Parameters:
background (float | Literal['min', 'median'] | numpy.typing.ArrayLike) – A constant;
"min"or"median"of each frame; or an array broadcastable to the intensity (e.g. a dark frame).- Raises:
ValueError – If background is an unknown keyword.
- Return type:
Self
- normalize(method: Literal['max', 'area'] = 'max') Self
Scale every frame to a peak of 1 or a unit area; the unit becomes
a.u..- Parameters:
method (Literal['max', 'area']) –
"max"or"area"(trapezoidal, over the axis).- Raises:
ValueError – If method is unknown or a frame’s norm is zero.
- Return type:
Self
- energy() plesty.lib.data.array.PlestyArray
Return the photon energy of each pixel, in eV.
- Raises:
ValueError – If the wavelength unit is not a length.
- Return type:
- find_peaks(frame: int = 0, height: float | None = None, prominence: float | None = None, distance: int = 1) numpy.ndarray
Find local maxima in one frame (NumPy only).
A plateau counts once, at its first pixel. prominence is the height above the higher of the two lowest points separating the peak from taller neighbours (or from the ends of the axis).
- Parameters:
frame (int) – Frame to search.
height (float | None) – Minimum value of a peak.
prominence (float | None) – Minimum prominence of a peak.
distance (int) – Minimum separation in pixels; the taller peak wins.
- Returns:
Pixel indices of the peaks, in ascending order.
- Return type:
numpy.ndarray
- peak_prominences(indices: numpy.typing.ArrayLike, frame: int = 0) numpy.ndarray
Return the prominence of each peak at indices, as
find_peaks()defines it.- Parameters:
indices (numpy.typing.ArrayLike) – Pixel indices of peaks, e.g. from
find_peaks().frame (int) – Frame the peaks are in.
- Returns:
One prominence per index, in the intensity’s unit.
- Raises:
IndexError – If an index is outside the axis.
- Return type:
numpy.ndarray
- match_peaks(reference: numpy.typing.ArrayLike, tolerance: float, frame: int = 0) numpy.ndarray
Relocate known line positions to the strongest local maximum near each.
For each reference position, the local maxima within
±toleranceare searched and the strongest is taken; without a local maximum in range, the highest pixel in range is.- Parameters:
reference (numpy.typing.ArrayLike) – Line positions, in the wavelength’s unit — e.g. lines identified in another measurement of the same emitter.
tolerance (float) – Half-width of the search range around each position.
frame (int) – Frame to search.
- Returns:
One pixel index per reference position, in the order given.
- Raises:
ValueError – If tolerance is not positive or a range holds no pixel.
- Return type:
numpy.ndarray
- _derive(wavelength: numpy.typing.ArrayLike, intensity: numpy.typing.ArrayLike, step: dict[str, Any], coordinates: Mapping[str, numpy.typing.ArrayLike] | None = None) Self
Return a new spectrum carrying this one’s context plus step.
The frame coordinates are kept unless coordinates replaces them.
- Parameters:
wavelength (numpy.typing.ArrayLike)
intensity (numpy.typing.ArrayLike)
step (dict[str, Any])
coordinates (Mapping[str, numpy.typing.ArrayLike] | None)
- Return type:
Self
- class plesty.lib.data.spectrum.SpectrumFitData(values: Mapping[str, numpy.typing.ArrayLike], wavelength_unit: str | None = 'nm', intensity_unit: str | None = 'counts', metadata: dict[str, Any] | None = None, provenance: dict[str, Any] | None = None, coordinates: Mapping[str, numpy.typing.ArrayLike] | None = None)
Bases:
plesty.lib.data.experiment_data.ExperimentDataLine-shape fit results of a spectrum: one row per fitted frame, one column per line.
Produced by
plesty.lib.analyzer.SpectrumFit. Every quantity is an array of shape(frames, peaks), withnanwhere a frame’s fit failed;framenames the spectrum frame each row came from, andx_ref(one per peak) the position the linear background’s offset refers to.centerline position (wavelength unit)
fwhmfull width at half maximum (wavelength unit)
heightpeak height above the background (intensity unit)
areaintegrated intensity (intensity × wavelength unit)
background_offsetbackground at
x_ref(intensity unit)background_slopebackground slope (intensity / wavelength unit)
r_squaredcoefficient of determination of the peak’s group
Each quantity but
r_squaredhas a one-sigma<name>_errarray.metadatarecords themodel, thebackgroundmode and thegroupsof peaks fitted together.coordinatescarries the fitted frames’ sweep values (hwp_deg,power_w, …) from the spectrum, one per row — what a sweep analysis plots the quantities against.Validate the arrays and attach their units.
- Parameters:
values (Mapping[str, numpy.typing.ArrayLike]) – Every name in
names, as arrays.wavelength_unit (str | None) – Unit of the spectrum’s axis.
intensity_unit (str | None) – Unit of the spectrum’s intensity.
metadata (dict[str, Any] | None) – Fit context (
model,background,groups).provenance (dict[str, Any] | None) – Origin of the data.
coordinates (Mapping[str, numpy.typing.ArrayLike] | None) – Sweep values of the fitted frames, one per row.
- Raises:
ValueError – If a name is missing or the shapes disagree.
- kind = 'spectrum_fit'
Registry key and schema dtype token, e.g.
"spectrum".
- schema_version = 1
Version of the array layout this class writes and reads.
- QUANTITIES: ClassVar[tuple[str, Ellipsis]] = ('center', 'fwhm', 'height', 'area', 'background_offset', 'background_slope')
- values: dict[str, plesty.lib.data.array.PlestyArray]
the quantities, their errors,
r_squared,frame,x_ref.- Type:
Every array by name
- coordinates: dict[str, plesty.lib.data.array.PlestyArray]
Sweep values of the fitted frames by name, one per row.
- classmethod names() tuple[str, Ellipsis]
Return every array name, in storage order.
- Return type:
tuple[str, Ellipsis]
- static _units(wavelength: str | None, intensity: str | None) dict[str, str | None]
Return the unit of each array from the spectrum’s units.
- Parameters:
wavelength (str | None)
intensity (str | None)
- Return type:
dict[str, str | None]
- __getitem__(name: str) plesty.lib.data.array.PlestyArray
Return the array called name, e.g.
fit["center"].- Parameters:
name (str)
- Return type:
- property n_frames: int
Number of fitted frames.
- Return type:
int
- property n_peaks: int
Number of fitted lines.
- Return type:
int
- peak(index: int) dict[str, plesty.lib.data.array.PlestyArray]
Return every per-frame quantity of one line, as 1-D arrays over frames.
- Parameters:
index (int) – Peak index.
- Raises:
IndexError – If there is no such peak.
- Return type:
dict[str, plesty.lib.data.array.PlestyArray]
- to_arrays() dict[str, plesty.lib.data.array.PlestyArray]
Return every array by name, coordinates as
coordinate_<name>.- Return type:
dict[str, plesty.lib.data.array.PlestyArray]
- classmethod from_arrays(arrays: dict[str, plesty.lib.data.array.PlestyArray], metadata: dict[str, Any], provenance: dict[str, Any]) Self
Rebuild fit results from
to_arrays(); units travel with the arrays.- Parameters:
arrays (dict[str, plesty.lib.data.array.PlestyArray])
metadata (dict[str, Any])
provenance (dict[str, Any])
- Return type:
Self
- classmethod example() Self
Return one Gaussian line at 775 nm fitted in two frames.
- Return type:
Self
- plesty.lib.data.spectrum._coordinate_unit(name: str) str | None
Return the unit a coordinate’s name ends in, e.g.
degforhwp_deg.- Parameters:
name (str)
- Return type:
str | None
- plesty.lib.data.spectrum._frame_coordinates(coordinates: Mapping[str, numpy.typing.ArrayLike] | None, n_frames: int) dict[str, plesty.lib.data.array.PlestyArray]
Validate per-frame coordinates and give plain arrays their name and unit.
- Parameters:
coordinates (Mapping[str, numpy.typing.ArrayLike] | None)
n_frames (int)
- Return type:
dict[str, plesty.lib.data.array.PlestyArray]
- plesty.lib.data.spectrum._split_coordinates(arrays: Mapping[str, plesty.lib.data.array.PlestyArray]) dict[str, plesty.lib.data.array.PlestyArray]
Return the
coordinate_<name>arrays of a saved spectrum, keyed by name.- Parameters:
arrays (Mapping[str, plesty.lib.data.array.PlestyArray])
- Return type:
dict[str, plesty.lib.data.array.PlestyArray]
- plesty.lib.data.spectrum._is_frame_block_header(line: str) bool
Return whether line opens a frame block (
Frame 3), not a column header.- Parameters:
line (str)
- Return type:
bool
- plesty.lib.data.spectrum._parse_block_row(line: str) tuple[float, float] | None
Parse
wavelength intensityfrom a block row, commas read as decimals.- Parameters:
line (str)
- Return type:
tuple[float, float] | None
- plesty.lib.data.spectrum._plateau_falls(y: numpy.ndarray, start: int) bool
Return whether the flat run starting at start is followed by a drop.
- Parameters:
y (numpy.ndarray)
start (int)
- Return type:
bool
- plesty.lib.data.spectrum._prominence(y: numpy.ndarray, index: int) float
Return the topographic prominence of the peak at index.
- Parameters:
y (numpy.ndarray)
index (int)
- Return type:
float