Source code for pyms.eic
"""
Class to model a subset of data from an Intensity Matrix.
"""
################################################################################
# #
# PyMassSpec software for processing of mass-spectrometry data #
# Copyright (C) 2020 Dominic Davis-Foster #
# #
# This program is free software; you can redistribute it and/or modify #
# it under the terms of the GNU General Public License version 2 as #
# published by the Free Software Foundation. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program; if not, write to the Free Software #
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #
# #
################################################################################
# stdlib
from typing import Iterable, List, Optional, Sequence, Union, cast
# 3rd party
import numpy
# this package
from pyms.IntensityMatrix import BaseIntensityMatrix, IntensityMatrix
from pyms.IonChromatogram import BasePeakChromatogram, ExtractedIonChromatogram, IonChromatogram
from pyms.Utils.Utils import is_number
__all__ = ["ExtractedIntensityMatrix", "build_extracted_intensity_matrix"]
[docs]class ExtractedIntensityMatrix(BaseIntensityMatrix):
"""
Represents an extracted subset of the chromatographic data.
:param time_list: Retention time values
:param mass_list: Binned mass values
:param intensity_array: List of lists of binned intensity values per scan
:authors: Dominic Davis-Foster
.. versionadded:: 2.3.0
"""
[docs] def get_ic_at_mass(self, mass: Optional[float] = None) -> IonChromatogram:
"""
Returns the ion chromatogram for the nearest binned mass to the specified mass.
If no mass value is given, the function returns the extracted ion chromatogram.
:param mass: Mass value of an ion chromatogram
:return: Ion chromatogram for given mass
:authors: Andrew Isaac, Vladimir Likic
"""
if mass is None:
return self.eic
elif not is_number(mass):
raise TypeError("'mass' must be a number")
if mass < self._min_mass or mass > self._max_mass:
print("min mass: ", self._min_mass, "max mass:", self._max_mass)
raise IndexError("mass is out of range")
ix = self.get_index_of_mass(mass)
return self.get_ic_at_index(ix)
@property
def eic(self) -> ExtractedIonChromatogram:
"""
Returns an :class:`~.IonChromatogram` object representing this EIC.
"""
intensity_list = []
for row in self._intensity_array:
intensity_list.append(sum(row))
return ExtractedIonChromatogram(numpy.array(intensity_list), self._time_list[:], self.mass_list)
@property
def bpc(self) -> IonChromatogram:
"""
Constructs a Base Peak Chromatogram from the data.
This represents the most intense ion
-- out of those used to create the :class:`~.ExtractedIntensityMatrix`
-- for each scan.
:authors: Dominic Davis-Foster
.. versionadded:: 2.3.0
"""
return BasePeakChromatogram(
[max(intensities) for intensities in self._intensity_array],
self._time_list[:],
)
[docs]def build_extracted_intensity_matrix(
im: IntensityMatrix,
masses: Sequence[Union[float, Iterable[float]]],
left_bound: float = 0.5,
right_bound: float = 0.5,
) -> ExtractedIntensityMatrix:
"""
Given an intensity matrix and a list of masses, construct a
:class:`~.ExtractedIntensityMatrix` for those masses.
The masses can either be:
* single masses (of type :class:`float`),
* an iterable of masses.
``left_bound`` and ``right_bound`` specify a range in which to include values for around each mass.
For example, a mass of ``169`` with bounds of ``0.3`` and ``0.7`` would include every mass
between ``168.7`` and ``169.7`` (inclusive on both sides).
Set the bounds to ``0`` to include only the given masses.
:param im:
:param masses:
:param left_bound:
:param right_bound:
""" # noqa: D400
flat_target_masses: List[float] = []
for mass in masses:
if is_number(mass):
mass = cast(float, mass)
flat_target_masses.append(mass)
elif isinstance(masses, (Sequence, Iterable, range)):
mass = cast(Union[Sequence, Iterable, range], mass)
flat_target_masses.extend(mass)
else:
raise NotImplementedError(f"Unsupported type '{type(mass)}'")
# get indices of all those masses, taking bounds into account.
indices = set()
for idx, mass in enumerate(im.mass_list):
for target_mass in flat_target_masses:
if (target_mass - left_bound) <= mass <= (target_mass + right_bound):
indices.add(idx)
# construct array of rt vs (intensity for each mass)
intensity_array = []
target_indices = sorted(indices)
for intensities in im._intensity_array:
intensities_for_scan = []
for idx in target_indices:
intensities_for_scan.append(intensities[idx])
intensity_array.append(intensities_for_scan)
# Construct the extracted intensity matrix
return ExtractedIntensityMatrix(
time_list=im.time_list,
mass_list=[im._mass_list[idx] for idx in target_indices],
intensity_array=intensity_array,
)