Source code for proteobench.io.params.msangel
"""
MSAngel creates modular pipelines that allows several search engines to identify
peptides, which are then quantified with Proline.
The parameters are provided in a .json file.
MSAngel allows for multiple search engines to be used in the same pipeline. So it
requires a list of search engines and their respective parameters, which are then
concatenated.
Relevant information in file:
-
"""
import json
import os
import pathlib
import re
from typing import Union
import pandas as pd
from proteobench.io.params import ProteoBenchParameters
from proteobench.io.params.maxquant import _homogenize_mods
def _homogenize_mod_xtandem(mod_str: str) -> str:
"""Convert MSAngel X!Tandem modification format to ProForma-like notation.
Format: ``{modname} of {residue}``, e.g. ``Oxidation of M``,
``Acetylation of protein N-term``.
"""
mod_str = mod_str.strip()
if " of " not in mod_str:
return mod_str
name, residue_part = mod_str.split(" of ", 1)
residue_part = residue_part.strip()
lower = residue_part.lower()
if "protein n-term" in lower:
return f"Protein N-term[{name}]"
elif "n-term" in lower:
return f"N-term[{name}]"
elif "protein c-term" in lower:
return f"Protein C-term[{name}]"
elif "c-term" in lower:
return f"C-term[{name}]"
else:
return f"{residue_part.upper()}[{name}]"
# Mapping from Mascot enzyme name strings to canonical ProteoBench names.
# Keys are lowercase to allow case-insensitive lookup.
_ENZYME_MAP = {
"trypsin": "Trypsin",
"trypsin (kr/np)": "Trypsin",
"trypsin/p": "Trypsin/P",
"lysc": "Lys-C",
"lys-c": "Lys-C",
"argc": "Arg-C",
"arg-c": "Arg-C",
"aspn": "Asp-N",
"asp-n": "Asp-N",
"gluc": "Glu-C",
"glu-c": "Glu-C",
"chymotrypsin": "Chymotrypsin",
}
[docs]
def get_charges(charge_str):
"""
Extract minimum and maximum precursor charges from the charge string.
String is of the format "X+, Y+, ..., and Z+"
Parameters
----------
charge_str : str
The charge string in the format "min-max".
Returns
-------
tuple
A tuple containing the minimum and maximum precursor charges as integers.
"""
# Use regex to find all charge values in the string because "and" is in the string next to commaas
charges = re.findall(r"(\d+)\+", charge_str)
if not charges:
raise ValueError(f"Invalid charge string format: {charge_str}")
min_charge = int(min(charges))
max_charge = int(max(charges))
return min_charge, max_charge
[docs]
def extract_params_xtandem_specific(search_params: list, input_params: ProteoBenchParameters) -> ProteoBenchParameters:
"""
Extract search parameters from the JSON data of a workflow running X!Tandem.
Adds them to the partially completed input_params ProteoBenchParameters object.
Parameters
----------
search_params : list
The list of search parameters extracted from the JSON file.
input_params : ProteoBenchParameters
The partially completed input_params object.
Returns
-------
ProteoBenchParameters
The input_params object with the extracted parameters added.
"""
for each_search_params in search_params["operations"]:
if "searchEnginesWithForms" in each_search_params:
# params.search_engine_version =
raw_enzyme = each_search_params["searchEnginesWithForms"][0][1]["paramMap"]["digestionParameters"][
"enzymes"
][0]["name"]
input_params.enzyme = _ENZYME_MAP.get(raw_enzyme.strip().lower(), raw_enzyme)
# params.allowed_miscleavages =
input_params.fixed_mods = ", ".join(
_homogenize_mod_xtandem(m)
for m in each_search_params["searchEnginesWithForms"][0][1]["paramMap"]["modificationParameters"][
"fixedModifications"
]
)
input_params.variable_mods = ", ".join(
_homogenize_mod_xtandem(m)
for m in each_search_params["searchEnginesWithForms"][0][1]["paramMap"]["modificationParameters"][
"variableModifications"
]
)
# Use the raw enzyme name for the missed cleavages lookup (dict keys are vendor names).
n_missed_cleavages_dict = each_search_params["searchEnginesWithForms"][0][1]["paramMap"][
"digestionParameters"
]["nMissedCleavages"]
input_params.allowed_miscleavages = n_missed_cleavages_dict.get(raw_enzyme, None)
# get tolerance for precursors:
tol = each_search_params["searchEnginesWithForms"][0][1]["paramMap"]["precursorTolerance"]
unit = each_search_params["searchEnginesWithForms"][0][1]["paramMap"]["precursorAccuracyType"]
unit_homogenized = "ppm" if unit.lower() == "ppm" else "Da"
tol = float(tol)
input_params.precursor_mass_tolerance = (
"[-" + str(tol) + " " + unit_homogenized + ", " + str(tol) + " " + unit_homogenized + "]"
)
# get tolerance for fragments:
tol2 = each_search_params["searchEnginesWithForms"][0][1]["paramMap"]["fragmentIonMZTolerance"]
unit2 = each_search_params["searchEnginesWithForms"][0][1]["paramMap"]["fragmentAccuracyType"]
unit2_homogenized = "ppm" if unit2.lower() == "ppm" else "Da"
tol2 = float(tol2)
input_params.fragment_mass_tolerance = (
"[-" + str(tol2) + " " + unit2_homogenized + ", " + str(tol2) + " " + unit2_homogenized + "]"
)
input_params.min_precursor_charge = each_search_params["searchEnginesWithForms"][0][1]["paramMap"][
"minChargeSearched"
]
input_params.max_precursor_charge = each_search_params["searchEnginesWithForms"][0][1]["paramMap"][
"maxChargeSearched"
]
# Add "hidden" modifications when using X!Tandem:
for key, value in each_search_params["searchEnginesWithForms"][0][1]["paramMap"][
"algorithmParameters"
].items():
if value["type"] == "com.compomics.util.parameters.identification.tool_specific.XtandemParameters":
if value["data"]["proteinQuickAcetyl"] == True:
input_params.variable_mods = input_params.variable_mods + ", N-term[Acetyl]"
if value["data"]["quickPyrolidone"] == True:
input_params.variable_mods = input_params.variable_mods + ", N-term[Pyrolidone]"
if "validationConfig" in each_search_params:
input_params.ident_fdr_psm = each_search_params["validationConfig"]["psmExpectedFdr"] / 100
# input_params.min_peptide_length = each_search_params["validationConfig"]["psmFilters"] #TODO: I am not sure if this is the max or min length
if "quantitationConfig" in each_search_params:
input_params.quantification_method = each_search_params["quantitationConfig"]["quantMethod"]["type"]
input_params.abundance_normalization_ions = each_search_params["quantitationConfig"]["lfqConfig"][
"masterMapCreationConfig"
]["normalizationMethod"]["value"]
return input_params
if __name__ == "__main__":
"""
Extract parameters from MSAngel JSON files and save them as CSV.
"""
from pathlib import Path
files = [
Path("../../../test/params/MSAngel_Xtandem-export-param.json"),
Path("../../../test/params/MSAngel_fromRAWtoQUANT-Mascot-export-param.json"),
]
for file in files:
# Extract parameters from the file
params = extract_params(file)
# Convert the extracted parameters to a dictionary and then to a pandas Series
data_dict = params.__dict__
series = pd.Series(data_dict)
print(series)
# Write the Series to a CSV file
series.to_csv(file.with_suffix(".csv"))