|
5 | 5 | import numpy as np |
6 | 6 |
|
7 | 7 | from tqdm import tqdm |
8 | | -from matchms.importing import load_from_mgf |
9 | 8 | import pymzml |
10 | | -from pyteomics import mzxml, mzml |
| 9 | +from pyteomics import mzxml, mzml, mgf |
11 | 10 |
|
12 | 11 | import logging |
13 | 12 | logger = logging.getLogger('msql_fileloading') |
@@ -143,51 +142,83 @@ def load_data(input_filename, cache=None, cache_dir=None, cache_file=None): |
143 | 142 | return ms1_df, ms2_df |
144 | 143 |
|
145 | 144 | def _load_data_mgf(input_filename): |
146 | | - file = load_from_mgf(input_filename) |
| 145 | + ms2_data_list = [] |
147 | 146 |
|
148 | | - ms2mz_list = [] |
149 | | - for i, spectrum in enumerate(file): |
150 | | - if len(spectrum.peaks.mz) == 0: |
151 | | - continue |
152 | | - |
153 | | - mz_list = list(spectrum.peaks.mz) |
154 | | - i_list = list(spectrum.peaks.intensities) |
155 | | - i_max = max(i_list) |
156 | | - i_sum = sum(i_list) |
| 147 | + # Use 'with' context manager for safe file handling |
| 148 | + with mgf.read(input_filename) as reader: |
| 149 | + for index, spectrum in enumerate(reader): |
| 150 | + |
| 151 | + # Pyteomics returns numpy arrays |
| 152 | + mz_array = spectrum['m/z array'] |
| 153 | + int_array = spectrum['intensity array'] |
157 | 154 |
|
158 | | - for i in range(len(mz_list)): |
159 | | - if i_list[i] == 0: |
| 155 | + # Skip empty spectra |
| 156 | + if len(mz_array) == 0: |
160 | 157 | continue |
161 | 158 |
|
162 | | - peak_dict = {} |
163 | | - peak_dict["i"] = i_list[i] |
164 | | - peak_dict["i_norm"] = i_list[i] / i_max |
165 | | - peak_dict["i_tic_norm"] = i_list[i] / i_sum |
166 | | - peak_dict["mz"] = mz_list[i] |
| 159 | + # Calculate spectrum-wide statistics |
| 160 | + i_max = int_array.max() |
| 161 | + i_sum = int_array.sum() |
| 162 | + |
| 163 | + # --- Metadata Extraction --- |
| 164 | + params = spectrum.get('params', {}) |
167 | 165 |
|
168 | | - # Handling malformed mgf files |
| 166 | + # Scan: Use 'scans' or fallback to index |
| 167 | + scan = params.get('scans', index + 1) |
| 168 | + |
| 169 | + # RT: Parse 'rtinseconds', default 0, convert to minutes |
169 | 170 | try: |
170 | | - peak_dict["scan"] = spectrum.metadata["scans"] |
171 | | - except: |
172 | | - peak_dict["scan"] = i + 1 |
| 171 | + rt = float(params.get('rtinseconds', 0)) / 60.0 |
| 172 | + except (ValueError, TypeError): |
| 173 | + rt = 0.0 |
| 174 | + |
| 175 | + # Precursor m/z: 'pepmass' is usually a tuple (mz, intensity) |
173 | 176 | try: |
174 | | - peak_dict["rt"] = float(spectrum.metadata["rtinseconds"]) / 60 |
175 | | - except: |
176 | | - peak_dict["rt"] = 0 |
| 177 | + precmz = float(params.get('pepmass', [0])[0]) |
| 178 | + except (IndexError, ValueError, TypeError): |
| 179 | + precmz = 0.0 |
| 180 | + |
| 181 | + # Charge: Parse 'CHARGE=2+' format |
| 182 | + # Pyteomics often returns charge as a list or integer depending on config |
177 | 183 | try: |
178 | | - peak_dict["precmz"] = float(spectrum.metadata["pepmass"][0]) |
| 184 | + charge_val = params.get('charge', [1]) |
| 185 | + # Handle cases where it is a list e.g., [2+] or [2] |
| 186 | + if isinstance(charge_val, list): |
| 187 | + charge_str = str(charge_val[0]) |
| 188 | + else: |
| 189 | + charge_str = str(charge_val) |
| 190 | + # Strip '+' and convert to int |
| 191 | + charge = int(charge_str.strip('+')) |
179 | 192 | except: |
180 | | - peak_dict["precmz"] = 0 |
181 | | - |
182 | | - peak_dict["ms1scan"] = 0 |
183 | | - peak_dict["charge"] = 1 # TODO: Add Charge Correctly here |
184 | | - peak_dict["polarity"] = 1 # TODO: Add Polarity Correctly here |
185 | | - |
186 | | - ms2mz_list.append(peak_dict) |
187 | | - |
188 | | - # Turning into pandas data frames |
189 | | - ms1_df = pd.DataFrame([peak_dict]) |
190 | | - ms2_df = pd.DataFrame(ms2mz_list) |
| 193 | + charge = 1 |
| 194 | + |
| 195 | + # --- Peak Extraction --- |
| 196 | + # Zip arrays to iterate pairs |
| 197 | + for mz, intensity in zip(mz_array, int_array): |
| 198 | + if intensity == 0: |
| 199 | + continue |
| 200 | + |
| 201 | + peak_dict = { |
| 202 | + "i": intensity, |
| 203 | + "i_norm": intensity / i_max, |
| 204 | + "i_tic_norm": intensity / i_sum, |
| 205 | + "mz": mz, |
| 206 | + "scan": scan, |
| 207 | + "rt": rt, |
| 208 | + "precmz": precmz, |
| 209 | + "ms1scan": 0, |
| 210 | + "charge": charge, # Implemented |
| 211 | + "polarity": 1 # Default |
| 212 | + } |
| 213 | + |
| 214 | + ms2_data_list.append(peak_dict) |
| 215 | + |
| 216 | + # Convert to DataFrames |
| 217 | + ms2_df = pd.DataFrame(ms2_data_list) |
| 218 | + |
| 219 | + # Original code assigned the last single peak to ms1_df. |
| 220 | + # Initializing empty to prevent bugs. |
| 221 | + ms1_df = pd.DataFrame() |
191 | 222 |
|
192 | 223 | return ms1_df, ms2_df |
193 | 224 |
|
|
0 commit comments