JCAMP-DX¶
Status: Supported (scoped) · Vendor: Vendor-neutral / IUPAC · Extensions:
.jdx,.dx,.jcm,.jcamp
JCAMP-DX is the IUPAC labelled-data interchange format for IR, NIR, Raman, UV-Vis
and NMR spectra. nirs4all-formats ships a native Rust reader for the high-value
spectroscopic shapes: dense XYDATA tables (plain and packed), XYPOINTS,
NTUPLES pages, sparse PEAK TABLE / PEAK ASSIGNMENTS, top-level multi-block
files and DATA TYPE=LINK containers.
Instruments & software¶
JCAMP-DX is written as an export by a wide range of spectrometers and chemometric
software rather than being tied to one vendor. Committed fixtures cover NIST
WebBook IR exports, Bruker test spectra, IUPAC NMR NTUPLES examples and an Ocean
Optics SpectraSuite LINK export.
File structure¶
A JCAMP-DX file is plain ASCII organised as ##KEY=value labelled-data records
(LDRs) terminated by ##END=. The reader sniffs any file containing
##JCAMP-DX= or ##JCAMPDX= and dispatches on the data shape:
XYDATA=(X++(Y..Y))— the X axis is reconstructed fromFIRSTXandDELTAX, or fromFIRSTX,LASTXandNPOINTSwhenDELTAXis absent. Each data line begins with an X checkpoint.XYPOINTS=(XY..XY)— explicit X/Y pairs are read directly rather than reconstructing the axis.NTUPLES— multi-page tables; the NMR real/imaginary layout (SYMBOL=X,R,I,N,VAR_TYPE=INDEPENDENT,DEPENDENT,DEPENDENT,PAGE) emits the real and imaginary channels as separate signals on one record.PEAK TABLE/PEAK ASSIGNMENTS— sparse peak lists (see below).DATA TYPE=LINKand top-level multi-block files — one or several records.
Ordinate encodings supported inside XYDATA/NTUPLES lines: plain AFFN rows,
PAC adjacent signed numbers, SQZ pseudo-digits, DIF difference coding and DUP
repeat counts. YFACTOR scales ordinates; XFACTOR scales peak abscissas and
widths inside peak tables.
What nirs4all-formats extracts¶
Signals — one or more
SpectralRecords.XYDATA/XYPOINTSproduce a singlesignal;NTUPLESproduces named channels (real,imaginary, …); peak blocks produce onepeak_intensitysignal. Signal type is mapped fromYUNITS(Absorbance / Transmittance / Reflectance, elseUnknown).Axis — values plus unit/kind from
XUNITS(orNTUPLESUNITS): wavenumbercm-1, wavelengthnm/um, frequencyhz, energyeV, times, otherwiseindex. Native axis order is preserved.LINK containers — two modes. Composite (same-axis): when every child reuses one axis the reader emits a single record whose signals are the children (the Ocean Optics flow:
sample,dark_reference,white_referenceplus a computedprocessedtransmittance,(sample - dark) / (white - dark) * 100). Fan-out (heterogeneous axes): one record per child, each carryinglink_parent_id,link_index,link_totaland alink_relation(sample/dark/reference/interferogram/fid/peaks/unknown) inferred fromDATA TYPEorTITLE. Top-level multi-block files behave like fan-out and also keep the legacyjcamp_block_index.Metadata — all LDRs are preserved under
metadata.jcamp; the full per-peak list is exported underjcamp_peak_table.Provenance & warnings — source file + SHA-256, reader name/version, and structured warnings (see below).
Peak tables¶
Sparse PEAK TABLE / PEAK ASSIGNMENTS blocks become a single peak_intensity
signal whose axis carries the listed peak abscissas in their native order (so
SpectralAxis.order may be ascending, descending or non-monotonic). Shapes
(XY..XY), (XYW..XYW), (XYM..XYM), (XYA), (XYWA), (XYMA) and
DATA TABLE=(XY..XY), PEAK … are parsed; assignment text is the first <…>
substring on a line. When both a PEAK TABLE and PEAK ASSIGNMENTS exist in one
block the richer ASSIGNMENTS form wins and the other is preserved under
jcamp_peak_table_dropped.
X-checkpoint verification¶
For XYDATA, line-start X values are checked against the reconstructed axis,
accepting either physical checkpoints or checkpoints that require XFACTOR. On
mismatch the reader emits a structured jcamp_xydata_x_checkpoint_drift warning
carrying the absolute and relative drift at the first mismatch so downstream tools
can act on it rather than parse a free-form string. (In the committed Bruker
fixtures FIRSTX/DELTAX are physical while line checkpoints are scaled
integers.)
Variants & support status¶
Variant |
Status |
Notes |
|---|---|---|
|
Supported |
X axis reconstructed; checkpoints verified. |
|
Supported |
Explicit X/Y pairs. |
|
Supported |
Channels split into signals; |
Top-level multi-block files |
Supported |
One record per block with |
|
Supported |
Ocean Optics flow; computed transmittance. |
|
Supported |
One record per child via |
|
Supported |
All documented JCAMP-DX 5.0 shapes parsed. |
|
Refused |
Mixing dense + sparse on one record has no clear semantics; use a standalone peak file. |
General real-world |
Partial |
Beyond Ocean Optics, generic LINK shapes still need scoping. |
Limitations & known gaps¶
For
XYDATA/NTUPLES,XFACTORis preserved in metadata but not applied to the reconstructed axis.When
NPOINTSdeclares more points than can be decoded the file is rejected as malformed; when it declares fewer, the record is truncated with a warning.Peak-table shape parsing covers all documented JCAMP-DX 5.0 variants, but only a synthetic peak fixture is committed; real vendor peak tables (embedded
>, multi-line assignments,;-separated groups) are still wanted.Generic multi-block
LINKfiles with heterogeneous semantics, andLINKs that combine dense spectra with peak tables, are not yet handled.The Ocean Optics zero-denominator case has no missing-value marker in the data model: those points are set to
0.0with a provenance warning.
Reference readers¶
Cross-checked conceptually against jcamp (jcamp.jcamp_readfile, wired into the
conformance harness), SpectroChemPy, nmrglue, ChemoSpec and hyperSpec. The
current reader is intentionally narrower than these mature libraries, prioritising
the high-value NIR/IR XYDATA cases.
Samples & validation¶
Fixtures live under samples/jcamp_dx/ and are covered by golden summaries in
crates/nirs4all-formats/tests/goldens/; the probe reports format jcamp-dx at
Confidence::Definite. Committed control values:
File |
Encoding |
Points |
Axis |
Value control |
|---|---|---|---|---|
|
plain AFFN |
3917 |
|
|
|
two top-level |
7153 × 2 |
|
reflectance first values |
|
SQZ |
16384 |
|
|
|
DIF/DUP |
16384 |
|
|
|
mixed SQZ/DIF/DUP |
1801 |
|
|
|
|
16384 × 2 |
|
real |
|
|
16384 × 2 |
|
real |
|
|
3648 × 4 |
|
computed transmittance |
|
|
4 peaks |
|
absorbance |
Full-array conformance reports against open JCAMP readers for every committed
fixture are tracked in docs/CONFORMANCE.md.