Repository: matchms/matchms
Pull request #70 (2020-06-04 13:03:15)

Add loss normalization to normalize_intensities filter
- Add loss normalization to ``normalize_intensities`` filter
- Add case to unit tests.
- Slightly simplify ``add_losses`` function



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 87e0bb32..99b35465 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,7 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Changed
 
-- ...
+- normalize_intensities filter now also normalizes losses [#69](https://github.com/matchms/matchms/issues/69)
 
 ### Fixed
 
diff --git a/matchms/filtering/add_losses.py b/matchms/filtering/add_losses.py
index 06eb9e01..9a4df6ea 100644
--- a/matchms/filtering/add_losses.py
+++ b/matchms/filtering/add_losses.py
@@ -15,13 +15,6 @@ def add_losses(spectrum_in: SpectrumType, loss_mz_from=0.0, loss_mz_to=1000.0) -
     loss_mz_to:
         Maximum allowed m/z value for losses. Default is 1000.0.
     """
-    def precursor_mz_is_number():
-        if isinstance(precursor_mz, int):
-            return True
-        if isinstance(precursor_mz, float):
-            return True
-        return False
-
     if spectrum_in is None:
         return None
 
@@ -29,8 +22,8 @@ def add_losses(spectrum_in: SpectrumType, loss_mz_from=0.0, loss_mz_to=1000.0) -
 
     precursor_mz = spectrum.get("precursor_mz")
     if precursor_mz:
-        assert precursor_mz_is_number(), ("Expected 'precursor_mz' to be a scalar number.",
-                                          "Consider applying 'add_precursor_mz' filter first.")
+        assert isinstance(precursor_mz, (float, int)), ("Expected 'precursor_mz' to be a scalar number.",
+                                                        "Consider applying 'add_precursor_mz' filter first.")
         peaks_mz, peaks_intensities = spectrum.peaks
         losses_mz = (precursor_mz - peaks_mz)[::-1]
         losses_intensities = peaks_intensities[::-1]
diff --git a/matchms/filtering/normalize_intensities.py b/matchms/filtering/normalize_intensities.py
index a1dbb7e3..8a38fcda 100644
--- a/matchms/filtering/normalize_intensities.py
+++ b/matchms/filtering/normalize_intensities.py
@@ -4,17 +4,27 @@ from ..Spikes import Spikes
 
 
 def normalize_intensities(spectrum_in: SpectrumType) -> SpectrumType:
-    """Normalize intensities to unit height."""
+    """Normalize intensities of peaks (and losses) to unit height."""
 
     if spectrum_in is None:
         return None
 
     spectrum = spectrum_in.clone()
 
-    if len(spectrum.peaks) > 0:
-        scale_factor = numpy.max(spectrum.peaks.intensities)
-        mz, intensities = spectrum.peaks
-        normalized_intensities = intensities / scale_factor
-        spectrum.peaks = Spikes(mz=mz, intensities=normalized_intensities)
+    if len(spectrum.peaks) == 0:
+        return spectrum
+
+    max_intensity = numpy.max(spectrum.peaks.intensities)
+
+    # Normalize peak intensities
+    mz, intensities = spectrum.peaks
+    normalized_intensities = intensities / max_intensity
+    spectrum.peaks = Spikes(mz=mz, intensities=normalized_intensities)
+
+    # Normalize loss intensities
+    if spectrum.losses is not None and len(spectrum.losses) > 0:
+        mz, intensities = spectrum.losses
+        normalized_intensities = intensities / max_intensity
+        spectrum.losses = Spikes(mz=mz, intensities=normalized_intensities)
 
     return spectrum


Test patch:
diff --git a/tests/test_normalize_intensities.py b/tests/test_normalize_intensities.py
index 40ecd7bd..a2d828a0 100644
--- a/tests/test_normalize_intensities.py
+++ b/tests/test_normalize_intensities.py
@@ -1,10 +1,11 @@
 import numpy
 from matchms import Spectrum
+from matchms.filtering import add_losses
 from matchms.filtering import normalize_intensities
 
 
 def test_normalize_intensities():
-
+    """Test if peak intensities are normalized correctly."""
     mz = numpy.array([10, 20, 30, 40], dtype='float')
     intensities = numpy.array([0, 1, 10, 100], dtype='float')
     spectrum_in = Spectrum(mz=mz, intensities=intensities)
@@ -12,12 +13,29 @@ def test_normalize_intensities():
     spectrum = normalize_intensities(spectrum_in)
 
     assert max(spectrum.peaks.intensities) == 1.0, "Expected the spectrum to be scaled to 1.0."
-    assert numpy.array_equal(spectrum.peaks.mz, mz), "Expected the spectrum's intensity locations along "\
-                                                     "the mz-axis to be unaffected."
+    assert numpy.array_equal(spectrum.peaks.intensities, intensities/100), "Expected different intensities"
+    assert numpy.array_equal(spectrum.peaks.mz, mz), "Expected different peak mz."
 
 
-def test_normalize_intensities_empty_peaks():
+def test_normalize_intensities_losses_present():
+    """Test if also losses (if present) are normalized correctly."""
+    mz = numpy.array([10, 20, 30, 40], dtype='float')
+    intensities = numpy.array([0, 1, 10, 100], dtype='float')
+    spectrum_in = Spectrum(mz=mz, intensities=intensities,
+                           metadata={"precursor_mz": 45.0})
+
+    spectrum = add_losses(spectrum_in)
+    spectrum = normalize_intensities(spectrum)
+    expected_loss_intensities = numpy.array([1., 0.1, 0.01, 0.], dtype='float')
+
+    assert max(spectrum.peaks.intensities) == 1.0, "Expected the spectrum to be scaled to 1.0."
+    assert numpy.array_equal(spectrum.peaks.intensities, intensities/100), "Expected different intensities"
+    assert max(spectrum.losses.intensities) == 1.0, "Expected the losses to be scaled to 1.0."
+    assert numpy.all(spectrum.losses.intensities == expected_loss_intensities), "Expected different loss intensities"
+
 
+def test_normalize_intensities_empty_peaks():
+    """Test running filter with empty peaks spectrum."""
     mz = numpy.array([], dtype='float')
     intensities = numpy.array([], dtype='float')
     spectrum_in = Spectrum(mz=mz, intensities=intensities)
@@ -25,3 +43,10 @@ def test_normalize_intensities_empty_peaks():
     spectrum = normalize_intensities(spectrum_in)
 
     assert spectrum == spectrum_in, "Spectrum should remain unchanged."
+
+
+def test_normalize_intensities_empty_spectrum():
+    """Test running filter with spectrum == None."""
+    spectrum = normalize_intensities(None)
+
+    assert spectrum is None, "Expected spectrum to be None."