plesty.lib.analyzer.spectrum_fit
Spectrum fits: line shapes (Gaussian, Lorentzian, Voigt) on a background.
Fitting is analysis, so it lives with the analyzers rather than on the data type. Two layers:
SpectrumFit— theAnalyzer: aSpectrumDatain; every line fitted in every frame out, asSpectrumFitData(centre, FWHM, height, area and background, each ± σ, shaped(frames, peaks)), plus the fitted curve. It seeds from the average spectrum, tracks each line from frame to frame, and fits overlapping lines together.fit_spectrum()andfit_peak()— the primitives on any 1-Dx/y: several line shapes on a constant or linear background, with bounds and per-point errors, for analyzers that fit something other than a spectrum stack.
Every line shape is height-parameterised, so height is the peak value
above the background and area the integrated intensity, whatever the
shape. Fitting needs SciPy, shipped in the fit extra
(uv add "plesty-lib[fit]").
from plesty.lib.analyzer import SpectrumFit
outputs = SpectrumFit(model="gaussian", background="linear")(spectrum=spectrum)
fit = outputs["fit"]
fit["center"], fit["center_err"], fit["area"] # (frames, peaks)
Attributes
Exceptions
Raised when a fit does not converge. |
|
Warned when fitted lines show signs of a fit that did not follow its line. |
Classes
One line to fit, with its starting values and constraints. |
|
The fitted values of one line, each with its one-sigma error. |
|
Result of |
|
Fit every line in every frame of a spectrum. |
Functions
|
Import SciPy, naming the extra that provides it when it is missing. |
|
Gaussian of peak height amplitude above offset. |
|
Lorentzian of peak height amplitude above offset. |
|
Voigt profile of peak height amplitude above offset (needs SciPy). |
|
FWHM of a Voigt profile (Olivero & Longbothum, accurate to ~0.02 %). |
|
Convert the shape's intrinsic width parameters to the line's FWHM. |
|
Return the integrated area of a height-parameterised line shape. |
|
Return the model's intrinsic width parameters for a target FWHM. |
|
Return |
|
Fit one or more line shapes on a background. |
|
Fit one line on a background — |
|
Return the lower and upper bound of every parameter. |
|
Move starting values strictly inside their bounds. |
|
Return the distance between the half-maximum crossings around index. |
|
Return data-driven starting values for |
|
Return the one-sigma error of |
Module Contents
- plesty.lib.analyzer.spectrum_fit.MODELS: tuple[str, Ellipsis] = ('gaussian', 'lorentzian', 'voigt')
- plesty.lib.analyzer.spectrum_fit.BACKGROUNDS: tuple[str, Ellipsis] = ('constant', 'linear')
- plesty.lib.analyzer.spectrum_fit.AVERAGES: tuple[str, Ellipsis] = ('mean', 'median')
- plesty.lib.analyzer.spectrum_fit._GAUSS_FWHM
- plesty.lib.analyzer.spectrum_fit._WIDTH_PARAMETERS: dict[str, tuple[str, Ellipsis]]
- exception plesty.lib.analyzer.spectrum_fit.PeakFitError
Bases:
RuntimeErrorRaised when a fit does not converge.
Initialize self. See help(type(self)) for accurate signature.
- exception plesty.lib.analyzer.spectrum_fit.FitQualityWarning
Bases:
UserWarningWarned when fitted lines show signs of a fit that did not follow its line.
Initialize self. See help(type(self)) for accurate signature.
- plesty.lib.analyzer.spectrum_fit._AT_BOUND = 0.001
- plesty.lib.analyzer.spectrum_fit._OUTLIER_Z = 5.0
- plesty.lib.analyzer.spectrum_fit.DIAGNOSTICS: tuple[str, Ellipsis] = ('failed', 'no_error', 'center_at_bound', 'width_at_bound', 'jumps', 'outliers')
- plesty.lib.analyzer.spectrum_fit._require_scipy() Any
Import SciPy, naming the extra that provides it when it is missing.
- Return type:
Any
- plesty.lib.analyzer.spectrum_fit.gaussian(x: numpy.typing.ArrayLike, amplitude: float, center: float, sigma: float, offset: float) numpy.ndarray
Gaussian of peak height amplitude above offset.
- Parameters:
x (numpy.typing.ArrayLike) – Positions.
amplitude (float) – Peak height above the offset.
center (float) – Peak position.
sigma (float) – Standard deviation; FWHM is
2·sqrt(2·ln 2)·sigma.offset (float) – Constant background.
- Returns:
The model evaluated at x.
- Return type:
numpy.ndarray
- plesty.lib.analyzer.spectrum_fit.lorentzian(x: numpy.typing.ArrayLike, amplitude: float, center: float, gamma: float, offset: float) numpy.ndarray
Lorentzian of peak height amplitude above offset.
- Parameters:
x (numpy.typing.ArrayLike) – Positions.
amplitude (float) – Peak height above the offset.
center (float) – Peak position.
gamma (float) – Half width at half maximum; FWHM is
2·gamma.offset (float) – Constant background.
- Returns:
The model evaluated at x.
- Return type:
numpy.ndarray
- plesty.lib.analyzer.spectrum_fit.voigt(x: numpy.typing.ArrayLike, amplitude: float, center: float, sigma: float, gamma: float, offset: float) numpy.ndarray
Voigt profile of peak height amplitude above offset (needs SciPy).
- Parameters:
x (numpy.typing.ArrayLike) – Positions.
amplitude (float) – Peak height above the offset.
center (float) – Peak position.
sigma (float) – Gaussian standard deviation.
gamma (float) – Lorentzian half width at half maximum.
offset (float) – Constant background.
- Returns:
The model evaluated at x.
- Return type:
numpy.ndarray
- plesty.lib.analyzer.spectrum_fit.voigt_fwhm(sigma: float, gamma: float) float
FWHM of a Voigt profile (Olivero & Longbothum, accurate to ~0.02 %).
- Parameters:
sigma (float) – Gaussian standard deviation.
gamma (float) – Lorentzian half width at half maximum.
- Returns:
The full width at half maximum.
- Return type:
float
- plesty.lib.analyzer.spectrum_fit._FUNCTIONS: dict[str, Callable[Ellipsis, numpy.ndarray]]
- plesty.lib.analyzer.spectrum_fit._fwhm(model: str, widths: Sequence[float] | numpy.ndarray) float
Convert the shape’s intrinsic width parameters to the line’s FWHM.
widthsare the model-specific broadening parameters:sigmafor a Gaussian,gammafor a Lorentzian, and(sigma, gamma)for a Voigt. The returned FWHM is the physical width at half maximum in the same units as the fitted axis.- Parameters:
model (str)
widths (Sequence[float] | numpy.ndarray)
- Return type:
float
- plesty.lib.analyzer.spectrum_fit._area(model: str, height: float, widths: Sequence[float] | numpy.ndarray) float
Return the integrated area of a height-parameterised line shape.
heightis the peak value above the background, whilewidthsare the model-specific width parameters rather than the final FWHM. For Gaussian and Lorentzian profiles, the area is analytic; for Voigt, it is derived from the central value of the Voigt profile.- Parameters:
model (str)
height (float)
widths (Sequence[float] | numpy.ndarray)
- Return type:
float
- plesty.lib.analyzer.spectrum_fit._widths_from_fwhm(model: str, fwhm: float) list[float]
Return the model’s intrinsic width parameters for a target FWHM.
This is used to seed a fit from a rough width estimate in the physical FWHM units of the data. The conversion differs for each line shape because each model uses a different definition of its broadening parameter.
- Parameters:
model (str)
fwhm (float)
- Return type:
list[float]
- class plesty.lib.analyzer.spectrum_fit.Peak
One line to fit, with its starting values and constraints.
- Variables:
center – Initial line position.
width – Initial FWHM; estimated from the data when
None.center_bounds –
(low, high)for the position; the fitted range whenNone.width_bounds –
(low, high)bounds on the FWHM in the same units asx. If omitted, the width is constrained to stay above roughly one sample spacing, preventing a narrow noise spike from fitting as a line. For a Voigt profile, the bound is applied to each of the two width components separately.nonnegative – Keep the height at or above zero.
- center: float
- width: float | None = None
- center_bounds: tuple[float, float] | None = None
- width_bounds: tuple[float, float] | None = None
- nonnegative: bool = True
- class plesty.lib.analyzer.spectrum_fit.PeakResult
The fitted values of one line, each with its one-sigma error.
- Variables:
params – The raw line-shape parameters (
height,center,sigmaand/orgamma).errors – Their one-sigma errors (
nanwhen not estimable).
- center: float
- center_err: float
- fwhm: float
- fwhm_err: float
- height: float
- height_err: float
- area: float
- area_err: float
- params: dict[str, float]
- errors: dict[str, float]
- class plesty.lib.analyzer.spectrum_fit.SpectrumFitResult
Result of
fit_spectrum().- Variables:
model – The line shape of every peak.
background –
"constant"or"linear".peaks – One
PeakResultper peak, in the order given.background_params –
offset(atx_ref) andslope(0for a constant background).background_errors – Their one-sigma errors.
x_ref – Position the background offset refers to.
r_squared – Coefficient of determination.
values – The optimiser parameter tuple in fixed order: background terms first (
offsetand optionallyslope), then for each peak(height, center, ...)with the width parameters in the model’s native order (sigmafor Gaussian,gammafor Lorentzian,sigma, gammafor Voigt). Examples:(offset, slope, h1, c1, sigma1, h2, c2, sigma2)for two Gaussian peaks on a linear background;(offset, slope, h, c, gamma)for one Lorentzian peak on a linear background;(offset, h, c, sigma, gamma)for one Voigt peak on a constant background. This is the exact order expected by_model_function()and can be reused as a seed for a later fit.covariance – The parameter covariance matrix in the same order as
values.
- model: str
- background: str
- peaks: tuple[PeakResult, Ellipsis]
- background_params: dict[str, float]
- background_errors: dict[str, float]
- x_ref: float
- r_squared: float
- values: tuple[float, Ellipsis]
- covariance: numpy.ndarray
- evaluate(x: numpy.typing.ArrayLike) numpy.ndarray
Evaluate the fitted model — background plus every line — at x.
- Parameters:
x (numpy.typing.ArrayLike)
- Return type:
numpy.ndarray
- to_dict() dict[str, Any]
Return the result as a JSON-serializable dictionary (no covariance).
- Return type:
dict[str, Any]
- plesty.lib.analyzer.spectrum_fit._model_function(model: str, background: str, n_peaks: int, x_ref: float) Callable[Ellipsis, numpy.ndarray]
Return
f(x, *values): background plus n_peaks line shapes.- Parameters:
model (str)
background (str)
n_peaks (int)
x_ref (float)
- Return type:
Callable[Ellipsis, numpy.ndarray]
- plesty.lib.analyzer.spectrum_fit.fit_spectrum(x: numpy.typing.ArrayLike, y: numpy.typing.ArrayLike, peaks: Sequence[Peak], model: str = 'gaussian', background: str = 'linear', *, sigma: numpy.typing.ArrayLike | None = None, seed: SpectrumFitResult | None = None, x_ref: float | None = None) SpectrumFitResult
Fit one or more line shapes on a background.
Without a seed, starting values come from the data: the background from a fit to the points away from the lines, each height from the data at its centre, each width from the half-maximum crossings (or
Peak.width). Starting values are moved inside the bounds.- Parameters:
x (numpy.typing.ArrayLike) – Positions, 1-D.
y (numpy.typing.ArrayLike) – Values at x, same shape.
peaks (Sequence[Peak]) – The lines to fit.
model (str) – Line shape of every peak, one of
MODELS.background (str) – One of
BACKGROUNDS.sigma (numpy.typing.ArrayLike | None) – One-sigma error of each y, for a weighted fit. The covariance is scaled by the reduced chi-square, as a relative weighting.
seed (SpectrumFitResult | None) – A previous result with the same peaks, model and background, whose values start this fit.
x_ref (float | None) – Position the background offset refers to; the mean of the peak centres by default.
- Returns:
The fit result.
- Raises:
ValueError – If an argument is unknown or the data are unusable.
PeakFitError – If the optimiser does not converge.
ImportError – If SciPy (the
fitextra) is not installed.
- Return type:
- plesty.lib.analyzer.spectrum_fit.fit_peak(x: numpy.typing.ArrayLike, y: numpy.typing.ArrayLike, model: str = 'gaussian', *, center: float | None = None, width: float | None = None, background: str = 'linear', sigma: numpy.typing.ArrayLike | None = None, center_bounds: tuple[float, float] | None = None, width_bounds: tuple[float, float] | None = None, nonnegative: bool = True) SpectrumFitResult
Fit one line on a background —
fit_spectrum()with a singlePeak.- Parameters:
x (numpy.typing.ArrayLike) – Positions, 1-D.
y (numpy.typing.ArrayLike) – Values at x.
model (str) – Line shape, one of
MODELS.center (float | None) – Initial line position; the highest point by default.
width (float | None) – Initial FWHM.
background (str) – One of
BACKGROUNDS.sigma (numpy.typing.ArrayLike | None) – One-sigma error of each y.
center_bounds (tuple[float, float] | None) –
(low, high)for the position.width_bounds (tuple[float, float] | None) –
(low, high)for the FWHM.nonnegative (bool) – Keep the height at or above zero.
- Returns:
The fit result;
result.peaks[0]holds the line.- Return type:
- plesty.lib.analyzer.spectrum_fit._bounds(xs: numpy.ndarray, peaks: Sequence[Peak], model: str, background: str) tuple[numpy.ndarray, numpy.ndarray]
Return the lower and upper bound of every parameter.
- Parameters:
xs (numpy.ndarray)
peaks (Sequence[Peak])
model (str)
background (str)
- Return type:
tuple[numpy.ndarray, numpy.ndarray]
- plesty.lib.analyzer.spectrum_fit._inside(values: numpy.ndarray, lower: numpy.ndarray, upper: numpy.ndarray) numpy.ndarray
Move starting values strictly inside their bounds.
- Parameters:
values (numpy.ndarray)
lower (numpy.ndarray)
upper (numpy.ndarray)
- Return type:
numpy.ndarray
- plesty.lib.analyzer.spectrum_fit._estimate_width(xs: numpy.ndarray, ys: numpy.ndarray, index: int, level: float) float | None
Return the distance between the half-maximum crossings around index.
- Parameters:
xs (numpy.ndarray)
ys (numpy.ndarray)
index (int)
level (float)
- Return type:
float | None
- plesty.lib.analyzer.spectrum_fit._initial_guess(xs: numpy.ndarray, ys: numpy.ndarray, peaks: Sequence[Peak], model: str, background: str, x_ref: float) numpy.ndarray
Return data-driven starting values for
fit_spectrum().- Parameters:
xs (numpy.ndarray)
ys (numpy.ndarray)
peaks (Sequence[Peak])
model (str)
background (str)
x_ref (float)
- Return type:
numpy.ndarray
- plesty.lib.analyzer.spectrum_fit._propagate(function: Callable[[numpy.ndarray], float], values: numpy.ndarray, covariance: numpy.ndarray, indices: Sequence[int]) float
Return the one-sigma error of
function(values)from the covariance block.- Parameters:
function (Callable[[numpy.ndarray], float])
values (numpy.ndarray)
covariance (numpy.ndarray)
indices (Sequence[int])
- Return type:
float
- class plesty.lib.analyzer.spectrum_fit.SpectrumFit(peaks: str | Sequence[float] = 'auto', model: str = 'gaussian', background: str = 'linear', window: float | None = None, frames: str | int | Sequence[int] = 'all', order: Sequence[int] | None = None, track: bool = True, overlap: float = 2.0, prominence: float | None = None, distance: int = 1, tolerance: float | None = None, width: float | None = None, width_bounds: tuple[float, float] | None = None, center_tolerance: float | None = None, nonnegative: bool = True, average: str = 'mean')
Bases:
plesty.lib.analyzer.base_analyzer.AnalyzerFit every line in every frame of a spectrum.
Lines —
peaks="auto"finds them in the average of the selected frames (prominence,distance); a list of positions uses those, relocated to the nearest local maximum withintoleranceif set.average="median"takes the per-pixel median of the frames instead of their mean: a cosmic ray hits one frame and drops out of the median, where in the mean of a few dozen frames it can still stand out as a line.Groups — each line’s FWHM is estimated on the average; neighbours closer than
overlap× the larger FWHM are fitted together, every other line alone.overlap=0fits every line alone.Range — a group is fitted over
windowbeyond its outer lines on each side, re-centred on each frame’s starting centres so the range follows a drifting line; without a window, up to halfway to the neighbouring groups.Frames — each group is fitted to the average first; that result seeds the first frame in
order, and withtrackeach frame seeds the next.center_tolerancekeeps each line within that distance of its seed. A frame whose fit fails isnan.Quality — nothing above is changed by it: per line, frames that failed, lacked a centre error or sat at a centre or width bound, jumps wider than the line between frames, and outlying centres are counted into
fit.metadata["diagnostics"], and aFitQualityWarningnames every line with a count. Withtrack, each frame’s range is centred on the previous frame’s fitted position, so when a line is weak in one frame its fit can move onto a brighter neighbouring spectral line inside the range and stay on it; these counts are how that shows.
Outputs
fit(SpectrumFitData, one row per frame inframes) andcurve— the fitted model on the spectrum’s axis,nanoutside the fitted ranges.Validate and store the fit parameters.
- Parameters:
peaks (str | Sequence[float]) –
"auto", or line positions in the wavelength unit.model (str) – Line shape, one of
MODELS.background (str) – One of
BACKGROUNDS.window (float | None) – Fitted range beyond a group’s outer lines, each side.
frames (str | int | Sequence[int]) –
"all", one frame index, or a list of them.order (Sequence[int] | None) – The frames in the order to fit them.
track (bool) – Seed each frame with the previous frame’s fit.
overlap (float) – Grouping factor on the FWHM;
0never groups.prominence (float | None) – Minimum prominence for
peaks="auto".distance (int) – Minimum separation in pixels for
peaks="auto".tolerance (float | None) – Relocate given positions to a local maximum this close.
width (float | None) – Initial FWHM of every line.
width_bounds (tuple[float, float] | None) –
(low, high)FWHM bounds of every line.center_tolerance (float | None) – Maximum distance of a line from its seed position.
nonnegative (bool) – Keep heights at or above zero.
average (str) –
"mean"or"median"of the frames: the spectrum lines are found in, their widths estimated on, and the first fit made to.
- Raises:
ValueError – If a parameter is out of range.
- analyze(spectrum: plesty.lib.data.spectrum.SpectrumData) dict[str, Any]
Fit every line in every selected frame.
- Parameters:
spectrum (plesty.lib.data.spectrum.SpectrumData) – The spectrum to fit.
- Returns:
fitandcurve, see the class description.- Raises:
ValueError – If a frame is out of range,
orderdoes not matchframes, or no line is found.PeakFitError – If a group cannot be fitted even to the average.
- Return type:
dict[str, Any]
- static _frames(selection: str | int | list[int], total: int) list[int]
Return the selected frame indices, normalised and checked.
- Parameters:
selection (str | int | list[int])
total (int)
- Return type:
list[int]
- _order(order: list[int], frames: list[int], total: int) list[int]
Return the fitting order, which must be a permutation of frames.
- Parameters:
order (list[int])
frames (list[int])
total (int)
- Return type:
list[int]
- _centers(spectrum: plesty.lib.data.spectrum.SpectrumData, average: numpy.ndarray) numpy.ndarray
Return the sorted line positions to fit.
- Parameters:
spectrum (plesty.lib.data.spectrum.SpectrumData)
average (numpy.ndarray)
- Return type:
numpy.ndarray
- _fwhms(axis: numpy.ndarray, average: numpy.ndarray, centers: numpy.ndarray) numpy.ndarray
Estimate each line’s FWHM with a single-line fit to the average.
- Parameters:
axis (numpy.ndarray)
average (numpy.ndarray)
centers (numpy.ndarray)
- Return type:
numpy.ndarray
- _groups(centers: numpy.ndarray, fwhms: numpy.ndarray) list[list[int]]
Group neighbouring lines closer than
overlap× the larger FWHM.- Parameters:
centers (numpy.ndarray)
fwhms (numpy.ndarray)
- Return type:
list[list[int]]
- _range(axis: numpy.ndarray, centers: numpy.ndarray, fwhms: numpy.ndarray, groups: list[list[int]], g: int) tuple[float, float]
Return the fitted range of group g.
- Parameters:
axis (numpy.ndarray)
centers (numpy.ndarray)
fwhms (numpy.ndarray)
groups (list[list[int]])
g (int)
- Return type:
tuple[float, float]
- _center_bounds(center: float, low: float, high: float) tuple[float, float]
Return the position bounds of a line: its tolerance, within the range.
- Parameters:
center (float)
low (float)
high (float)
- Return type:
tuple[float, float]
- static _check_bounds(diagnostics: list[dict[str, int]], group: list[int], result: SpectrumFitResult, bounded: list[Peak], x: numpy.ndarray) None
Count, for one frame, lines without a centre error or pinned at a bound.
- Parameters:
diagnostics (list[dict[str, int]])
group (list[int])
result (SpectrumFitResult)
bounded (list[Peak])
x (numpy.ndarray)
- Return type:
None
- static _check_tracks(diagnostics: list[dict[str, int]], center: numpy.ndarray, frames: list[int], order: list[int], fwhms: numpy.ndarray) None
Count, per line, jumps wider than the line between frames and outlying centres.
- Parameters:
diagnostics (list[dict[str, int]])
center (numpy.ndarray)
frames (list[int])
order (list[int])
fwhms (numpy.ndarray)
- Return type:
None
- static _warn(diagnostics: list[dict[str, int]], centers: numpy.ndarray, unit: str | None) None
Warn once, naming every line with a count, without changing any result.
- Parameters:
diagnostics (list[dict[str, int]])
centers (numpy.ndarray)
unit (str | None)
- Return type:
None
- static _store(table: dict[str, numpy.ndarray], row: int, group: list[int], result: SpectrumFitResult) None
Write one group’s fit of one frame into the result table.
- Parameters:
table (dict[str, numpy.ndarray])
row (int)
group (list[int])
result (SpectrumFitResult)
- Return type:
None