Repository: matchms/matchms
Pull request #291 (2022-01-05 13:51:38)

change Spikes getitem
Changes the API for handling Spikes (spectrum.peaks) so that `spectrum.peaks[5]` will return the peak number 5 (hence a pair of mz and intensity).


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index babcc2ef..8676c433 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Changed
 
+- Spikes object now has different getitem method that allows to extract specific peaks as mz/intensity pair (or array) [#291](https://github.com/matchms/matchms/pull/291)
 - minor improvement of compound name cleaning in `derive_adduct_from_name()` filter [#280](https://github.com/matchms/matchms/pull/280)
 
 ### Fixed
diff --git a/matchms/Spikes.py b/matchms/Spikes.py
index 8f0e33b1..5d5768de 100644
--- a/matchms/Spikes.py
+++ b/matchms/Spikes.py
@@ -4,6 +4,33 @@ import numpy
 class Spikes:
     """
     Stores arrays of intensities and M/z values, with some checks on their internal consistency.
+
+    For example
+
+    .. testcode::
+
+        import numpy as np
+        from matchms import Spikes
+
+        mz = np.array([10, 20, 30], dtype="float")
+        intensities = np.array([100, 20, 300], dtype="float")
+
+        peaks = Spikes(mz=mz, intensities=intensities)
+        print(peaks[2])
+
+    Should output
+
+    .. testoutput::
+
+       [ 30. 300.]
+
+    Attributes
+    ----------
+    mz:
+        Numpy array of m/z values.
+    intensities:
+        Numpy array of peak intensity values.
+
     """
     def __init__(self, mz=None, intensities=None):
         assert isinstance(mz, numpy.ndarray), "Input argument 'mz' should be a numpy.array."
@@ -28,7 +55,7 @@ class Spikes:
         return self._mz.size
 
     def __getitem__(self, item):
-        return [self.mz, self.intensities][item]
+        return numpy.asarray([self.mz[item], self.intensities[item]])
 
     def _is_sorted(self):
         return numpy.all(self.mz[:-1] <= self.mz[1:])
diff --git a/matchms/filtering/add_losses.py b/matchms/filtering/add_losses.py
index 2ed63bb9..0b838380 100644
--- a/matchms/filtering/add_losses.py
+++ b/matchms/filtering/add_losses.py
@@ -28,7 +28,7 @@ def add_losses(spectrum_in: SpectrumType, loss_mz_from=0.0, loss_mz_to=1000.0) -
     if precursor_mz:
         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
+        peaks_mz, peaks_intensities = spectrum.peaks.mz, spectrum.peaks.intensities
         losses_mz = (precursor_mz - peaks_mz)[::-1]
         losses_intensities = peaks_intensities[::-1]
         # Add losses which are within given boundaries
diff --git a/matchms/filtering/normalize_intensities.py b/matchms/filtering/normalize_intensities.py
index 3aa86988..f632ecce 100644
--- a/matchms/filtering/normalize_intensities.py
+++ b/matchms/filtering/normalize_intensities.py
@@ -25,13 +25,13 @@ def normalize_intensities(spectrum_in: SpectrumType) -> SpectrumType:
         return None
 
     # Normalize peak intensities
-    mz, intensities = spectrum.peaks
+    mz, intensities = spectrum.peaks.mz, spectrum.peaks.intensities
     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
+        mz, intensities = spectrum.losses.mz, spectrum.losses.intensities
         normalized_intensities = intensities / max_intensity
         spectrum.losses = Spikes(mz=mz, intensities=normalized_intensities)
 
diff --git a/matchms/filtering/reduce_to_number_of_peaks.py b/matchms/filtering/reduce_to_number_of_peaks.py
index 17a76f78..a7127a12 100644
--- a/matchms/filtering/reduce_to_number_of_peaks.py
+++ b/matchms/filtering/reduce_to_number_of_peaks.py
@@ -38,7 +38,7 @@ def reduce_to_number_of_peaks(spectrum_in: SpectrumType, n_required: int = 1, n_
         raise ValueError("Cannot use ratio_desired for spectrum without parent_mass.")
 
     def _remove_lowest_intensity_peaks():
-        mz, intensities = spectrum.peaks
+        mz, intensities = spectrum.peaks.mz, spectrum.peaks.intensities
         idx = intensities.argsort()[-threshold:]
         idx_sort_by_mz = mz[idx].argsort()
         spectrum.peaks = Spikes(mz=mz[idx][idx_sort_by_mz],
diff --git a/matchms/filtering/remove_peaks_around_precursor_mz.py b/matchms/filtering/remove_peaks_around_precursor_mz.py
index cfd94f06..d30b4781 100644
--- a/matchms/filtering/remove_peaks_around_precursor_mz.py
+++ b/matchms/filtering/remove_peaks_around_precursor_mz.py
@@ -27,7 +27,7 @@ def remove_peaks_around_precursor_mz(spectrum_in: SpectrumType, mz_tolerance: fl
                                                     "Consider applying 'add_precursor_mz' filter first.")
     assert mz_tolerance >= 0, "mz_tolerance must be a positive scalar."
 
-    mzs, intensities = spectrum.peaks
+    mzs, intensities = spectrum.peaks.mz, spectrum.peaks.intensities
     peaks_to_remove = ((numpy.abs(precursor_mz-mzs) <= mz_tolerance) & (mzs != precursor_mz))
     new_mzs, new_intensities = mzs[~peaks_to_remove], intensities[~peaks_to_remove]
     spectrum.peaks = Spikes(mz=new_mzs, intensities=new_intensities)
diff --git a/matchms/filtering/remove_peaks_outside_top_k.py b/matchms/filtering/remove_peaks_outside_top_k.py
index b1715d18..44f9ce1b 100644
--- a/matchms/filtering/remove_peaks_outside_top_k.py
+++ b/matchms/filtering/remove_peaks_outside_top_k.py
@@ -26,7 +26,7 @@ def remove_peaks_outside_top_k(spectrum_in: SpectrumType, k: int = 6,
 
     assert k >= 1, "k must be a positive nonzero integer."
     assert mz_window >= 0, "mz_window must be a positive scalar."
-    mzs, intensities = spectrum.peaks
+    mzs, intensities = spectrum.peaks.mz, spectrum.peaks.intensities
     top_k = intensities.argsort()[::-1][0:k]
     k_ordered_mzs = mzs[top_k]
     indices = [i for i in range(len(mzs)) if i not in top_k]


Test patch:
diff --git a/tests/test_spikes.py b/tests/test_spikes.py
index 920c5049..d5b6d314 100644
--- a/tests/test_spikes.py
+++ b/tests/test_spikes.py
@@ -83,17 +83,16 @@ def test_spikes_dot_clone():
     assert peaks is not peaks_cloned
 
 
-def test_spikes_unpack():
+def test_spikes_getitem():
 
     mz = numpy.array([10, 20, 30], dtype="float")
     intensities = numpy.array([100, 20, 300], dtype="float")
 
     peaks = Spikes(mz=mz, intensities=intensities)
 
-    mz_unpacked, intensities_unpacked = peaks
-
-    assert numpy.allclose(mz, mz_unpacked)
-    assert numpy.allclose(intensities, intensities_unpacked)
+    assert numpy.allclose(peaks[1], numpy.array(mz[1], intensities[1]))
+    assert numpy.allclose(peaks[:],
+                          numpy.stack((peaks.mz, peaks.intensities)))
 
 
 def test_spikes_to_numpy():