Data types¶
spectro-kernel defines one canonical representation for each kind of object. Every algorithm consumes and produces these types - never ad-hoc tuples or per-project variants. That single agreement is what makes results comparable across applications.
Spectrum1D - the spectrum¶
The heart of the library: a 1D spectrum is flux sampled over a wavelength axis.
from spectro_kernel import Spectrum1D
spec = Spectrum1D(
wavelength=wave, # 1D array, conventionally Ångström
flux=flux, # 1D array, same length
flux_unit="ADU",
uncertainty=None, # optional 1-sigma error array
mask=None, # optional boolean array (True = ignore)
meta={"object": "Vega"}, # free-form metadata
header=None, # raw FITS header, if loaded from a file
)
| Field | Meaning |
|---|---|
wavelength |
The wavelength axis (Å by convention). |
flux |
Flux values, one per wavelength sample. |
flux_unit |
Label for the flux unit. |
uncertainty |
Optional per-sample 1-σ uncertainty. |
mask |
Optional boolean array; True marks a sample to ignore. |
meta |
Free-form metadata (object name, instrument, dates…). |
header |
The original FITS header, when read from a file. |
It is a small, well-behaved object:
len(spec) # number of samples
spec.npix # same thing, explicit
spec.wavelength_min, spec.wavelength_max
spec.copy() # a deep, independent copy
spec.select_range(6500, 6620) # a cropped sub-spectrum
spec.content_hash() # stable SHA-256 of the numeric content
spec.preview() # small JSON-safe summary (used by MCP)
Why one type matters
When read_fits, normalize_polynomial and fit_gaussian_line all speak
Spectrum1D, they compose without glue code - and a spectrum measured in one
application means exactly the same thing in another.
Related types live alongside it: ImageFrame (a 2D detector frame, the entry point for
CCD reduction), LineFitResult, Periodogram, LightCurve, CatalogResult,
SpectralLine.
WorkContext - the analysis state¶
A WorkContext is the mutable bag of results carried through an analysis. It
generalises the idea of "the data I am working on": it has typed slots for the common
objects plus an open extras dict.
flowchart TD
subgraph WC["WorkContext"]
S["spectrum : Spectrum1D"]
SS["spectra : list<Spectrum1D>"]
IMG["image / images"]
LF["line_fits : dict"]
PG["periodograms : dict"]
LC["light_curves : dict"]
CL["catalog_lookups : dict"]
FIG["figures : dict"]
EXP["exports : dict"]
MET["metrics : dict<str,float>"]
EXT["extras : dict (anything)"]
HIS["history : list<ProcessingStep>"]
end
An algorithm reads its inputs from the context and writes its outputs back:
from spectro_kernel import WorkContext, run_algorithm
ctx = WorkContext(spectrum=spec)
run_algorithm("snr_der", ctx) # reads ctx.spectrum, writes ctx.metrics
run_algorithm("fit_gaussian_line", ctx, {"line_center_angstrom": 6562.8})
ctx.metrics # {"snr_der": 142.3, ...}
ctx.line_fits # {"6562.8": LineFitResult(...)}
ctx.history # the full audit trail
ctx.summary() # a compact, JSON-safe description of everything held
Because one context carries everything, an algorithm can use the output of an earlier one with no plumbing - that is exactly how pipelines work.
ProcessingStep - the audit trail¶
Every algorithm execution appends a ProcessingStep to ctx.history:
ProcessingStep(
algorithm="snr_der", version="1.0.0", params={...},
timestamp="2026-05-22T14:23:15+00:00",
input_hash="sha256:…", output_hash="sha256:…",
duration_ms=1.8, success=True, message="DER_SNR = 142.3",
)
Together with per-algorithm versions, this is what makes a spectro-kernel result traceable and replayable - see Pipelines → Reproducibility.
Full field-by-field API
See the API reference for the complete, generated documentation of every type.