Resample a spectrum onto a new grid
Your spectrum lives on one axis grid and you need it on another: to match a second instrument’s wavenumber axis, or to align replicates before you compare them.
sample.transform covers your own resampling function; the reviewed SciPy-backed resampling operations in this guide are committed through sample.core.transform with explicit field names.
This guide assumes: you have finished the tutorial path, including Transform and plot a spectrum, and you are comfortable committing checkpoints and reading lineage.
Resampling is interpolation: you keep the measured points and ask for estimated values on a
new set of axis positions. The base install of MTRL supplies resample_linear. The
interp extra adds two SciPy-backed operations beside it: resample_pchip, which is
shape-preserving and avoids overshoot near sharp peaks, and resample_cubic, a smooth
not-a-knot spline. SciPy loads only when one of them runs, so the extra costs nothing
until you use it.
Install the extra into your environment:
uv pip install "vector-mtrl[interp]"Required install: vector-mtrl[interp]
import numpy as np
from mtrl import InstrumentRun, MaterialData, Mtrl, Unit
axis = np.linspace(2000.0, 3000.0, 101)content = np.empty( axis.size, dtype=[("wavenumber", "<f8"), ("absorbance", "<f8")],)content["wavenumber"] = axiscontent["absorbance"] = np.exp(-((axis - 2500.0) / 35.0) ** 2)
application = Mtrl(sample_id="polymer-film-01")run = InstrumentRun(run_name="ftir-replicate-01")checkpoint = MaterialData( content=content, type="raw", checkpoint_name="spectrum", units=Unit.from_raw_map({"wavenumber": "cm^-1", "absorbance": "a.u."}),)run.add_checkpoint(checkpoint)application.add(run)
targets = np.linspace(2200.0, 2800.0, 21).tolist()resampled = application.transform( run.run_id, checkpoint.checkpoint_id, "resample_pchip", parameters={"x_field": "wavenumber", "y_field": "absorbance", "x_targets": targets},)print(f"operation: {resampled.lineage.provenance.qualified_identifier}")print(f"points: {resampled.content.size}; max absorbance: {resampled.content['absorbance'].max()}")operation: mtrl.resample.pchippoints: 21; max absorbance: 1.0The first line prints operation: mtrl.resample.pchip: the qualified name recorded in
the new checkpoint’s lineage. The second prints points: 21; max absorbance: 1.0: the
resampled spectrum has your 21 target points, and the peak at 2500 cm^-1 survives at full
height because the target grid lands on it exactly.
What just happened?
Section titled “What just happened?”The call application.transform(..., "resample_pchip", parameters={"x_field": "wavenumber", "y_field": "absorbance", "x_targets": targets})
looked up the operation in the application’s registry, loaded SciPy for that one call, and
committed the interpolated spectrum as a new checkpoint in the same run. The lineage
records the qualified name mtrl.resample.pchip and the effective parameters, including
the target axis, so the recipe is complete. Your raw spectrum is unchanged.
Two facts about the operation matter. First, every target must lie inside the source axis range: the resample operations never extrapolate, and a target outside the range fails rather than inventing data. Second, interpolated values are not measurements. The new checkpoint is an estimate derived from your raw spectrum, and its lineage says so.
Choose the kernel to match your purpose. resample_pchip preserves the shape of the data
and does not overshoot, which suits peaks and edges. resample_cubic gives a smoother
curve, at the price of possible overshoot near sharp features. resample_linear needs no
optional library and is the fallback when the interp extra is not installed.
Where next
Section titled “Where next”- Align mixed-resolution members — the common reason to resample: getting replicates onto one axis before aggregating them.
- Handle missing extras — what happens when code needs
interpin an environment that lacks it. - Reference — the operation registry table with every short name and its qualified name.