imspy-core 0.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- imspy_core/__init__.py +75 -0
- imspy_core/chemistry/__init__.py +37 -0
- imspy_core/chemistry/amino_acids.py +7 -0
- imspy_core/chemistry/constants.py +12 -0
- imspy_core/chemistry/elements.py +6 -0
- imspy_core/chemistry/mobility.py +82 -0
- imspy_core/chemistry/sum_formula.py +38 -0
- imspy_core/chemistry/unimod.py +5 -0
- imspy_core/chemistry/utility.py +43 -0
- imspy_core/core/__init__.py +9 -0
- imspy_core/core/base.py +38 -0
- imspy_core/data/__init__.py +17 -0
- imspy_core/data/peptide.py +528 -0
- imspy_core/data/spectrum.py +586 -0
- imspy_core/timstof/__init__.py +25 -0
- imspy_core/timstof/collision.py +31 -0
- imspy_core/timstof/data.py +429 -0
- imspy_core/timstof/dda.py +364 -0
- imspy_core/timstof/dia.py +131 -0
- imspy_core/timstof/frame.py +604 -0
- imspy_core/timstof/quadrupole.py +189 -0
- imspy_core/timstof/slice.py +506 -0
- imspy_core/utility/__init__.py +21 -0
- imspy_core/utility/sequence.py +38 -0
- imspy_core/utility/utilities.py +278 -0
- imspy_core-0.4.0.dist-info/METADATA +70 -0
- imspy_core-0.4.0.dist-info/RECORD +28 -0
- imspy_core-0.4.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
from typing import Union, List
|
|
2
|
+
|
|
3
|
+
from imspy_core.data.spectrum import MzSpectrum
|
|
4
|
+
from imspy_core.timstof.frame import TimsFrame
|
|
5
|
+
from numpy.typing import NDArray
|
|
6
|
+
|
|
7
|
+
import imspy_connector
|
|
8
|
+
ims = imspy_connector.py_quadrupole
|
|
9
|
+
|
|
10
|
+
class PasefMeta:
|
|
11
|
+
def __init__(self, frame: int, scan_start: int, scan_end: int, isolation_mz: float, isolation_width: float,
|
|
12
|
+
collision_energy: float, precursor: int):
|
|
13
|
+
self.__py_ptr = ims.PyPasefMeta(frame, scan_start, scan_end, isolation_mz, isolation_width, collision_energy, precursor)
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def frame(self) -> int:
|
|
17
|
+
return self.__py_ptr.frame
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def scan_start(self) -> int:
|
|
21
|
+
return self.__py_ptr.scan_start
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def scan_end(self) -> int:
|
|
25
|
+
return self.__py_ptr.scan_end
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def isolation_mz(self) -> float:
|
|
29
|
+
return self.__py_ptr.isolation_mz
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def isolation_width(self) -> float:
|
|
33
|
+
return self.__py_ptr.isolation_width
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def collision_energy(self) -> float:
|
|
37
|
+
return self.__py_ptr.collision_energy
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def precursor(self) -> int:
|
|
41
|
+
return self.__py_ptr.precursor
|
|
42
|
+
|
|
43
|
+
def __repr__(self):
|
|
44
|
+
return f"PasefMeta(frame={self.frame}, scan_start={self.scan_start}, scan_end={self.scan_end}, " \
|
|
45
|
+
f"isolation_mz={self.isolation_mz}, isolation_width={self.isolation_width}, " \
|
|
46
|
+
f"collision_energy={self.collision_energy}, precursor={self.precursor})"
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
def from_py_ptr(cls, py_ptr):
|
|
50
|
+
self = cls.__new__(cls)
|
|
51
|
+
self.__py_ptr = py_ptr
|
|
52
|
+
return self
|
|
53
|
+
|
|
54
|
+
def get_py_ptr(self):
|
|
55
|
+
return self.__py_ptr
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class TimsTofQuadrupoleDDA:
|
|
59
|
+
def __init__(self, pasef_meta: List[PasefMeta], k: float | None = None):
|
|
60
|
+
self.__py_ptr = ims.PyTimsTransmissionDDA(
|
|
61
|
+
[pasef_meta[i].get_py_ptr() for i in range(len(pasef_meta))], k
|
|
62
|
+
)
|
|
63
|
+
def apply_transmission(self, frame_id: int, scan_id: int, mz: NDArray) -> NDArray:
|
|
64
|
+
return self.__py_ptr.apply_transmission(frame_id, scan_id, mz)
|
|
65
|
+
|
|
66
|
+
def transmit_spectrum(self, frame_id: int, scan_id: int, spectrum: MzSpectrum, min_probability: float | None = None) -> MzSpectrum:
|
|
67
|
+
return MzSpectrum.from_py_ptr(self.__py_ptr.transmit_spectrum(frame_id, scan_id, spectrum.get_py_ptr(), min_probability))
|
|
68
|
+
|
|
69
|
+
def transmit_frame(self, frame: TimsFrame, min_probability: float | None = None) -> TimsFrame:
|
|
70
|
+
return TimsFrame.from_py_ptr(self.__py_ptr.transmit_tims_frame(frame.get_py_ptr(), min_probability))
|
|
71
|
+
|
|
72
|
+
def transmit_ion(self, frames: NDArray, scans: NDArray, spectrum: MzSpectrum, min_probability: float | None = None) -> List[List[MzSpectrum]]:
|
|
73
|
+
transmission_profile = self.__py_ptr.transmit_ion(frames, scans, spectrum.get_py_ptr(), min_probability)
|
|
74
|
+
result = []
|
|
75
|
+
for i in enumerate(frames):
|
|
76
|
+
scan_list = []
|
|
77
|
+
for j in enumerate(scans):
|
|
78
|
+
scan_list.append(MzSpectrum.from_py_ptr(transmission_profile[i][j]))
|
|
79
|
+
result.append(scan_list)
|
|
80
|
+
|
|
81
|
+
return result
|
|
82
|
+
|
|
83
|
+
def is_transmitted(self, frame_id: int, scan_id: int, mz: float, min_probability: float | None = None) -> bool:
|
|
84
|
+
return self.__py_ptr.is_transmitted(frame_id, scan_id, mz, min_probability)
|
|
85
|
+
|
|
86
|
+
def any_transmitted(self, frame_id: int, scan_id: int, mz: NDArray, min_probability: float | None = None) -> bool:
|
|
87
|
+
return self.__py_ptr.any_transmitted(frame_id, scan_id, mz, min_probability)
|
|
88
|
+
|
|
89
|
+
def all_transmitted(self, frame_id: int, scan_id: int, mz: NDArray, min_probability: float | None) -> bool:
|
|
90
|
+
return self.__py_ptr.all_transmitted(frame_id, scan_id, mz, min_probability)
|
|
91
|
+
|
|
92
|
+
def get_transmission_set(self, frame_id: int, scan_id: int, mz: NDArray, min_probability: float | None) -> set[int]:
|
|
93
|
+
return self.__py_ptr.get_transmission_set(frame_id, scan_id, mz, min_probability)
|
|
94
|
+
|
|
95
|
+
def isotopes_transmitted(self, frame_id: int, scan_id: int, mz_mono: float, mz: NDArray, min_probability: float | None) -> tuple[float, list[tuple[float, float]]]:
|
|
96
|
+
return self.__py_ptr.isotopes_transmitted(frame_id, scan_id, mz_mono, mz, min_probability)
|
|
97
|
+
|
|
98
|
+
def __repr__(self):
|
|
99
|
+
return f"TimsTofQuadrupoleDDA()"
|
|
100
|
+
|
|
101
|
+
@classmethod
|
|
102
|
+
def from_py_ptr(cls, py_ptr):
|
|
103
|
+
self = cls.__new__(cls)
|
|
104
|
+
self.__py_ptr = py_ptr
|
|
105
|
+
return self
|
|
106
|
+
|
|
107
|
+
def get_py_ptr(self):
|
|
108
|
+
return self.__py_ptr
|
|
109
|
+
|
|
110
|
+
class TimsTofQuadrupoleDIA:
|
|
111
|
+
def __init__(self, frame: NDArray, frame_window_group: NDArray, window_group: NDArray, scan_start: NDArray,
|
|
112
|
+
scan_end: NDArray, isolation_mz: NDArray, isolation_width: NDArray, k: float | None = None):
|
|
113
|
+
self.handle = ims.PyTimsTransmissionDIA(
|
|
114
|
+
frame, frame_window_group, window_group, scan_start, scan_end, isolation_mz, isolation_width, k
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
def apply_transmission(self, frame_id: int, scan_id: int, mz: NDArray) -> NDArray:
|
|
118
|
+
return self.handle.apply_transmission(frame_id, scan_id, mz)
|
|
119
|
+
|
|
120
|
+
def transmit_spectrum(self, frame_id: int, scan_id: int, spectrum: MzSpectrum,
|
|
121
|
+
min_probability: float | None = None) -> MzSpectrum:
|
|
122
|
+
return MzSpectrum.from_py_ptr(self.handle.transmit_spectrum(frame_id, scan_id,
|
|
123
|
+
spectrum.get_py_ptr(), min_probability))
|
|
124
|
+
|
|
125
|
+
def transmit_frame(self, frame: TimsFrame, min_probability: float | None = None) -> TimsFrame:
|
|
126
|
+
return TimsFrame.from_py_ptr(self.handle.transmit_tims_frame(frame.get_py_ptr(), min_probability))
|
|
127
|
+
|
|
128
|
+
def frame_to_window_group(self, frame_id: int) -> int:
|
|
129
|
+
return self.handle.frame_to_window_group(frame_id)
|
|
130
|
+
|
|
131
|
+
def is_transmitted(self, frame_id: int, scan_id: int, mz: float, min_proba: float | None = None) -> bool:
|
|
132
|
+
return self.handle.is_transmitted(frame_id, scan_id, mz, min_proba)
|
|
133
|
+
|
|
134
|
+
def any_transmitted(self, frame_id: int, scan_id: int, mz: NDArray, min_proba: float | None = None) -> bool:
|
|
135
|
+
return self.handle.any_transmitted(frame_id, scan_id, mz, min_proba)
|
|
136
|
+
|
|
137
|
+
def all_transmitted(self, frame_id: int, scan_id: int, mz: NDArray, min_proba: float | None = None) -> bool:
|
|
138
|
+
return self.handle.all_transmitted(frame_id, scan_id, mz, min_proba)
|
|
139
|
+
|
|
140
|
+
def get_transmission_set(self, frame_id: int, scan_id: int, mz: NDArray, min_proba: float | None = None) -> set[int]:
|
|
141
|
+
return self.handle.get_transmission_set(frame_id, scan_id, mz, min_proba)
|
|
142
|
+
|
|
143
|
+
def transmit_ion(self, frame_ids: NDArray, scan_ids: NDArray, spectrum: MzSpectrum, min_probability: Union[float, None]) -> List[List[MzSpectrum]]:
|
|
144
|
+
transmission_profile = self.handle.transmit_ion(frame_ids, scan_ids, spectrum.get_py_ptr(), min_probability)
|
|
145
|
+
result = []
|
|
146
|
+
for i in enumerate(frame_ids):
|
|
147
|
+
scan_list = []
|
|
148
|
+
for j in enumerate(scan_ids):
|
|
149
|
+
scan_list.append(MzSpectrum.from_py_ptr(transmission_profile[i][j]))
|
|
150
|
+
result.append(scan_list)
|
|
151
|
+
|
|
152
|
+
return result
|
|
153
|
+
|
|
154
|
+
def is_precursor(self, frame_id: int) -> bool:
|
|
155
|
+
return self.handle.is_precursor(frame_id)
|
|
156
|
+
|
|
157
|
+
def isotopes_transmitted(
|
|
158
|
+
self,
|
|
159
|
+
frame_id: int,
|
|
160
|
+
scan_id: int,
|
|
161
|
+
mz_mono: float,
|
|
162
|
+
mz: NDArray,
|
|
163
|
+
min_proba: float | None = None
|
|
164
|
+
) -> tuple[float, list[tuple[float, float]]]:
|
|
165
|
+
"""
|
|
166
|
+
Get the transmission probability for a list of isotopes
|
|
167
|
+
Args:
|
|
168
|
+
frame_id:
|
|
169
|
+
scan_id:
|
|
170
|
+
mz_mono:
|
|
171
|
+
mz:
|
|
172
|
+
min_proba:
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
|
|
176
|
+
"""
|
|
177
|
+
return self.handle.isotopes_transmitted(frame_id, scan_id, mz_mono, mz, min_proba)
|
|
178
|
+
|
|
179
|
+
def __repr__(self):
|
|
180
|
+
return f"TimsTofQuadrupoleDIA()"
|
|
181
|
+
|
|
182
|
+
@classmethod
|
|
183
|
+
def from_py_ptr(cls, py_ptr):
|
|
184
|
+
self = cls.__new__(cls)
|
|
185
|
+
self.handle = py_ptr
|
|
186
|
+
return self
|
|
187
|
+
|
|
188
|
+
def get_py_ptr(self):
|
|
189
|
+
return self.handle
|
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from typing import List
|
|
4
|
+
|
|
5
|
+
from numpy.typing import NDArray
|
|
6
|
+
|
|
7
|
+
from imspy_core.utility.utilities import re_index_indices
|
|
8
|
+
from imspy_core.timstof.frame import TimsFrame, TimsFrameVectorized
|
|
9
|
+
from imspy_core.data.spectrum import TimsSpectrum
|
|
10
|
+
|
|
11
|
+
import imspy_connector
|
|
12
|
+
ims = imspy_connector.py_tims_slice
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TimsSlice:
|
|
16
|
+
def __init__(self,
|
|
17
|
+
frame_id: NDArray[np.int32],
|
|
18
|
+
scan: NDArray[np.int32],
|
|
19
|
+
tof: NDArray[np.int32],
|
|
20
|
+
retention_time: NDArray[np.float64],
|
|
21
|
+
mobility: NDArray[np.float64],
|
|
22
|
+
mz: NDArray[np.float64],
|
|
23
|
+
intensity: NDArray[np.float64]):
|
|
24
|
+
"""Create a TimsSlice.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
frame_id (NDArray[np.int32]): Frame ID.
|
|
28
|
+
scan (NDArray[np.int32]): Scan.
|
|
29
|
+
tof (NDArray[np.int32]): TOF.
|
|
30
|
+
retention_time (NDArray[np.float64]): Retention time.
|
|
31
|
+
mobility (NDArray[np.float64]): Mobility.
|
|
32
|
+
mz (NDArray[np.float64]): m/z.
|
|
33
|
+
intensity (NDArray[np.float64]): Intensity.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
assert len(frame_id) == len(scan) == len(tof) == len(retention_time) == len(mobility) == len(mz) == len(
|
|
37
|
+
intensity), "All arrays must have the same length."
|
|
38
|
+
|
|
39
|
+
self.__slice_ptr = ims.PyTimsSlice(
|
|
40
|
+
frame_id, scan, tof, retention_time, mobility, mz, intensity
|
|
41
|
+
)
|
|
42
|
+
self.__current_index = 0
|
|
43
|
+
|
|
44
|
+
@classmethod
|
|
45
|
+
def from_py_tims_slice(cls, tims_slice: ims.PyTimsSlice):
|
|
46
|
+
"""Create a TimsSlice from a PyTimsSlice.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
tims_slice (pims.PyTimsSlice): PyTimsSlice to create the TimsSlice from.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
TimsSlice: TimsSlice created from the PyTimsSlice.
|
|
53
|
+
"""
|
|
54
|
+
instance = cls.__new__(cls)
|
|
55
|
+
instance.__slice_ptr = tims_slice
|
|
56
|
+
instance.__current_index = 0
|
|
57
|
+
return instance
|
|
58
|
+
|
|
59
|
+
@classmethod
|
|
60
|
+
def from_frames(cls, frames: List[TimsFrame]):
|
|
61
|
+
"""Create a TimsSlice from a list of TimsFrames.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
frames (List[TimsFrame]): List of TimsFrames.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
TimsSlice: TimsSlice created from the list of TimsFrames.
|
|
68
|
+
"""
|
|
69
|
+
return cls.from_py_tims_slice(ims.PyTimsSlice.from_frames([frame.get_py_ptr() for frame in frames]))
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def first_frame_id(self) -> int:
|
|
73
|
+
"""First frame ID.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
int: First frame ID.
|
|
77
|
+
"""
|
|
78
|
+
return self.__slice_ptr.first_frame_id
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def last_frame_id(self) -> int:
|
|
82
|
+
"""Last frame ID.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
int: Last frame ID.
|
|
86
|
+
"""
|
|
87
|
+
return self.__slice_ptr.last_frame_id
|
|
88
|
+
|
|
89
|
+
def __repr__(self):
|
|
90
|
+
return f"TimsSlice({self.first_frame_id}, {self.last_frame_id})"
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def precursors(self):
|
|
94
|
+
return TimsSlice.from_py_tims_slice(self.__slice_ptr.get_precursors())
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def fragments(self):
|
|
98
|
+
return TimsSlice.from_py_tims_slice(self.__slice_ptr.get_fragments_dda())
|
|
99
|
+
|
|
100
|
+
def filter(self, mz_min: float = 0.0, mz_max: float = 2000.0, scan_min: int = 0, scan_max: int = 1000,
|
|
101
|
+
mobility_min: float = 0.0,
|
|
102
|
+
mobility_max: float = 2.0,
|
|
103
|
+
intensity_min: float = 0.0, intensity_max: float = 1e9, num_threads: int = 4) -> 'TimsSlice':
|
|
104
|
+
"""Filter the slice by m/z, scan and intensity.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
mz_min (float): Minimum m/z value.
|
|
108
|
+
mz_max (float): Maximum m/z value.
|
|
109
|
+
scan_min (int, optional): Minimum scan value. Defaults to 0.
|
|
110
|
+
scan_max (int, optional): Maximum scan value. Defaults to 1000.
|
|
111
|
+
mobility_min (float, optional): Minimum inverse mobility value. Defaults to 0.0.
|
|
112
|
+
mobility_max (float, optional): Maximum inverse mobility value. Defaults to 2.0.
|
|
113
|
+
intensity_min (float, optional): Minimum intensity value. Defaults to 0.0.
|
|
114
|
+
intensity_max (float, optional): Maximum intensity value. Defaults to 1e9.
|
|
115
|
+
num_threads (int, optional): Number of threads to use. Defaults to 4.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
TimsSlice: Filtered slice.
|
|
119
|
+
"""
|
|
120
|
+
return TimsSlice.from_py_tims_slice(
|
|
121
|
+
self.__slice_ptr.filter_ranged(mz_min, mz_max, scan_min, scan_max, mobility_min, mobility_max,
|
|
122
|
+
intensity_min, intensity_max, num_threads))
|
|
123
|
+
|
|
124
|
+
def filter_by_type(self,
|
|
125
|
+
mz_min_ms1: float = 0,
|
|
126
|
+
mz_max_ms1: float = 2000,
|
|
127
|
+
scan_min_ms1: int = 0,
|
|
128
|
+
scan_max_ms1: int = 1000,
|
|
129
|
+
inv_mob_min_ms1: float = 0,
|
|
130
|
+
inv_mob_max_ms1: float = 2,
|
|
131
|
+
intensity_min_ms1: float = 0,
|
|
132
|
+
intensity_max_ms1: float = 1e9,
|
|
133
|
+
mz_min_ms2: float = 0,
|
|
134
|
+
mz_max_ms2: float = 2000,
|
|
135
|
+
scan_min_ms2: int = 0,
|
|
136
|
+
scan_max_ms2: int = 1000,
|
|
137
|
+
inv_mob_min_ms2: float = 0,
|
|
138
|
+
inv_mob_max_ms2: float = 2,
|
|
139
|
+
intensity_min_ms2: float = 0,
|
|
140
|
+
intensity_max_ms2: float = 1e9,
|
|
141
|
+
num_threads: int = 4) -> 'TimsSlice':
|
|
142
|
+
|
|
143
|
+
"""Filter the slice by m/z, scan and intensity, for MS1 and MS2 with different ranges.
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
mz_min_ms1 (float, optional): Minimum m/z value for MS1. Defaults to 0.
|
|
147
|
+
mz_max_ms1 (float, optional): Maximum m/z value for MS1. Defaults to 2000.
|
|
148
|
+
scan_min_ms1 (int, optional): Minimum scan value for MS1. Defaults to 0.
|
|
149
|
+
scan_max_ms1 (int, optional): Maximum scan value for MS1. Defaults to 1000.
|
|
150
|
+
inv_mob_min_ms1 (float, optional): Minimum inverse mobility value for MS1. Defaults to 0.
|
|
151
|
+
inv_mob_max_ms1 (float, optional): Maximum inverse mobility value for MS1. Defaults to 2.
|
|
152
|
+
intensity_min_ms1 (float, optional): Minimum intensity value for MS1. Defaults to 0.
|
|
153
|
+
intensity_max_ms1 (float, optional): Maximum intensity value for MS1. Defaults to 1e9.
|
|
154
|
+
mz_min_ms2 (float, optional): Minimum m/z value for MS2. Defaults to 0.
|
|
155
|
+
mz_max_ms2 (float, optional): Maximum m/z value for MS2. Defaults to 2000.
|
|
156
|
+
scan_min_ms2 (int, optional): Minimum scan value for MS2. Defaults to 0.
|
|
157
|
+
scan_max_ms2 (int, optional): Maximum scan value for MS2. Defaults to 1000.
|
|
158
|
+
inv_mob_min_ms2 (float, optional): Minimum inverse mobility value for MS2. Defaults to 0.
|
|
159
|
+
inv_mob_max_ms2 (float, optional): Maximum inverse mobility value for MS2. Defaults to 2.
|
|
160
|
+
intensity_min_ms2 (float, optional): Minimum intensity value for MS2. Defaults to 0.
|
|
161
|
+
intensity_max_ms2 (float, optional): Maximum intensity value for MS2. Defaults to 1e9.
|
|
162
|
+
num_threads (int, optional): Number of threads to use. Defaults to 4.
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
TimsSlice: Filtered slice.
|
|
166
|
+
"""
|
|
167
|
+
return TimsSlice.from_py_tims_slice(
|
|
168
|
+
self.__slice_ptr.filter_ranged_ms_type_specific(
|
|
169
|
+
mz_min_ms1, mz_max_ms1, scan_min_ms1, scan_max_ms1, inv_mob_min_ms1,
|
|
170
|
+
inv_mob_max_ms1, intensity_min_ms1, intensity_max_ms1, mz_min_ms2, mz_max_ms2,
|
|
171
|
+
scan_min_ms2, scan_max_ms2, inv_mob_min_ms2, inv_mob_max_ms2, intensity_min_ms2,
|
|
172
|
+
intensity_max_ms2, num_threads))
|
|
173
|
+
|
|
174
|
+
@property
|
|
175
|
+
def frames(self) -> List[TimsFrame]:
|
|
176
|
+
"""Get the frames.
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
List[TimsFrame]: Frames.
|
|
180
|
+
"""
|
|
181
|
+
return [TimsFrame.from_py_ptr(frame) for frame in self.__slice_ptr.get_frames()]
|
|
182
|
+
|
|
183
|
+
def to_resolution(self, resolution: int, num_threads: int = 4) -> 'TimsSlice':
|
|
184
|
+
"""Convert the slice to a given resolution.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
resolution (int): Resolution.
|
|
188
|
+
num_threads (int, optional): Number of threads to use. Defaults to 4.
|
|
189
|
+
|
|
190
|
+
Returns:
|
|
191
|
+
TimsSlice: Slice with given resolution.
|
|
192
|
+
"""
|
|
193
|
+
return TimsSlice.from_py_tims_slice(self.__slice_ptr.to_resolution(resolution, num_threads))
|
|
194
|
+
|
|
195
|
+
def to_windows(self, window_length: float = 10, overlapping: bool = True, min_num_peaks: int = 5,
|
|
196
|
+
min_intensity: float = 1, num_threads: int = 4) -> List[TimsSpectrum]:
|
|
197
|
+
"""Convert the slice to a list of windows.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
window_length (float, optional): Window length. Defaults to 10.
|
|
201
|
+
overlapping (bool, optional): Whether the windows should overlap. Defaults to True.
|
|
202
|
+
min_num_peaks (int, optional): Minimum number of peaks in a window. Defaults to 5.
|
|
203
|
+
min_intensity (float, optional): Minimum intensity of a peak in a window. Defaults to 1.
|
|
204
|
+
num_threads (int, optional): Number of threads to use. Defaults to 1.
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
List[MzSpectrum]: List of windows.
|
|
208
|
+
"""
|
|
209
|
+
return [TimsSpectrum.from_py_tims_spectrum(spec) for spec in self.__slice_ptr.to_windows(
|
|
210
|
+
window_length, overlapping, min_num_peaks, min_intensity, num_threads)]
|
|
211
|
+
|
|
212
|
+
def to_dense_windows(self, window_length: float = 10, resolution: int = 1, overlapping: bool = True,
|
|
213
|
+
min_num_peaks: int = 5, min_intensity: float = 0.0, num_theads: int = 4) -> (
|
|
214
|
+
tuple)[list[NDArray], list[NDArray], list[NDArray]]:
|
|
215
|
+
|
|
216
|
+
DW = self.__slice_ptr.to_dense_windows(window_length, overlapping, min_num_peaks, min_intensity, resolution,
|
|
217
|
+
num_theads)
|
|
218
|
+
|
|
219
|
+
scan_list, window_indices_list, values_list = [], [], []
|
|
220
|
+
|
|
221
|
+
for values, scans, bins, row, col in DW:
|
|
222
|
+
W = np.reshape(values, (row, col))
|
|
223
|
+
scan_list.append(scans)
|
|
224
|
+
window_indices_list.append(bins)
|
|
225
|
+
values_list.append(W)
|
|
226
|
+
|
|
227
|
+
return scan_list, window_indices_list, values_list
|
|
228
|
+
|
|
229
|
+
@property
|
|
230
|
+
def df(self) -> pd.DataFrame:
|
|
231
|
+
"""Get the data as a pandas DataFrame.
|
|
232
|
+
|
|
233
|
+
Returns:
|
|
234
|
+
pd.DataFrame: Data.
|
|
235
|
+
"""
|
|
236
|
+
columns = ['frame', 'scan', 'tof', 'retention_time', 'mobility', 'mz', 'intensity']
|
|
237
|
+
return pd.DataFrame({c: v for c, v in zip(columns, self.__slice_ptr.to_arrays())})
|
|
238
|
+
|
|
239
|
+
def __iter__(self):
|
|
240
|
+
return self
|
|
241
|
+
|
|
242
|
+
def __next__(self):
|
|
243
|
+
if self.__current_index < self.__slice_ptr.frame_count:
|
|
244
|
+
frame_ptr = self.__slice_ptr.get_frame_at_index(self.__current_index)
|
|
245
|
+
self.__current_index += 1
|
|
246
|
+
if frame_ptr is not None:
|
|
247
|
+
return TimsFrame.from_py_ptr(frame_ptr)
|
|
248
|
+
else:
|
|
249
|
+
raise ValueError("Frame pointer is None for valid index.")
|
|
250
|
+
else:
|
|
251
|
+
self.__current_index = 0 # Reset for next iteration
|
|
252
|
+
raise StopIteration
|
|
253
|
+
|
|
254
|
+
def vectorized(self, resolution: int = 2, num_threads: int = 4) -> 'TimsSliceVectorized':
|
|
255
|
+
"""Get a vectorized version of the slice.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
resolution (int, optional): Resolution. Defaults to 2.
|
|
259
|
+
num_threads (int, optional): Number of threads to use. Defaults to 4.
|
|
260
|
+
|
|
261
|
+
Returns:
|
|
262
|
+
TimsSliceVectorized: Vectorized version of the slice.
|
|
263
|
+
"""
|
|
264
|
+
return TimsSliceVectorized.from_vectorized_py_tims_slice(self.__slice_ptr.vectorized(resolution, num_threads))
|
|
265
|
+
|
|
266
|
+
def get_tims_planes(self, tof_max_value: int = 400_000, num_chunks: int = 7, num_threads: int = 4) -> List[
|
|
267
|
+
'TimsPlane']:
|
|
268
|
+
return [TimsPlane.from_py_tims_plane(plane) for plane in
|
|
269
|
+
self.__slice_ptr.to_tims_planes(tof_max_value, num_chunks, num_threads)]
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
class TimsSliceVectorized:
|
|
273
|
+
def __init__(self):
|
|
274
|
+
self.__slice_ptr = None
|
|
275
|
+
self.__current_index = 0
|
|
276
|
+
|
|
277
|
+
@classmethod
|
|
278
|
+
def from_vectorized_py_tims_slice(cls, tims_slice: ims.PyTimsSliceVectorized):
|
|
279
|
+
"""Create a TimsSlice from a PyTimsSlice.
|
|
280
|
+
|
|
281
|
+
Args:
|
|
282
|
+
tims_slice (pims.PyTimsSlice): PyTimsSlice to create the TimsSlice from.
|
|
283
|
+
|
|
284
|
+
Returns:
|
|
285
|
+
TimsSlice: TimsSlice created from the PyTimsSlice.
|
|
286
|
+
"""
|
|
287
|
+
instance = cls.__new__(cls)
|
|
288
|
+
instance.__slice_ptr = tims_slice
|
|
289
|
+
instance.__current_index = 0
|
|
290
|
+
return instance
|
|
291
|
+
|
|
292
|
+
@property
|
|
293
|
+
def first_frame_id(self) -> int:
|
|
294
|
+
"""First frame ID.
|
|
295
|
+
|
|
296
|
+
Returns:
|
|
297
|
+
int: First frame ID.
|
|
298
|
+
"""
|
|
299
|
+
return self.__slice_ptr.first_frame_id
|
|
300
|
+
|
|
301
|
+
@property
|
|
302
|
+
def last_frame_id(self) -> int:
|
|
303
|
+
"""Last frame ID.
|
|
304
|
+
|
|
305
|
+
Returns:
|
|
306
|
+
int: Last frame ID.
|
|
307
|
+
"""
|
|
308
|
+
return self.__slice_ptr.last_frame_id
|
|
309
|
+
|
|
310
|
+
@property
|
|
311
|
+
def precursors(self):
|
|
312
|
+
return TimsSlice.from_py_tims_slice(self.__slice_ptr.get_precursors())
|
|
313
|
+
|
|
314
|
+
@property
|
|
315
|
+
def fragments(self):
|
|
316
|
+
return TimsSlice.from_py_tims_slice(self.__slice_ptr.get_fragments_dda())
|
|
317
|
+
|
|
318
|
+
@property
|
|
319
|
+
def frames(self) -> List[TimsFrameVectorized]:
|
|
320
|
+
"""Get the frames.
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
List[TimsFrame]: Frames.
|
|
324
|
+
"""
|
|
325
|
+
return [TimsFrameVectorized.from_py_ptr(frame) for frame in
|
|
326
|
+
self.__slice_ptr.get_vectorized_frames]
|
|
327
|
+
|
|
328
|
+
@property
|
|
329
|
+
def df(self) -> pd.DataFrame:
|
|
330
|
+
"""Get the data as a pandas DataFrame.
|
|
331
|
+
|
|
332
|
+
Returns:
|
|
333
|
+
pd.DataFrame: Data.
|
|
334
|
+
"""
|
|
335
|
+
columns = ['frame', 'scan', 'tof', 'retention_time', 'mobility', 'index', 'intensity']
|
|
336
|
+
return pd.DataFrame({c: v for c, v in zip(columns, self.__slice_ptr.to_arrays())})
|
|
337
|
+
|
|
338
|
+
def __iter__(self):
|
|
339
|
+
return self
|
|
340
|
+
|
|
341
|
+
def __next__(self):
|
|
342
|
+
if self.__current_index < self.__slice_ptr.frame_count:
|
|
343
|
+
frame_ptr = self.__slice_ptr.get_frame_at_index(self.__current_index)
|
|
344
|
+
self.__current_index += 1
|
|
345
|
+
if frame_ptr is not None:
|
|
346
|
+
return TimsFrameVectorized.from_py_ptr(frame_ptr)
|
|
347
|
+
else:
|
|
348
|
+
raise ValueError("Frame pointer is None for valid index.")
|
|
349
|
+
else:
|
|
350
|
+
self.__current_index = 0
|
|
351
|
+
raise StopIteration
|
|
352
|
+
|
|
353
|
+
def __repr__(self):
|
|
354
|
+
return f"TimsSliceVectorized({self.first_frame_id}, {self.last_frame_id})"
|
|
355
|
+
|
|
356
|
+
def get_tensor_repr(self, dense=True, zero_index=True, re_index=True, frame_max=None, scan_max=None,
|
|
357
|
+
index_max=None):
|
|
358
|
+
"""Get a tensor representation of the slice.
|
|
359
|
+
|
|
360
|
+
Note:
|
|
361
|
+
Requires tensorflow to be installed.
|
|
362
|
+
"""
|
|
363
|
+
try:
|
|
364
|
+
from tensorflow import sparse as sp
|
|
365
|
+
except ImportError:
|
|
366
|
+
raise ImportError(
|
|
367
|
+
"get_tensor_repr requires tensorflow. "
|
|
368
|
+
"Install it with: pip install tensorflow"
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
frames, scans, _, _, _, indices, intensities = self.__slice_ptr.to_arrays()
|
|
372
|
+
|
|
373
|
+
if zero_index:
|
|
374
|
+
scans = scans - np.min(scans)
|
|
375
|
+
frames = frames - np.min(frames)
|
|
376
|
+
indices = indices - np.min(indices)
|
|
377
|
+
|
|
378
|
+
if re_index:
|
|
379
|
+
frames = re_index_indices(frames)
|
|
380
|
+
|
|
381
|
+
if scan_max is None:
|
|
382
|
+
m_s = np.max(scans) + 1
|
|
383
|
+
else:
|
|
384
|
+
m_s = scan_max + 1
|
|
385
|
+
|
|
386
|
+
if index_max is None:
|
|
387
|
+
m_i = np.max(indices) + 1
|
|
388
|
+
else:
|
|
389
|
+
m_i = index_max + 1
|
|
390
|
+
|
|
391
|
+
if frame_max is None:
|
|
392
|
+
m_f = np.max(frames) + 1
|
|
393
|
+
else:
|
|
394
|
+
m_f = frame_max + 1
|
|
395
|
+
|
|
396
|
+
sv = sp.reorder(
|
|
397
|
+
sp.SparseTensor(indices=np.c_[frames, scans, indices], values=intensities, dense_shape=(m_f, m_s, m_i)))
|
|
398
|
+
|
|
399
|
+
if dense:
|
|
400
|
+
return sp.to_dense(sv)
|
|
401
|
+
else:
|
|
402
|
+
return sv
|
|
403
|
+
|
|
404
|
+
def filter(self, mz_min: float = 0.0, mz_max: float = 2000.0, scan_min: int = 0, scan_max: int = 1000,
|
|
405
|
+
mobility_min: float = 0.0,
|
|
406
|
+
mobility_max: float = 2.0,
|
|
407
|
+
intensity_min: float = 0.0, intensity_max: float = 1e9, num_threads: int = 4) -> 'TimsSliceVectorized':
|
|
408
|
+
"""Filter the slice by m/z, scan and intensity.
|
|
409
|
+
|
|
410
|
+
Args:
|
|
411
|
+
mz_min (float): Minimum m/z value.
|
|
412
|
+
mz_max (float): Maximum m/z value.
|
|
413
|
+
scan_min (int, optional): Minimum scan value. Defaults to 0.
|
|
414
|
+
scan_max (int, optional): Maximum scan value. Defaults to 1000.
|
|
415
|
+
mobility_min (float, optional): Minimum inverse mobility value. Defaults to 0.0.
|
|
416
|
+
mobility_max (float, optional): Maximum inverse mobility value. Defaults to 2.0.
|
|
417
|
+
intensity_min (float, optional): Minimum intensity value. Defaults to 0.0.
|
|
418
|
+
intensity_max (float, optional): Maximum intensity value. Defaults to 1e9.
|
|
419
|
+
num_threads (int, optional): Number of threads to use. Defaults to 4.
|
|
420
|
+
|
|
421
|
+
Returns:
|
|
422
|
+
TimsSlice: Filtered slice.
|
|
423
|
+
"""
|
|
424
|
+
return TimsSliceVectorized.from_vectorized_py_tims_slice(
|
|
425
|
+
self.__slice_ptr.filter_ranged(mz_min, mz_max, scan_min, scan_max, mobility_min, mobility_max,
|
|
426
|
+
intensity_min, intensity_max, num_threads))
|
|
427
|
+
|
|
428
|
+
def get_py_ptr(self):
|
|
429
|
+
return self.__slice_ptr
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
class TimsPlane:
|
|
433
|
+
def __init__(self):
|
|
434
|
+
self.__plane_ptr = None
|
|
435
|
+
|
|
436
|
+
@classmethod
|
|
437
|
+
def from_py_tims_plane(cls, plane: ims.PyTimsPlane):
|
|
438
|
+
"""Create a TimsPlane from a PyTimsPlane.
|
|
439
|
+
|
|
440
|
+
Args:
|
|
441
|
+
plane (pims.PyTimsPlane): PyTimsPlane to create the TimsPlane from.
|
|
442
|
+
|
|
443
|
+
Returns:
|
|
444
|
+
TimsPlane: TimsPlane created from the PyTimsPlane.
|
|
445
|
+
"""
|
|
446
|
+
instance = cls.__new__(cls)
|
|
447
|
+
instance.__plane_ptr = plane
|
|
448
|
+
return instance
|
|
449
|
+
|
|
450
|
+
@property
|
|
451
|
+
def mz_mean(self):
|
|
452
|
+
return self.__plane_ptr.mz_mean
|
|
453
|
+
|
|
454
|
+
@property
|
|
455
|
+
def mz_std(self):
|
|
456
|
+
return self.__plane_ptr.mz_std
|
|
457
|
+
|
|
458
|
+
@property
|
|
459
|
+
def tof_mean(self):
|
|
460
|
+
return self.__plane_ptr.tof_mean
|
|
461
|
+
|
|
462
|
+
@property
|
|
463
|
+
def tof_std(self):
|
|
464
|
+
return self.__plane_ptr.tof_std
|
|
465
|
+
|
|
466
|
+
@property
|
|
467
|
+
def frame_ids(self):
|
|
468
|
+
return self.__plane_ptr.frame_ids
|
|
469
|
+
|
|
470
|
+
@property
|
|
471
|
+
def scans(self):
|
|
472
|
+
return self.__plane_ptr.scans
|
|
473
|
+
|
|
474
|
+
@property
|
|
475
|
+
def intensities(self):
|
|
476
|
+
return self.__plane_ptr.intensity
|
|
477
|
+
|
|
478
|
+
@property
|
|
479
|
+
def retention_times(self):
|
|
480
|
+
return self.__plane_ptr.retention_times
|
|
481
|
+
|
|
482
|
+
@property
|
|
483
|
+
def mobilities(self):
|
|
484
|
+
return self.__plane_ptr.mobilities
|
|
485
|
+
|
|
486
|
+
@property
|
|
487
|
+
def num_points(self):
|
|
488
|
+
return len(self.frame_ids)
|
|
489
|
+
|
|
490
|
+
@property
|
|
491
|
+
def df(self):
|
|
492
|
+
return pd.DataFrame({
|
|
493
|
+
'frame': self.frame_ids,
|
|
494
|
+
'scan': self.scans,
|
|
495
|
+
'retention_time': self.retention_times,
|
|
496
|
+
'mobility': self.mobilities,
|
|
497
|
+
'intensity': self.intensities
|
|
498
|
+
})
|
|
499
|
+
|
|
500
|
+
def __repr__(self):
|
|
501
|
+
return (f"TimsPlane(mz_mean: "
|
|
502
|
+
f"{np.round(self.mz_mean, 4)}, "
|
|
503
|
+
f"mz_std: {np.round(self.mz_std, 4)},"
|
|
504
|
+
f" tof_mean: {np.round(self.tof_mean, 4)}, "
|
|
505
|
+
f"tof_std: {np.round(self.tof_std, 4)}, "
|
|
506
|
+
f"num_points: {len(self.frame_ids)})")
|