Repository: matchms/matchms
Pull request #449 (2023-06-27 11:21:56)

Add filter ionmode
Added a filter function to remove the wrong ionmode


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0660a5a6..7adce3b9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,9 +8,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ## [Unreleased]
 
 ### Added
-
-- New filter functions to repair a smiles that mismatches parent mass
-=======
 - New filter functions to repair a smiles that mismatches parent mass [#440](https://github.com/matchms/matchms/pull/440)
   - Updated adduct coversion and known adducts
   - added repair_adduct_based_on_smiles
@@ -20,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
   - added require_parent_mass_match_smiles
   - added function to combine this in repair_parent_mass_match_smiles_wrapper
 - Added repair_smiles_from_compound_name [#448](https://github.com/matchms/matchms/pull/448)
+- Added require_correct_ionmode [#449](https://github.com/matchms/matchms/pull/449)
 
 ### Changed
 - Use pandas for loading adducts dict
diff --git a/matchms/filtering/__init__.py b/matchms/filtering/__init__.py
index fc1f4ba6..f1516deb 100644
--- a/matchms/filtering/__init__.py
+++ b/matchms/filtering/__init__.py
@@ -77,6 +77,7 @@ from .repair_parent_mass_from_smiles.repair_smiles_of_salts import \
 from .repair_parent_mass_from_smiles.require_parent_mass_match_smiles import \
     require_parent_mass_match_smiles
 from .repair_smiles_from_compound_name import repair_smiles_from_compound_name
+from .require_correct_ionmode import require_correct_ionmode
 from .require_minimum_number_of_peaks import require_minimum_number_of_peaks
 from .require_minimum_of_high_peaks import require_minimum_of_high_peaks
 from .require_precursor_below_mz import require_precursor_below_mz
@@ -118,6 +119,7 @@ __all__ = [
     "remove_peaks_around_precursor_mz",
     "remove_peaks_outside_top_k",
     "repair_adduct_based_on_smiles",
+    "require_correct_ionmode",
     "repair_inchi_inchikey_smiles",
     "repair_parent_mass_is_mol_wt",
     "repair_parent_mass_match_smiles_wrapper",
diff --git a/matchms/filtering/require_correct_ionmode.py b/matchms/filtering/require_correct_ionmode.py
new file mode 100644
index 00000000..2a0ca306
--- /dev/null
+++ b/matchms/filtering/require_correct_ionmode.py
@@ -0,0 +1,26 @@
+import logging
+from matchms import Spectrum
+
+
+logger = logging.getLogger("matchms")
+
+
+def require_correct_ionmode(spectrum_in: Spectrum,
+                            ion_mode_to_keep):
+    """Removes spectra that are not in the correct ionmode"""
+    if spectrum_in is None:
+        return None
+    spectrum = spectrum_in.clone()
+    if ion_mode_to_keep not in {"positive", "negative", "both"}:
+        raise ValueError("ion_mode_to_keep should be 'positive', 'negative' or 'both'")
+    ion_mode = spectrum.get("ionmode")
+    if ion_mode_to_keep == "both":
+        if ion_mode in ("positive", "negative"):
+            return spectrum
+
+        logger.info("Spectrum was removed since ionmode was: %s which does not match positive or negative", ion_mode)
+        return None
+    if ion_mode == ion_mode_to_keep:
+        return spectrum
+    logger.info("Spectrum was removed since ionmode was: %s which does not match %s", ion_mode, ion_mode_to_keep)
+    return None


Test patch:
diff --git a/tests/filtering/test_require_correct_ionmode.py b/tests/filtering/test_require_correct_ionmode.py
new file mode 100644
index 00000000..dc08885d
--- /dev/null
+++ b/tests/filtering/test_require_correct_ionmode.py
@@ -0,0 +1,23 @@
+import pytest
+from matchms.filtering import require_correct_ionmode
+from ..builder_Spectrum import SpectrumBuilder
+
+
+@pytest.mark.parametrize("ionmode, ionmode_to_keep, spectrum_removed", [
+    ("positive", "positive", False),
+    ("negative", "negative", False),
+    ("positive", "both", False),
+    ("negative", "both", False),
+    ("positive", "negative", True),
+    ("negative", "positive", True),
+    ("n/a", "both", True),
+])
+def test_require_correct_ionmode(ionmode, ionmode_to_keep, spectrum_removed):
+    builder = SpectrumBuilder()
+    spectrum_in = builder.with_metadata({"ionmode": ionmode}).build()
+    spectrum = require_correct_ionmode(spectrum_in, ionmode_to_keep)
+
+    if spectrum_removed is True:
+        assert spectrum is None, "Expected spectrum to be filtered out since it does not have the correct ionmode"
+    else:
+        assert spectrum == spectrum_in