masster 0.2.5__py3-none-any.whl → 0.3.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.
Potentially problematic release.
This version of masster might be problematic. Click here for more details.
- masster/__init__.py +27 -27
- masster/_version.py +17 -17
- masster/chromatogram.py +497 -503
- masster/data/examples/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.featureXML +199787 -0
- masster/data/examples/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.sample5 +0 -0
- masster/logger.py +318 -244
- masster/sample/__init__.py +9 -9
- masster/sample/defaults/__init__.py +15 -15
- masster/sample/defaults/find_adducts_def.py +325 -325
- masster/sample/defaults/find_features_def.py +366 -366
- masster/sample/defaults/find_ms2_def.py +285 -285
- masster/sample/defaults/get_spectrum_def.py +314 -318
- masster/sample/defaults/sample_def.py +374 -378
- masster/sample/h5.py +1321 -1297
- masster/sample/helpers.py +833 -364
- masster/sample/lib.py +762 -0
- masster/sample/load.py +1220 -1187
- masster/sample/parameters.py +131 -131
- masster/sample/plot.py +1610 -1622
- masster/sample/processing.py +1402 -1416
- masster/sample/quant.py +209 -0
- masster/sample/sample.py +391 -387
- masster/sample/sample5_schema.json +181 -181
- masster/sample/save.py +737 -736
- masster/sample/sciex.py +1213 -0
- masster/spectrum.py +1287 -1319
- masster/study/__init__.py +9 -9
- masster/study/defaults/__init__.py +21 -19
- masster/study/defaults/align_def.py +267 -267
- masster/study/defaults/export_def.py +41 -40
- masster/study/defaults/fill_chrom_def.py +264 -264
- masster/study/defaults/fill_def.py +260 -0
- masster/study/defaults/find_consensus_def.py +256 -256
- masster/study/defaults/find_ms2_def.py +163 -163
- masster/study/defaults/integrate_chrom_def.py +225 -225
- masster/study/defaults/integrate_def.py +221 -0
- masster/study/defaults/merge_def.py +256 -0
- masster/study/defaults/study_def.py +272 -269
- masster/study/export.py +674 -287
- masster/study/h5.py +1398 -886
- masster/study/helpers.py +1650 -433
- masster/study/helpers_optimized.py +317 -0
- masster/study/load.py +1201 -1078
- masster/study/parameters.py +99 -99
- masster/study/plot.py +632 -645
- masster/study/processing.py +1057 -1046
- masster/study/save.py +149 -134
- masster/study/study.py +606 -522
- masster/study/study5_schema.json +247 -241
- {masster-0.2.5.dist-info → masster-0.3.0.dist-info}/METADATA +15 -10
- masster-0.3.0.dist-info/RECORD +59 -0
- {masster-0.2.5.dist-info → masster-0.3.0.dist-info}/licenses/LICENSE +661 -661
- masster-0.2.5.dist-info/RECORD +0 -50
- {masster-0.2.5.dist-info → masster-0.3.0.dist-info}/WHEEL +0 -0
- {masster-0.2.5.dist-info → masster-0.3.0.dist-info}/entry_points.txt +0 -0
masster/sample/sample.py
CHANGED
|
@@ -1,387 +1,391 @@
|
|
|
1
|
-
"""
|
|
2
|
-
sample.py
|
|
3
|
-
|
|
4
|
-
This module provides tools for processing and analyzing Data-Dependent Acquisition (DDA) mass spectrometry data.
|
|
5
|
-
It defines the `Sample` class, which offers methods to load, process, analyze, and visualize mass spectrometry data
|
|
6
|
-
from various file formats, including mzML, Thermo RAW, and Sciex WIFF formats.
|
|
7
|
-
|
|
8
|
-
Key Features:
|
|
9
|
-
- **File Handling**: Load and save data in multiple formats.
|
|
10
|
-
- **Feature Detection**: Detect and process mass spectrometry features.
|
|
11
|
-
- **Spectrum Analysis**: Retrieve and analyze MS1/MS2 spectra.
|
|
12
|
-
- **Visualization**: Generate interactive and static plots for spectra and chromatograms.
|
|
13
|
-
- **Statistics**: Compute and export detailed DDA run statistics.
|
|
14
|
-
|
|
15
|
-
Dependencies:
|
|
16
|
-
- `pyopenms`: For file handling and feature detection.
|
|
17
|
-
- `polars` and `pandas`: For data manipulation.
|
|
18
|
-
- `numpy`: For numerical computations.
|
|
19
|
-
- `bokeh`, `panel`, `holoviews`, `datashader`: For interactive visualizations.
|
|
20
|
-
|
|
21
|
-
Classes:
|
|
22
|
-
- `Sample`: Main class for handling DDA data, providing methods for data import, processing, and visualization.
|
|
23
|
-
|
|
24
|
-
Example Usage:
|
|
25
|
-
```python
|
|
26
|
-
from masster.sample import Sample
|
|
27
|
-
|
|
28
|
-
sample = Sample(file="example.mzML")
|
|
29
|
-
sample.find_features()
|
|
30
|
-
sample.plot_2d()
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
|
-
import importlib
|
|
36
|
-
import os
|
|
37
|
-
import sys
|
|
38
|
-
|
|
39
|
-
import polars as pl
|
|
40
|
-
|
|
41
|
-
from masster._version import get_version
|
|
42
|
-
|
|
43
|
-
from masster.sample.defaults.sample_def import sample_defaults
|
|
44
|
-
|
|
45
|
-
# Sample-specific imports
|
|
46
|
-
from masster.sample.h5 import _load_sample5
|
|
47
|
-
from masster.sample.h5 import _save_sample5
|
|
48
|
-
from masster.sample.helpers import _delete_ms2
|
|
49
|
-
from masster.sample.helpers import
|
|
50
|
-
from masster.sample.helpers import
|
|
51
|
-
from masster.sample.helpers import
|
|
52
|
-
from masster.sample.helpers import
|
|
53
|
-
from masster.sample.helpers import
|
|
54
|
-
from masster.sample.helpers import
|
|
55
|
-
from masster.sample.helpers import
|
|
56
|
-
from masster.sample.
|
|
57
|
-
from masster.sample.
|
|
58
|
-
from masster.sample.
|
|
59
|
-
from masster.sample.
|
|
60
|
-
from masster.sample.
|
|
61
|
-
from masster.sample.load import
|
|
62
|
-
from masster.sample.load import
|
|
63
|
-
from masster.sample.load import
|
|
64
|
-
from masster.sample.load import
|
|
65
|
-
from masster.
|
|
66
|
-
from masster.sample.
|
|
67
|
-
from masster.sample.
|
|
68
|
-
from masster.sample.
|
|
69
|
-
from masster.sample.
|
|
70
|
-
from masster.
|
|
71
|
-
from masster.sample.plot import
|
|
72
|
-
from masster.sample.plot import
|
|
73
|
-
from masster.sample.plot import
|
|
74
|
-
from masster.sample.
|
|
75
|
-
from masster.sample.
|
|
76
|
-
from masster.sample.
|
|
77
|
-
from masster.sample.
|
|
78
|
-
from masster.sample.
|
|
79
|
-
from masster.sample.processing import
|
|
80
|
-
from masster.sample.processing import
|
|
81
|
-
from masster.sample.processing import
|
|
82
|
-
from masster.sample.processing import
|
|
83
|
-
from masster.sample.
|
|
84
|
-
from masster.sample.
|
|
85
|
-
from masster.sample.
|
|
86
|
-
from masster.sample.
|
|
87
|
-
from masster.sample.
|
|
88
|
-
from masster.sample.
|
|
89
|
-
from masster.sample.
|
|
90
|
-
from masster.sample.
|
|
91
|
-
from masster.sample.
|
|
92
|
-
from masster.sample.
|
|
93
|
-
from masster.sample.save import
|
|
94
|
-
from masster.sample.save import
|
|
95
|
-
from masster.sample.save import
|
|
96
|
-
from masster.sample.save import
|
|
97
|
-
from masster.sample.save import
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
-
|
|
126
|
-
-
|
|
127
|
-
-
|
|
128
|
-
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
if
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
self.
|
|
156
|
-
self.
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
self.
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
self.
|
|
182
|
-
|
|
183
|
-
self.
|
|
184
|
-
# the polars data frame with
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
#
|
|
188
|
-
self.
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
self.logger.
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
# Reload all discovered modules
|
|
334
|
-
for full_module_name in all_modules_to_reload:
|
|
335
|
-
try:
|
|
336
|
-
if full_module_name in sys.modules:
|
|
337
|
-
mod = sys.modules[full_module_name]
|
|
338
|
-
importlib.reload(mod)
|
|
339
|
-
self.logger.debug(f"Reloaded module: {full_module_name}")
|
|
340
|
-
except Exception as e:
|
|
341
|
-
self.logger.warning(f"Failed to reload module {full_module_name}: {e}")
|
|
342
|
-
|
|
343
|
-
# Finally, reload the current module (sample.py)
|
|
344
|
-
try:
|
|
345
|
-
mod = __import__(current_module, fromlist=[current_module.split(".")[0]])
|
|
346
|
-
importlib.reload(mod)
|
|
347
|
-
|
|
348
|
-
# Get the updated class reference from the reloaded module
|
|
349
|
-
new = getattr(mod, self.__class__.__name__)
|
|
350
|
-
# Update the class reference of the instance
|
|
351
|
-
self.__class__ = new
|
|
352
|
-
|
|
353
|
-
self.logger.debug("Module reload completed")
|
|
354
|
-
except Exception as e:
|
|
355
|
-
self.logger.error(f"Failed to reload current module {current_module}: {e}")
|
|
356
|
-
|
|
357
|
-
def get_version(self):
|
|
358
|
-
return get_version()
|
|
359
|
-
|
|
360
|
-
def info(self):
|
|
361
|
-
# show the key attributes of the object
|
|
362
|
-
str = f"File: {os.path.basename(self.file_path)}\n"
|
|
363
|
-
str += f"Path: {os.path.dirname(self.file_path)}\n"
|
|
364
|
-
str += f"
|
|
365
|
-
str += f"
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
str += f"Features
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
str += "Features
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
1
|
+
"""
|
|
2
|
+
sample.py
|
|
3
|
+
|
|
4
|
+
This module provides tools for processing and analyzing Data-Dependent Acquisition (DDA) mass spectrometry data.
|
|
5
|
+
It defines the `Sample` class, which offers methods to load, process, analyze, and visualize mass spectrometry data
|
|
6
|
+
from various file formats, including mzML, Thermo RAW, and Sciex WIFF formats.
|
|
7
|
+
|
|
8
|
+
Key Features:
|
|
9
|
+
- **File Handling**: Load and save data in multiple formats.
|
|
10
|
+
- **Feature Detection**: Detect and process mass spectrometry features.
|
|
11
|
+
- **Spectrum Analysis**: Retrieve and analyze MS1/MS2 spectra.
|
|
12
|
+
- **Visualization**: Generate interactive and static plots for spectra and chromatograms.
|
|
13
|
+
- **Statistics**: Compute and export detailed DDA run statistics.
|
|
14
|
+
|
|
15
|
+
Dependencies:
|
|
16
|
+
- `pyopenms`: For file handling and feature detection.
|
|
17
|
+
- `polars` and `pandas`: For data manipulation.
|
|
18
|
+
- `numpy`: For numerical computations.
|
|
19
|
+
- `bokeh`, `panel`, `holoviews`, `datashader`: For interactive visualizations.
|
|
20
|
+
|
|
21
|
+
Classes:
|
|
22
|
+
- `Sample`: Main class for handling DDA data, providing methods for data import, processing, and visualization.
|
|
23
|
+
|
|
24
|
+
Example Usage:
|
|
25
|
+
```python
|
|
26
|
+
from masster.sample import Sample
|
|
27
|
+
|
|
28
|
+
sample = Sample(file="example.mzML")
|
|
29
|
+
sample.find_features()
|
|
30
|
+
sample.plot_2d()
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
import importlib
|
|
36
|
+
import os
|
|
37
|
+
import sys
|
|
38
|
+
|
|
39
|
+
import polars as pl
|
|
40
|
+
|
|
41
|
+
from masster._version import get_version
|
|
42
|
+
|
|
43
|
+
from masster.sample.defaults.sample_def import sample_defaults
|
|
44
|
+
|
|
45
|
+
# Sample-specific imports
|
|
46
|
+
from masster.sample.h5 import _load_sample5
|
|
47
|
+
from masster.sample.h5 import _save_sample5
|
|
48
|
+
from masster.sample.helpers import _delete_ms2
|
|
49
|
+
from masster.sample.helpers import _estimate_memory_usage
|
|
50
|
+
from masster.sample.helpers import _get_scan_uids
|
|
51
|
+
from masster.sample.helpers import _get_feature_uids
|
|
52
|
+
from masster.sample.helpers import _features_sync
|
|
53
|
+
from masster.sample.helpers import features_delete
|
|
54
|
+
from masster.sample.helpers import features_filter
|
|
55
|
+
from masster.sample.helpers import select
|
|
56
|
+
from masster.sample.helpers import select_closest_scan
|
|
57
|
+
from masster.sample.helpers import get_dda_stats
|
|
58
|
+
from masster.sample.helpers import get_feature
|
|
59
|
+
from masster.sample.helpers import get_scan
|
|
60
|
+
from masster.sample.helpers import set_source
|
|
61
|
+
from masster.sample.load import _load_featureXML
|
|
62
|
+
from masster.sample.load import _load_ms2data
|
|
63
|
+
from masster.sample.load import _load_mzML
|
|
64
|
+
from masster.sample.load import _load_raw
|
|
65
|
+
from masster.sample.load import _load_wiff
|
|
66
|
+
from masster.sample.load import chrom_extract
|
|
67
|
+
from masster.sample.load import index_file
|
|
68
|
+
from masster.sample.load import load
|
|
69
|
+
from masster.sample.load import sanitize
|
|
70
|
+
from masster.logger import MassterLogger
|
|
71
|
+
from masster.sample.plot import plot_2d
|
|
72
|
+
from masster.sample.plot import plot_2d_oracle
|
|
73
|
+
from masster.sample.plot import plot_dda_stats
|
|
74
|
+
from masster.sample.plot import plot_eic
|
|
75
|
+
from masster.sample.plot import plot_feature_stats
|
|
76
|
+
from masster.sample.plot import plot_ms2_cycle
|
|
77
|
+
from masster.sample.plot import plot_ms2_eic
|
|
78
|
+
from masster.sample.plot import plot_ms2_q1
|
|
79
|
+
from masster.sample.processing import _clean_features_df
|
|
80
|
+
from masster.sample.processing import _features_deisotope
|
|
81
|
+
from masster.sample.processing import _get_ztscan_stats
|
|
82
|
+
from masster.sample.processing import _spec_to_mat
|
|
83
|
+
from masster.sample.processing import analyze_dda
|
|
84
|
+
from masster.sample.processing import find_adducts
|
|
85
|
+
from masster.sample.processing import find_features
|
|
86
|
+
from masster.sample.processing import find_ms2
|
|
87
|
+
from masster.sample.processing import get_spectrum
|
|
88
|
+
from masster.sample.parameters import store_history
|
|
89
|
+
from masster.sample.parameters import get_parameters
|
|
90
|
+
from masster.sample.parameters import update_parameters
|
|
91
|
+
from masster.sample.parameters import get_parameters_property
|
|
92
|
+
from masster.sample.parameters import set_parameters_property
|
|
93
|
+
from masster.sample.save import _save_featureXML
|
|
94
|
+
from masster.sample.save import export_chrom
|
|
95
|
+
from masster.sample.save import export_dda_stats
|
|
96
|
+
from masster.sample.save import export_features
|
|
97
|
+
from masster.sample.save import export_mgf
|
|
98
|
+
from masster.sample.save import save
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class Sample:
|
|
102
|
+
"""
|
|
103
|
+
Main class for handling mass spectrometry sample data analysis.
|
|
104
|
+
|
|
105
|
+
This class provides comprehensive functionality for loading, processing,
|
|
106
|
+
and analyzing DDA (data-dependent acquisition) mass spectrometry data.
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
def __init__(
|
|
110
|
+
self,
|
|
111
|
+
**kwargs,
|
|
112
|
+
):
|
|
113
|
+
"""
|
|
114
|
+
Initialize a DDA (data-dependent acquisition) instance.
|
|
115
|
+
|
|
116
|
+
This constructor initializes various attributes related to file handling,
|
|
117
|
+
data storage, and processing parameters used for mass spectrometry data analysis.
|
|
118
|
+
|
|
119
|
+
Parameters:
|
|
120
|
+
**kwargs: Keyword arguments for setting sample parameters. Can include:
|
|
121
|
+
- A sample_defaults instance to set all parameters at once (pass as params=sample_defaults(...))
|
|
122
|
+
- Individual parameter names and values (see sample_defaults for available parameters)
|
|
123
|
+
|
|
124
|
+
Core initialization parameters:
|
|
125
|
+
- file (str, optional): The file path or file object to be loaded
|
|
126
|
+
- ondisk (bool): Whether to keep data on disk or load into memory. Default is False
|
|
127
|
+
- label (str, optional): An optional label to identify the file or dataset
|
|
128
|
+
- log_level (str): The logging level to be set for the logger. Defaults to 'INFO'
|
|
129
|
+
- log_label (str, optional): Optional label for the logger
|
|
130
|
+
|
|
131
|
+
Processing parameters:
|
|
132
|
+
- All parameters from sample_defaults class (see class documentation)
|
|
133
|
+
|
|
134
|
+
For backward compatibility, original signature is supported:
|
|
135
|
+
Sample(file=..., ondisk=..., label=..., log_level=..., log_label=...)
|
|
136
|
+
"""
|
|
137
|
+
# Initialize default parameters
|
|
138
|
+
|
|
139
|
+
# Check if a sample_defaults instance was passed
|
|
140
|
+
if "params" in kwargs and isinstance(kwargs["params"], sample_defaults):
|
|
141
|
+
params = kwargs.pop("params")
|
|
142
|
+
else:
|
|
143
|
+
# Create default parameters and update with provided values
|
|
144
|
+
params = sample_defaults()
|
|
145
|
+
|
|
146
|
+
# Update with any provided parameters
|
|
147
|
+
for key, value in kwargs.items():
|
|
148
|
+
if hasattr(params, key):
|
|
149
|
+
params.set(key, value, validate=True)
|
|
150
|
+
|
|
151
|
+
# Store parameter instance for method access
|
|
152
|
+
self.parameters = params
|
|
153
|
+
|
|
154
|
+
# Set instance attributes for logger
|
|
155
|
+
self.log_level = params.log_level.upper()
|
|
156
|
+
self.log_label = params.log_label + " | " if params.log_label else ""
|
|
157
|
+
self.log_sink = params.log_sink
|
|
158
|
+
|
|
159
|
+
# Initialize independent logger
|
|
160
|
+
from masster.logger import MassterLogger
|
|
161
|
+
self.logger = MassterLogger(
|
|
162
|
+
instance_type="sample",
|
|
163
|
+
level=params.log_level.upper(),
|
|
164
|
+
label=params.log_label if params.log_label else "",
|
|
165
|
+
sink=params.log_sink,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
# Initialize history as dict to keep track of processing parameters
|
|
169
|
+
self.history = {}
|
|
170
|
+
self.store_history(["sample"], params.to_dict())
|
|
171
|
+
|
|
172
|
+
# this is the path to the original file. It's never sample5
|
|
173
|
+
self.file_source = None
|
|
174
|
+
# this is the path to the object that was loaded. It could be sample5
|
|
175
|
+
self.file_path = None
|
|
176
|
+
# Type of the file (e.g., mzML, RAW, WIFF, mzpkl)
|
|
177
|
+
self.file_type = None
|
|
178
|
+
# Interface to handle the file operations (e.g., oms, alpharaw)
|
|
179
|
+
self.file_interface = None
|
|
180
|
+
# The file object once loaded, can be oms.MzMLFile or alpharaw.AlphaRawFile
|
|
181
|
+
self.file_obj = None
|
|
182
|
+
|
|
183
|
+
self.features = None # the feature map as obtained by openMS
|
|
184
|
+
self.features_df = None # the polars data frame with features
|
|
185
|
+
# the polars data frame with metadata of all scans in the file
|
|
186
|
+
self.scans_df = pl.DataFrame()
|
|
187
|
+
# the polars data frame with MS1 level data
|
|
188
|
+
self.ms1_df = pl.DataFrame()
|
|
189
|
+
|
|
190
|
+
# lightweight lib data for matching, targeted analyses, etc. > superseded by study methods
|
|
191
|
+
self.lib = None
|
|
192
|
+
self.lib_match = None
|
|
193
|
+
self.chrom_df = None
|
|
194
|
+
|
|
195
|
+
if params.filename is not None:
|
|
196
|
+
self.load(params.filename, ondisk=params.ondisk)
|
|
197
|
+
|
|
198
|
+
# Attach module functions as class methods
|
|
199
|
+
load = load
|
|
200
|
+
save = save
|
|
201
|
+
find_features = find_features
|
|
202
|
+
find_adducts = find_adducts
|
|
203
|
+
find_ms2 = find_ms2
|
|
204
|
+
get_spectrum = get_spectrum
|
|
205
|
+
filter = filter
|
|
206
|
+
select = select
|
|
207
|
+
features_filter = features_filter # New function that keeps only specified features
|
|
208
|
+
filter_features = filter
|
|
209
|
+
features_select = select
|
|
210
|
+
select_features = select
|
|
211
|
+
analyze_dda = analyze_dda
|
|
212
|
+
store_history = store_history
|
|
213
|
+
get_parameters = get_parameters
|
|
214
|
+
update_parameters = update_parameters
|
|
215
|
+
get_parameters_property = get_parameters_property
|
|
216
|
+
set_parameters_property = set_parameters_property
|
|
217
|
+
export_features = export_features
|
|
218
|
+
export_mgf = export_mgf
|
|
219
|
+
export_chrom = export_chrom
|
|
220
|
+
export_dda_stats = export_dda_stats
|
|
221
|
+
plot_2d = plot_2d
|
|
222
|
+
plot_2d_oracle = plot_2d_oracle
|
|
223
|
+
plot_dda_stats = plot_dda_stats
|
|
224
|
+
plot_eic = plot_eic
|
|
225
|
+
plot_feature_stats = plot_feature_stats
|
|
226
|
+
plot_ms2_cycle = plot_ms2_cycle
|
|
227
|
+
plot_ms2_eic = plot_ms2_eic
|
|
228
|
+
plot_ms2_q1 = plot_ms2_q1
|
|
229
|
+
get_feature = get_feature
|
|
230
|
+
get_scan = get_scan
|
|
231
|
+
get_dda_stats = get_dda_stats
|
|
232
|
+
select_closest_scan = select_closest_scan
|
|
233
|
+
set_source = set_source
|
|
234
|
+
|
|
235
|
+
# Additional method assignments for all imported functions
|
|
236
|
+
_load_sample5 = _load_sample5
|
|
237
|
+
_save_sample5 = _save_sample5
|
|
238
|
+
_delete_ms2 = _delete_ms2
|
|
239
|
+
_estimate_memory_usage = _estimate_memory_usage
|
|
240
|
+
_get_scan_uids = _get_scan_uids
|
|
241
|
+
_get_feature_uids = _get_feature_uids
|
|
242
|
+
_features_sync = _features_sync
|
|
243
|
+
features_delete = features_delete
|
|
244
|
+
features_filter = features_filter
|
|
245
|
+
_load_featureXML = _load_featureXML
|
|
246
|
+
_load_ms2data = _load_ms2data
|
|
247
|
+
_load_mzML = _load_mzML
|
|
248
|
+
_load_raw = _load_raw
|
|
249
|
+
_load_wiff = _load_wiff
|
|
250
|
+
chrom_extract = chrom_extract
|
|
251
|
+
index_file = index_file
|
|
252
|
+
sanitize = sanitize
|
|
253
|
+
_clean_features_df = _clean_features_df
|
|
254
|
+
_features_deisotope = _features_deisotope
|
|
255
|
+
_get_ztscan_stats = _get_ztscan_stats
|
|
256
|
+
_spec_to_mat = _spec_to_mat
|
|
257
|
+
_save_featureXML = _save_featureXML
|
|
258
|
+
|
|
259
|
+
def logger_update(self, level: str | None = None, label: str | None = None, sink: str | None = None):
|
|
260
|
+
"""Update the logging configuration for this Sample instance.
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
level: New logging level ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL")
|
|
264
|
+
label: New label for log messages
|
|
265
|
+
sink: New output sink (file path, file object, or "sys.stdout")
|
|
266
|
+
"""
|
|
267
|
+
if level is not None:
|
|
268
|
+
self.log_level = level.upper()
|
|
269
|
+
self.logger.update_level(level)
|
|
270
|
+
|
|
271
|
+
if label is not None:
|
|
272
|
+
self.log_label = label + " | " if len(label) > 0 else ""
|
|
273
|
+
self.logger.update_label(self.log_label)
|
|
274
|
+
|
|
275
|
+
if sink is not None:
|
|
276
|
+
if sink == "sys.stdout":
|
|
277
|
+
self.log_sink = sys.stdout
|
|
278
|
+
else:
|
|
279
|
+
self.log_sink = sink
|
|
280
|
+
self.logger.update_sink(self.log_sink)
|
|
281
|
+
|
|
282
|
+
def _reload(self):
|
|
283
|
+
"""
|
|
284
|
+
Reloads all masster modules to pick up any changes to their source code,
|
|
285
|
+
and updates the instance's class reference to the newly reloaded class version.
|
|
286
|
+
This ensures that the instance uses the latest implementation without restarting the interpreter.
|
|
287
|
+
"""
|
|
288
|
+
# Reset logger configuration flags to allow proper reconfiguration after reload
|
|
289
|
+
try:
|
|
290
|
+
import masster.sample.logger as logger_module
|
|
291
|
+
|
|
292
|
+
if hasattr(logger_module, "_SAMPLE_LOGGER_CONFIGURED"):
|
|
293
|
+
logger_module._SAMPLE_LOGGER_CONFIGURED = False
|
|
294
|
+
except Exception:
|
|
295
|
+
pass
|
|
296
|
+
|
|
297
|
+
# Get the base module name (masster)
|
|
298
|
+
base_modname = self.__class__.__module__.split(".")[0]
|
|
299
|
+
current_module = self.__class__.__module__
|
|
300
|
+
|
|
301
|
+
# Dynamically find all sample submodules
|
|
302
|
+
sample_modules = []
|
|
303
|
+
sample_module_prefix = f"{base_modname}.sample."
|
|
304
|
+
|
|
305
|
+
# Get all currently loaded modules that are part of the sample package
|
|
306
|
+
for module_name in sys.modules:
|
|
307
|
+
if module_name.startswith(sample_module_prefix) and module_name != current_module:
|
|
308
|
+
sample_modules.append(module_name)
|
|
309
|
+
|
|
310
|
+
# Add core masster modules
|
|
311
|
+
core_modules = [
|
|
312
|
+
f"{base_modname}._version",
|
|
313
|
+
f"{base_modname}.chromatogram",
|
|
314
|
+
f"{base_modname}.spectrum",
|
|
315
|
+
]
|
|
316
|
+
|
|
317
|
+
# Add study submodules
|
|
318
|
+
study_modules = []
|
|
319
|
+
study_module_prefix = f"{base_modname}.study."
|
|
320
|
+
for module_name in sys.modules:
|
|
321
|
+
if module_name.startswith(study_module_prefix) and module_name != current_module:
|
|
322
|
+
study_modules.append(module_name)
|
|
323
|
+
|
|
324
|
+
# Add parameters submodules
|
|
325
|
+
parameters_modules = []
|
|
326
|
+
parameters_module_prefix = f"{base_modname}.parameters."
|
|
327
|
+
for module_name in sys.modules:
|
|
328
|
+
if module_name.startswith(parameters_module_prefix) and module_name != current_module:
|
|
329
|
+
parameters_modules.append(module_name)
|
|
330
|
+
|
|
331
|
+
all_modules_to_reload = core_modules + sample_modules + study_modules + parameters_modules
|
|
332
|
+
|
|
333
|
+
# Reload all discovered modules
|
|
334
|
+
for full_module_name in all_modules_to_reload:
|
|
335
|
+
try:
|
|
336
|
+
if full_module_name in sys.modules:
|
|
337
|
+
mod = sys.modules[full_module_name]
|
|
338
|
+
importlib.reload(mod)
|
|
339
|
+
self.logger.debug(f"Reloaded module: {full_module_name}")
|
|
340
|
+
except Exception as e:
|
|
341
|
+
self.logger.warning(f"Failed to reload module {full_module_name}: {e}")
|
|
342
|
+
|
|
343
|
+
# Finally, reload the current module (sample.py)
|
|
344
|
+
try:
|
|
345
|
+
mod = __import__(current_module, fromlist=[current_module.split(".")[0]])
|
|
346
|
+
importlib.reload(mod)
|
|
347
|
+
|
|
348
|
+
# Get the updated class reference from the reloaded module
|
|
349
|
+
new = getattr(mod, self.__class__.__name__)
|
|
350
|
+
# Update the class reference of the instance
|
|
351
|
+
self.__class__ = new
|
|
352
|
+
|
|
353
|
+
self.logger.debug("Module reload completed")
|
|
354
|
+
except Exception as e:
|
|
355
|
+
self.logger.error(f"Failed to reload current module {current_module}: {e}")
|
|
356
|
+
|
|
357
|
+
def get_version(self):
|
|
358
|
+
return get_version()
|
|
359
|
+
|
|
360
|
+
def info(self):
|
|
361
|
+
# show the key attributes of the object
|
|
362
|
+
str = f"File: {os.path.basename(self.file_path)}\n"
|
|
363
|
+
str += f"Path: {os.path.dirname(self.file_path)}\n"
|
|
364
|
+
str += f"Source: {self.file_source}\n"
|
|
365
|
+
str += f"MS1 scans: {len(self.scans_df.filter(pl.col('ms_level') == 1))}\n"
|
|
366
|
+
str += f"MS2 scans: {len(self.scans_df.filter(pl.col('ms_level') == 2))}\n"
|
|
367
|
+
if self.features_df is not None:
|
|
368
|
+
str += f"Features: {len(self.features_df) if self.features_df is not None else 0}\n"
|
|
369
|
+
str += f"Features with MS2 spectra: {len(self.features_df.filter(pl.col('ms2_scans').is_not_null()))}\n"
|
|
370
|
+
else:
|
|
371
|
+
str += "Features: 0\n"
|
|
372
|
+
str += "Features with MS2 spectra: 0\n"
|
|
373
|
+
|
|
374
|
+
# estimate memory usage
|
|
375
|
+
mem_usage = self._estimate_memory_usage()
|
|
376
|
+
str += f"Estimated memory usage: {mem_usage:.2f} MB\n"
|
|
377
|
+
|
|
378
|
+
print(str)
|
|
379
|
+
|
|
380
|
+
def __str__(self):
|
|
381
|
+
if self.features_df is None:
|
|
382
|
+
str = f"masster Sample, source: {os.path.basename(self.file_path)}, features: 0"
|
|
383
|
+
else:
|
|
384
|
+
str = f"masster Sample, source: {os.path.basename(self.file_path)}, features: {len(self.features_df)}"
|
|
385
|
+
return str
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
if __name__ == "__main__":
|
|
389
|
+
print(
|
|
390
|
+
"This module is not meant to be run directly. Please import it in your script.",
|
|
391
|
+
)
|