MSZX archives¶
Bundle an MSZ-compressed spectra file with search results into a single self-describing archive.
Build¶
from mscompress import MSZFile, MSZXBuilder
with MSZFile("spectra.msz") as msz:
(
MSZXBuilder()
.set_spectra(msz)
.set_description("DDA run #42")
.set_join_key("scan_number")
.add_annotation("percolator", "results.pin", format="percolator_pin")
.add_annotation("comet", "search.pep.xml", format="pepxml")
.set_extra(instrument="Orbitrap Eclipse")
.save("run42.mszx")
)
Or use the convenience function¶
from mscompress import create_mszx
create_mszx(
spectra="spectra.msz",
output="run42.mszx",
annotations=[
("percolator", "results.pin", "percolator_pin"),
("comet", "search.pep.xml", "pepxml"),
],
description="DDA run #42",
join_key="scan_number",
extra={"instrument": "Orbitrap Eclipse"},
)
Read¶
from mscompress import MSZXFile
with MSZXFile("run42.mszx") as archive:
print(archive.manifest.description)
print(archive.manifest.num_spectra)
# Iterate spectra
for s in archive.spectra:
...
# Iterate annotations
for entry in archive.manifest.annotations:
reader = archive.open_annotation(entry.name)
for psm in reader:
print(psm.scan_number, psm.peptide, psm.score)
Batch archives — many runs in one file¶
A v2 ("batch") archive bundles N independent MSZ files. Use it for a cohort, a
study, or anything you'd otherwise ship as a folder of .msz.
Compress a folder¶
from mscompress import compress_batch
compress_batch("runs/", "cohort.mszx", recursive=True, threads=8)
inputs accepts a path, a directory, a glob, or an iterable of any of those.
Directories contribute *.mzML; explicitly named files are taken as-is.
compress_batch(
["runA.mzML", "runB.mzML"],
"cohort.mszx",
description="cohort A",
extra={"study_id": "PXD012345"},
on_progress=lambda i, total, path: print(f"[{i + 1}/{total}] {path.name}"),
mz_lossy="delta32", # any RuntimeArguments setting
)
Incremental control, with annotations¶
from mscompress import MSZXBatchWriter
with MSZXBatchWriter("cohort.mszx", threads=8) as writer:
for path in mzml_paths:
idx = writer.add(path) # -> entry index
writer.add_annotation(
idx, pin_bytes, f"annotations/{path.stem}.pin",
format="percolator_tsv", num_records=4021,
)
writer.set_join_key(idx, "scan_number")
Leaving the with block via an exception calls abort(), so a partial archive
is never left behind. add() also accepts an already-open MZMLFile, reusing
its mapping rather than re-opening the file.
Annotation payloads are stored as given — compress them yourself and pass
compressed=True if you want them zstd-compressed.
Read a batch archive¶
from mscompress import read
with read("cohort.mszx") as archive: # -> MSZXBatchFile
print(len(archive), archive.names)
# Spectrum counts come from the manifest — no member is opened
for entry in archive.entries:
print(entry.entry, entry.num_spectra)
for member in archive: # opened lazily, cached
print(len(member.spectra))
first = archive[0] # or archive["runA.msz"]
psms = archive.get_annotation(0, "annotations/runA.pin")
archive.decompress("out/") # every member -> out/*.mzML
Members are opened on demand and released together by close(), so a
1000-member archive doesn't consume 1000 file descriptors unless you touch
every member.
Reading either version uniformly¶
MSZXBatchFile also opens a v1 archive, as a collection of one. Use it when
you're walking a directory of mixed archives and don't want to branch:
from mscompress.mszx import MSZXBatchFile
with MSZXBatchFile.open(path) as archive: # v1 -> 1 member, v2 -> N
for member in archive:
...
read() is unchanged: a v1 archive still returns an MSZXFile (which is an
MSZFile, so archive.spectra works directly). Opting into the collection view
is explicit.
Reproducibility¶
Batch archives contain no timestamps, so the same inputs and settings produce byte-identical output — and the CLI, Python, and Node all drive the same C writer, so it doesn't matter which one wrote the file.
The output must be a seekable regular file; writing to a pipe or stdout is an error. See why.
Manifest fields¶
See the MSZX format spec for both JSON schemas.
When to use it¶
- You're shipping data to a collaborator and want them to get spectra + identifications in one file.
- You're building an ML training dataset where each example needs to join a spectrum with a peptide assignment.
- You want a self-describing artifact with provenance baked in
(
description,extra). - You're moving a whole cohort as a single reproducible file (batch).