PDV 2.7.0
This release adds support for the Sage search engine: open a results.sage.tsv together with its mgf or mzML files and get the usual paged PSM table with annotated spectra, working modifications, and all 40 Sage columns. Along the way the Database Searching dialog learned to read gzipped spectrum files, and seven long-standing bugs affecting the other import formats were fixed — including one that made every mzIdentML import, and every import using an mzML spectrum file, fail outright on Java 16 and newer, and two that stopped mzXML and proBAM/proBed results being displayed at all.
✨ New: Sage support
Pick results.sage.tsv in the Database Searching dialog, choose Sage as the file type, and add the spectrum files the search used.
- mgf, mgf.gz, mzML and mzML.gz inputs, and several spectrum files per search — each PSM is matched to its own file through the result file's
filenamecolumn, ignoring a.gzsuffix so rows still resolve after decompression. - All 40 Sage columns become sortable table columns and can be toggled from View → Column Selection; 13 of the most useful (
proteins,filename,charge,rank,label,rt,hyperscore,delta_next,sage_discriminant_score,posterior_errorand the three q-values) are shown by default so the table stays readable. Column headers drop the underscores from Sage's names, sodelta_nextappears asdeltanext. - Inline modification masses are parsed from the Sage peptide grammar — residue mods (
C[+57.0215]), N-terminal ([+229.1629]-PEPTIDE) and C-terminal (PEPTIDE-[+12.34]) — and registered as user PTMs named<mass> of <residue>, so they render in the sequence strip and can be recoloured from the PTM colour dialog. - Both
scannrdialects are handled: the full mgfTITLEline for mgf input (CSV-quoted by Sage, with doubled quotes and embedded commas) and thecontrollerType=0 controllerNumber=1 scan=NnativeID for mzML, which is resolved to a scan number through the mzML index. - Every spectrum file referenced by the result file is checked before the import starts, and any that were not selected are listed in a single message instead of failing part-way through.
Import filters
A Sage-only filter row (hidden for the other formats) controls what is loaded:
- Targets only — skips decoy hits (
label = -1). On by default. - q <= 0.01 only — skips hits above 1%
spectrum_q. Off by default.
The two compose independently, so decoys can be inspected on their own when needed.
🗜️ New: gzipped spectrum files
The Database Searching dialog now accepts .mgf.gz, .mzML.gz and .mzXML.gz and decompresses them to the temp folder on import — none of the underlying readers can read gzip directly. This applies to every format in that dialog, not just Sage.
- The decompressed copy is placed in a folder keyed by the source's path, size and modification time, so two runs holding files of the same name never share one.
- It is written to a
.partfile and renamed on success, so an interrupted run never leaves a truncated file that the next import would take for a complete one. - An existing decompressed copy is reused across imports, and copies are marked for deletion when PDV exits.
🐞 Bug fixes
- Every mzIdentML import, and every import using an mzML spectrum file, failed on Java 16+. Both the mzIdentML reader and the mzML run-header reader go through JAXB, whose optimized accessor generation calls
ClassLoader.defineClassreflectively. Java 16 made strong encapsulation the default, so that call now throwsInaccessibleObjectExceptionfrom a static initializer and kills the parse withExceptionInInitializerError(on Java 9–15 it was permitted with a warning). PDV now disables that code generation at startup, so no--add-opensflag is needed. Verified on Java 21 against the mzIdentML and mzML example files linked in the README: both fail before the change and parse after it. The two are independent — an mgf + mzIdentML import was hit by the identification side, and a pepXML or mzTab import from an mzML by the spectrum side. pepXML itself is read with a pull parser and was never affected on its own. - mzXML and proBAM/proBed results could not be shown in the PSM table. Only the database import dialog builds one scan collection per spectrum file; the dialog loads a single collection for mzXML, and the proBAM/proBed dialog loads a single one for mzML as well. The table model assumed the per-file map, so filling any row threw
ClassCastExceptionand the table came up empty behind a "Table not instantiated" error. It now dispatches on the shape of the object it is given rather than on the format name, which is what every dialog agrees on. Verified on the README mzXML and proBAM examples. - Clicking a row of a proBAM or proBed result read from mzML threw.
getSpectrum()looked the scan collection up in the per-file map that this path never fills, so every row selection ended inNullPointerExceptionand no spectrum was ever drawn. proBed cannot key such a map anyway — it is not given the spectrum file, and it keys its matches with the file named in the mzIdentMLSpectraData— so the collection is now resolved rather than assumed. - A spectrum that cannot be drawn is now reported instead of crashing. An identification can name a scan the spectrum file does not hold, or an MS1 (which isolates nothing, so has no precursor), or a scan whose peaks were never parsed — importers load peaks for MS2 scans only. Any of these threw, out of a row click or in the middle of a batch export, with nothing to say which PSM was at fault. The mzML and mzXML readers now return no spectrum for such a match; the window says so in the panel border, naming the PSM, and clears the plot and the match statistics with it, and the two export paths skip the PSM, name it on the console and keep counting it towards the progress bar.
MzXMLScanImportalso stopped reading the first isolation window unconditionally, which made an mzXML MS1 throwIndexOutOfBoundsException. The headless CLI carried its own copy of the same reader and was given the same treatment. - Retention time was 60x too large for Mascot
.datresults and for FragPipe results. The two spectrum readers disagree on units — msftbx reports minutes, MSDK seconds — while the compomicsPrecursorexpects seconds, and the FragPipe/Mascot table read that field back as if it were already minutes. FragPipe from mgf and Mascot.datboth store a genuinely seconds-based retention time, so both were 60x out; FragPipe from mzXML was too, through MSDK.MzXMLScanImport.getRt()now returns minutes as theIScancontract states, everyPrecursoris built in seconds, and the readers ofRT (min)convert consistently. The plain database table was already correct for mgf and mzML and is unchanged. - Batch export rendered the wrong spectrum for mzML results.
getSpectrum(String)read the scan number of an mzML/mzXML spectrum from a mutable field the caller never set, so every exported PSM got whichever scan was last selected in the table. The match is now passed in explicitly. - Switching result formats in one session could leave the table blank. The column-visibility map kept the previous format's column names, which the table then looked up on the new format's columns and threw. It is now cleared when the session is reset.
🧪 Tests
- New
SageImportTest(12 tests, offline) covers the peptide grammar — unmodified peptides, residue mods and their 1-based sites, negative masses, N-terminal and C-terminal mods and both together, and an unterminated bracket — plus the CSV unquoting ofscannrand the spectrum-file-name matching, including path-qualified and gzipped names.
🔄 Compatibility
- Existing projects, import formats, and command-line modes continue to work unchanged.
- Sage is additive: it is a new entry in the result-type dropdown and changes nothing for the existing formats.
- Gzip support is additive too — uncompressed spectrum files behave exactly as before.
- The
RT (min)column changes value for Mascot.datand FragPipe results, because it was previously 60x too large there. Every other format'sRT (min), including plain mgf and mzML database results, is unchanged. - mzIdentML, mzXML and proBAM/proBed results, and anything read from an mzML, become usable again; they were broken by the bugs above rather than by anything in this release.
- A PSM whose spectrum cannot be found or drawn no longer aborts the view or the export: the panel says so, and exports skip it and carry on.
📦 Full changelog
- Add Sage search engine support (3ffcb13)
- Fix the PSM table failing for mzXML and proBAM/proBed results (0b785b4)
- Fix the row click on proBAM and proBed results read from mzML (90cc2f3)
- Report a spectrum that cannot be drawn instead of failing on it (c7d8f11)
- Complete the handling of spectra that cannot be drawn (28ce395)
Full diff: v2.6.0...v2.7.0