Google Summer of Code Report
GSoC 2026 · OpenMSAditya-Sarna

Google Summer of Code 2026

imzML parser in OpenMS

Work from 25th May to 23 August 2026.

Aditya Sarna
Aditya SarnaContributor · Mentor Timo Sachsenberg

OpenMS previously had no native support for imzML, the open standard for mass spectrometry imaging. An imzML dataset consists of an XML metadata file and a companion binary .ibd file containing the actual peak data. This project added native C++ imzML reading and writing to OpenMS and then carried the same stack into both pyopenms-viewer and openms-viewer.

The original task list is available on the OpenMS GSoC 2026 page. The flagship contribution is OpenMS #9454. The pull requests below were opened after 25 May 2026.

MergedOpenMS6 June 2026

#9454 ImzML parser in OpenMS

This is the core GSoC deliverable: native imzML support inside OpenMS. Previously, imaging datasets had to be converted or accessed through an external Python package. The new ImzMLFile adapter reuses OpenMS's mzML SAX infrastructure through an ImzMLHandler, which handles the imaging-specific vocabulary and seeks directly into the .ibd file for peak data.

Both official imzML encodings are supported. In continuous mode, every pixel shares a single m/z axis that is stored once. In processed mode, each pixel has its own m/z and intensity arrays. The implementation supports several loading paths, including a fully in-memory MSImagingExperiment, streaming through IMSDataConsumer, index-only parsing, and lazy random access through OnDiscImzMLExperiment.

Writing is also supported for both modes. The writer selects continuous or processed mode based on the metadata or whether all spectra share the same m/z axis, while respecting PeakFileOptions for precision and filtering.

Dataset-level metadata such as grid size, pixel size, UUIDs, checksums, scan pattern, and polarity is preserved on the experiment. Per-spectrum coordinates are stored as imzml:x/y/z MetaValues. Geometry is constructed from the parsed coordinate index, ensuring that in-memory and on-disc workflows use the same spatial mapping.

The implementation is covered by C++ and pyOpenMS tests using the official continuous and processed fixtures. A C++ tutorial (Tutorial_ImzMLFile) documents the public load, stream, on-disc, and store paths.

View pull request ↗
MergedOpenMS24 June 2026

#9654 On-disc extractIonImage

Imaging datasets can be far too large to load entirely into RAM just to generate a single ion image. This change adds OnDiscImzMLExperiment::extractIonImage(), which scans the .ibd file pixel by pixel and sums intensities within a specified m/z ± ppm window without decoding the entire experiment.

A second overload allows the scan to be restricted to a specific acquisition region when a file contains multiple regions. Pixel placement uses the MSImagingGeometry constructed when the file is opened, giving the on-disc extractor the same coordinate mapping as the in-memory MSImagingExperiment.

This means viewers and scripts can switch between in-memory and on-disc processing without changing how coordinates are interpreted. Invalid m/z or tolerance values, as well as unknown region IDs, are rejected with clear errors.

C++ tests compare on-disc and in-memory ion images pixel by pixel, while corresponding pyOpenMS tests ensure that both interfaces expose the same behavior.

View pull request ↗
Mergedpyopenms-viewer4 July 2026

#41 Replace pyimzML with OpenMS ImzMLFile

Initially, pyopenms-viewer relied on pyimzML to open imzML files. Once native support was available in OpenMS, the viewer was updated to use ImzMLFile instead.

This change gives the viewer and the C++ library a shared decoding path, ensuring that pixel coordinates, continuous versus processed encoding, and dataset metadata are interpreted consistently across OpenMS tools.

The pull request intentionally keeps the scope narrow. TIC and the existing generic viewer continue to work as before, with each pixel represented as an MSSpectrum. This preserves the existing peak map, spectrum browser, and table functionality while laying the foundation for the dedicated ion-image interface added next.

View pull request ↗
Mergedpyopenms-viewer7 July 2026

#42 Ion image panel

This change introduced the first complete MSI interaction loop in pyopenms-viewer.

After loading an imzML file, the new ImagingPanel displays a total-ion image. Users can then extract an ion image using a selected m/z value and ppm tolerance, or click a peak in the mean or skyline aggregate spectrum to update the corresponding image immediately.

The interaction works in both directions. Selecting a pixel updates the corresponding spectrum in the existing spectrum panel, while selecting peaks in the aggregate spectrum updates the spatial ion image. Multiple ions can also be combined into an RGB overlay and cleared when needed.

The aggregate spectrum is calculated once when the dataset is opened, avoiding repeated scans during interaction. Reload and reconnect behavior was also added so the imaging panel survives a browser refresh.

The pull request additionally fixes a Plotly blank-render issue that occurred after expanding the panel.

Screen recording from the pull request showing TIC, peak-click ion images, pixel-to-spectrum selection, and RGB overlays.
View pull request ↗
MergedOpenMS15 July 2026

#9745 ImzMLFile documentation

This documentation pass brought the ImzMLFile API documentation in line with the implementation that had shipped. After the parser was integrated with the first-class MSImagingExperiment API, several comments still described an earlier design.

The updated documentation clarifies that geometry is derived from the parsed per-spectrum coordinate index, which is also used by loadSpectraIndex() and OnDiscImzMLExperiment, rather than being reconstructed from imzml:x/y MetaValues.

It also documents the .ibd UUID check performed during loading. Each load path checks the first 16 bytes of the .ibd against the IMS:1000080 UUID declared in the XML. Missing or mismatched UUIDs generate advisory warnings so that legacy files can still be opened, while callers requiring stricter validation can inspect the log.

The documentation also specifies how invalid coordinates are handled. Coordinates outside the declared grid or below one are skipped with a warning. Duplicate pixels are warned about; only the first spectrum at a coordinate enters the geometry.

No functional code was changed in this pull request; the changes were limited to ImzMLFile.h.

View pull request ↗
Mergedopenms-viewer28 July 2026

#27 MSI ion-image parity

The C++/Qt OpenMS Viewer was updated to provide the same ion-image interaction model already available in pyopenms-viewer.

Screen recording from the review showing pixel selection and synchronized spectrum and imaging panels on Example_Processed.imzML.
View pull request ↗
MergedOpenMS13 August 2026

#9908 Per-peak ion mobility arrays

The initial imzML implementation handled m/z and intensity arrays but did not preserve additional per-peak arrays such as ion mobility. As a result, ion mobility information could be present in the source file but would be dropped during writing and unavailable when reading it back.

This change extends the imzML writer to store same-length FloatDataArray objects as additional external .ibd blocks after the m/z and intensity arrays. Known PSI-MS terms retain their accession and units, while unknown names are represented using MS:1000786.

Both the in-memory parser and OnDiscImzMLExperiment::getSpectrum() now restore these arrays, allowing ion mobility data to be accessed without loading the entire dataset. Arrays with inconsistent lengths are skipped with a warning, while zlib-compressed auxiliary arrays raise a ParseError.

View pull request ↗
Openpyopenms-viewer16 August 2026

#46 imzML ion-mobility visualization

With OpenMS now able to preserve per-peak ion mobility data in imzML, the next step was making that information visible in the viewer.

This pull request adds ion-mobility visualization to pyopenms-viewer. Imaging pixels containing an IM array can now be inspected alongside the spatial ion image, ensuring that the additional mobility dimension is no longer lost at the UI boundary.

The panel follows the same interaction model established by the earlier ion-image work. Selecting a peak or pixel updates the related views, while the mobility view becomes available when the loaded dataset actually contains ion-mobility information.

Walkthrough from the pull request: imzML ion-mobility visualization in pyopenms-viewer.
View pull request ↗