Feature filter multiply labeled peptides - #145
Conversation
Label assignment previously tested only for the presence of a labelable residue via grepl, never the count, so peptides with 2+ labelable residues (e.g. 2 lysines under Lys6) passed through into turnover analysis. Those peptides can be partially labeled, which the two-state turnover model cannot represent. Add .countRegexMatches and .filterMultiplyLabeledPeptides to the shared feature-cleaning utils, and gate them behind a new filter_multiply_ labeled flag on .classifyIsotopeLabelType so DIANN is unaffected until it opts in. Spectronaut enables the filter. The count is taken on the bracket-stripped sequence so that residue letters inside an unrelated modification tag are not counted, and across all residues in heavyLabels combined, since one lysine plus one arginine is doubly labelable when both labels are specified. Heavy and light rows are dropped together to avoid biasing the fraction-new denominator.
Apply the same 2+ labelable residue filter to the DIANN ModifiedSequence path. The Channel path is exempt: label state is read from a dedicated column rather than inferred from sequence content, so the converter cannot see the partial-labeling state at this layer. Move the filter out of .classifyIsotopeLabelType and into an explicit pre-processing call in each converter. DIANN could not reuse the flag added in the previous commit, since its light_regex matches label tags rather than bare residues, leaving the classifier with no residue pattern to count in DIANN mode. Threading two more regexes through a five-parameter function would also have kept a function named "classify" silently dropping rows. .filterMultiplyLabeledPeptides now strips annotations itself, so both converters share the counting logic while supplying their own patterns. Counting strips all parentheticals rather than only the label tags, so that a residue letter inside an unrelated modification such as (Kmod) is not counted, mirroring how the Spectronaut path strips all bracket annotations before counting.
The filter was silent, so peptides disappeared from a user's data with nothing to trace the loss back to. Log the exclusion through the standard MSstatsLog/MSstatsMsg pair, at INFO rather than WARN since this is intentional documented behaviour rather than a data problem. Report distinct peptides rather than rows, counted on the stripped sequence so the heavy and light forms of one peptide are not reported as two, with the row count alongside it for scale. Rows alone would overstate the loss, since one peptide spans many fragment ions, charge states and runs. Both converters route through .filterMultiplyLabeledPeptides, so a single call site covers Spectronaut and DIANN.
The user-facing @PARAM blocks described peptides as being classified heavy, light or unlabeled, with no mention of the fourth outcome now possible: removed entirely. Anyone reading ?SpectronauttoMSstatsFormat or ?DIANNtoMSstatsFormat would have had no way to know some of their peptides do not survive the converter. Document the filter on both converters, stating that residues are counted across all supplied labels together, and flag support for multiply labeled peptides as future work rather than a settled design choice. On DIANN the note sits inside the ModifiedSequence-parsing section and says the channel path is unaffected, since the filter applies to only one of that converter's two paths. Regenerate man/. MSstatsClean.Rd and the two .cleanRaw* pages inherit these params, so they pick the text up as well.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (13)
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughDIA-NN and Spectronaut sequence-based isotope-label workflows now remove peptides with multiple labelable residues before classification. The change adds shared filtering helpers, preserves DIA-NN channel processing, updates Spectronaut label syntax documentation, and adds tests. ChangesIsotope-label filtering
Estimated code review effort: 3 (Moderate) | ~20 minutes Merge Risk: ⚪ Minimal · up to The PR filters multiply labeled peptides from the affected turnover conversion paths and reports removals; no actionable merge-blocking risk remains after normal checks and review. Sequence Diagram(s)sequenceDiagram
participant SequenceData
participant filterMultiplyLabeledPeptides
participant IsotopeClassification
SequenceData->>filterMultiplyLabeledPeptides: count labelable residues
filterMultiplyLabeledPeptides-->>SequenceData: remove multiply labeled rows
SequenceData->>IsotopeClassification: classify remaining sequences
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Motivation and Context
Protein turnover analysis models each peptide as existing in exactly two mass
states: fully light and fully heavy. A peptide carrying more than one labelable
residue (e.g. two lysines under Lys6) breaks that assumption, because it can be
partially labeled and so occupies intermediate mass states the model has no
representation for. Including such peptides biases the fraction-new denominator.
Both turnover-capable converters were letting these peptides through. Label
assignment tested only for the presence of a labelable residue via
grepl,never the count, so a peptide with two or more labelable residues was classified
as heavy or light like any other and passed into downstream analysis.
This PR filters peptides with two or more labelable residues out of the turnover
paths in the Spectronaut and DIA-NN converters, and reports how many were
removed. Heavy and light rows for the same peptide are dropped together, so the
light/heavy ratio stays unbiased.
Changes
.filterMultiplyLabeledPeptides()toR/utils_clean_features.R: stripslabel and modification annotations from
PeptideSequence, counts labelableresidues on the stripped sequence, and drops rows with a count of two or more.
.countRegexMatches()helper in the same file, scoring no-match andNAas zero.
.assignSpectronautIsotopeLabelType()inR/clean_Spectronaut.R, ahead of.classifyIsotopeLabelType(). Residues arecounted across all labels in
heavyLabelscombined, so withc("K[Lys6]", "R[Arg10]")a peptide with one lysine and one arginine counts astwo and is removed.
ModifiedSequencepath inR/clean_DIANN.R,counting across all of
labeledAminoAcidscombined. The channel-based path isdeliberately exempt, since it does not infer labeling from sequence content.
an unrelated modification are not miscounted as labelable sites.
MSstatsLog/MSstatsMsgatINFO, since theexclusion is otherwise invisible to the user. Distinct peptides are counted on
the stripped sequence so the heavy and light forms of one peptide are reported
as one peptide, with the affected row count given alongside.
heavyLabelsandlabeledAminoAcidsparameters, including the note that supporting partiallylabeled peptides is future work, and regenerated the affected
.Rdfiles.Testing
Added unit tests; full suite is 766 assertions, 0 failures, no new warnings.
inst/tinytest/test_utils_clean_features.R— direct tests of.filterMultiplyLabeledPeptides(): that heavy and light forms of one peptideare reported as a single peptide with the row count alongside, and that nothing
is reported when there is nothing to remove. Console output is captured
directly, since the appender writes with
cat().inst/tinytest/test_clean_Spectronaut.R— multiply labeled peptides arefiltered from
.assignSpectronautIsotopeLabelType(); the count is taken acrossall labels combined; residue letters inside an unrelated modification are not
counted;
heavyLabels = NULLleaves the data untouched.inst/tinytest/test_clean_DIANN.R— the same cases for theModifiedSequencepath, plus a test asserting the
Channelpath is exempt and its rows arepreserved.
Checklist Before Requesting a Review
Motivation and Context
Turnover workflows do not support peptides with multiple labelable residues. These peptides can produce more than two labeling states. The PR removes these peptides before isotope-label classification.
The filtering applies to Spectronaut and DIA-NN
ModifiedSequenceworkflows. DIA-NN channel-based workflows remain unchanged.Changes
MSstatsLogandMSstatsMsgatINFO.ModifiedSequencepath.heavyLabelsdocumentation to require residue-qualified labels, such asK[Lys6]..Rddocumentation.Unit Tests
Coding Guideline Violations
The provided change summary does not identify any coding guideline violations.