Skip to content

Add return_all_patterns parameter to isotopes.detect to preserve overlapping isotope series - #49

Merged
kheal merged 2 commits into
masterfrom
copilot/fix-remove-overlapping-isotope-series
Mar 12, 2026
Merged

Add return_all_patterns parameter to isotopes.detect to preserve overlapping isotope series#49
kheal merged 2 commits into
masterfrom
copilot/fix-remove-overlapping-isotope-series

Conversation

Copilot AI commented Mar 12, 2026

Copy link
Copy Markdown
Contributor

The child-filter in isotopes.detect (lines 235–236) unconditionally removes any feature that appears as an isotope child, which silently drops valid isotope chains when a spurious low-intensity noise peak incorrectly matches as a parent — a common failure mode for large peptides where intensity doesn't monotonically decay.

Changes

  • deimos/isotopes.py — Adds return_all_patterns=False to detect(). When True, skips the step that removes features appearing as isotope children, preserving overlapping chains for downstream filtering.
  • tests/test_isotopes.py — Adds test_detect_return_all_patterns covering the noise-shadows-monoisotopic scenario from the issue report.

Usage

isotopes = deimos.isotopes.detect(
    features,
    dims=['mz', 'drift_time'],
    tol=[0.02, 1.0],
    delta=1.003355,
    max_isotopes=1,
    max_charge=3,
    require_lower_intensity=False,
    return_all_patterns=True,   # returns both 487→490 and 490→493
)
# Filter out spurious patterns by decay ratio, charge state, etc.
isotopes = isotopes[isotopes['decay'].apply(lambda d: all(v < 2.0 for v in d))]

Default behaviour (return_all_patterns=False) is unchanged.

Original prompt

This section details on the original issue you should resolve

<issue_title>Issue: deimos.isotopes.detect removes overlapping isotope series</issue_title>
<issue_description>## Problem

Lines 235-236 in isotopes.py remove any parent feature that also appears as a child:

# Remove children (features that are themselves isotopes of other features)
isotopes = isotopes.loc[~isotopes["idx"].isin(isotopes["idx_iso"]), :]

This prevents detecting overlapping isotope series where a feature is both an isotope child AND a parent of another isotope. For large peptides, this breaks valid isotope chains when a low-intensity noise peak incorrectly matches as a parent. We can't filter by decay (using the require_lower_intensity parameter, but that assumption is not true for large molecules).

Reproducible Example

import pandas as pd
import deimos.isotopes

# Simulated peptide peaks: 
# - idx 487: low intensity noise at 557.975 Da
# - idx 490: M peak at 558.312 Da (high intensity)
# - idx 493: M+1 peak at 558.644 Da (high intensity)
features = pd.DataFrame({
    'mz': [557.975, 558.312, 558.644],
    'drift_time': [285.84, 285.97, 285.93],
    'intensity': [1870, 831232, 892192]
}, index=[487, 490, 493])

isotopes = deimos.isotopes.detect(
    features,
    dims=['mz', 'drift_time'],
    tol=[0.02, 1.0],
    delta=1.003355,
    max_isotopes=1,
    max_charge=3,
    require_lower_intensity=False
)

# Result: Only finds 487→490 (decay=444, invalid)
# Missing: 490→493 (decay=0.95, valid) because idx 490 is marked as child
print(isotopes[['idx', 'mz', 'charge', 'idx_iso', 'decay']])

Expected: Both patterns detected, so downstream filtering can remove 487→490 based on decay ratio.
Actual: Only 487→490 detected, 490→493 is removed at line 235.

Proposed Solution

Add parameter return_all_patterns=False to optionally skip the child filter:

def detect(..., return_all_patterns=False):
    ...
    # Line 235-236
    if not return_all_patterns:
        isotopes = isotopes.loc[~isotopes["idx"].isin(isotopes["idx_iso"]), :]

This allows users to apply custom post-filtering (e.g., by intensity ratio) on all detected patterns.
</issue_description>

Comments on the Issue (you are @copilot in this section)


🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

…lapping isotope series

Co-authored-by: kheal <10502759+kheal@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix overlapping isotope series detection in deimos.isotopes.detect Add return_all_patterns parameter to isotopes.detect to preserve overlapping isotope series Mar 12, 2026
Copilot AI requested a review from kheal March 12, 2026 22:08
@kheal
kheal marked this pull request as ready for review March 12, 2026 22:52
@kheal
kheal merged commit f31b85c into master Mar 12, 2026
10 checks passed
@kheal
kheal deleted the copilot/fix-remove-overlapping-isotope-series branch March 16, 2026 18:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Issue: deimos.isotopes.detect removes overlapping isotope series

2 participants