diff --git a/liabilities/liabilities.py b/liabilities/liabilities.py new file mode 100644 index 0000000..7bb9cd3 --- /dev/null +++ b/liabilities/liabilities.py @@ -0,0 +1,265 @@ +from rdkit import Chem + +# Define the liabilities with SMARTS patterns, their corresponding liabilities, pH ranges, and references +liabilities = [ + { + "smarts": "N[CH1]([CH2][CH0](=[OH0])[OH1,O-])[CH0](=[OH0])[NH0]1[CH2][CH2][CH2][CH1]1[CH0](=[OH0])", + "fasta_pattern":"DP", + "liability": "Asp-Pro bond cleavage", + "pH_stability_range": "6.0–7.5", + "pH_instability_range": "<5.0 or >8.0", + "references": "Manning et al. (2010); Cleland et al. (1993)" + }, + { + "smarts": "[OH0]=[CH0][CH1](N)([CH2][CH2][SX2][CH3])", + "fasta_pattern":"M", + "liability": "Methionine oxidation", + "pH_stability_range": "6.0–7.5", + "pH_instability_range": "<5.0 or >8.0", + "references": "Manning et al. (2010); Cleland et al. (1993); Al Musaimi et al. (2022)" + }, + { + "smarts": "N[CH1]([CH2][CH0](=[OH0])[NH2])[CH0](=[OH0])", + "fasta_pattern":"N", + "liability": "Deamidation of Asn", + "pH_stability_range": "4.5–6.0", + "pH_instability_range": "<4.0 or >6.0", + "references": "Wakankar & Borchardt (2006)" + }, + + { + "smarts": "N[CH1]([CH2][CH0](=[OH0])[NH2])[CH0](=[OH0])[NH1][CH2][CH0](=[OH0])", + "fasta_pattern":"NG", + "liability": "Deamidationn of Asn-Gly", + "pH_stability_range": "4.5–6.5", + "pH_instability_range": "<4.0 or >7.0", + "references": "Cleland et al. (1993); Li et al. (1995); Al Musaimi et al. (2022)" + }, + + { + "smarts": "C[CH2][SX2][SX2][CH2]C", + "fasta_pattern":"C", + "liability": "Disulfide bond scrambling", + "pH_stability_range": "5.5–8.0", + "pH_instability_range": "<4.0 or >9.0", + "references": "Wang & Roberts (2018)" + }, + + { + "smarts": "[CH3][CH1]([OH1])[CH1]([NH1][CH0](=[OH0])[CH1](N)[CH2][OH1])[CH0](=[OH0])", + "fasta_pattern":"ST", + "liability": "Hydrolysis at Ser-Thr bonds", + "pH_stability_range": "7.0–8.5", + "pH_instability_range": "<6.0 or >9.0", + "references": "Shire et al. (2004)" + }, + + { + "smarts": "[NH2,N+H3][CH2][CH2][CH2][CH2][CH1](N)[CH0](=[OH0])", + "liability": "Lys oxidation", + "fasta_pattern":"K", + "pH_stability_range": "4.5–6.5", + "pH_instability_range": "<4.0 or >7.0", + "references": "Cleland et al. (1993); Li et al. (1995); Al Musaimi et al. (2022)" + }, + + { + "smarts": "[CH0](=[OH0])[CH1]1[CH2][CH2][CH2]N1", + "liability": "Hydrolysis near Pro residues", + "fasta_pattern":"P", + "pH_stability_range": "6.0–7.0", + "pH_instability_range": "<5.0 or >8.5", + "references": "Shire et al. (2004); Nugrahadi et al. (2003)" + }, + + { + "smarts": "[NH2,N+H3][CH1]([CH2][cH0]1[cH1][nH,n,n+H][cH1][nH,n,n+H]1)[CH0](=[OH0])", + "liability": "N-terminal His oxidation", + "fasta_pattern":"H", + "pH_stability_range": "6.5–8.0", + "pH_instability_range": "<6.0 or >8.5", + "references": "Manning et al. (2010); Li et al. (1995); Al Musaimi et al. (2022)" + } + +] + + +def calculate_liabilities_from_mol(mol): + """ + This function calculates the sequence liability based on the SMARTS patterns + of specific amino acid degradation pathways. The RDKit molecule is checked + for matching SMARTS patterns, and liabilities are flagged accordingly. + It also counts how many times each liability pattern is matched. + + :param mol: RDKit molecule object + :return: Dictionary of sequence liabilities with SMARTS patterns, pH ranges, references, and counts + """ + + # Initialize a dictionary to store detected liabilities + detected_liabilities = {} + + # Check for substructure matches with each SMARTS pattern + for liability in liabilities: + smarts_pattern = liability["smarts"] + smarts_mol = Chem.MolFromSmarts(smarts_pattern) + + # Get the list of all matches for the SMARTS pattern + matches = mol.GetSubstructMatches(smarts_mol) + match_count = len(matches) # Count the number of matches + + # If there are matches, add the liability to the detected liabilities dictionary + if match_count > 0: + detected_liabilities[liability["liability"]] = { + "liability": liability["liability"], + "fasta_pattern": liability["fasta_pattern"], +# "SMARTS_pattern": smarts_pattern, + "match_count": match_count, + "pH_stability_range": liability["pH_stability_range"], + "pH_instability_range": liability["pH_instability_range"], + "references": liability["references"] + } + + return detected_liabilities + + +# # Example usage with RDKit +# from rdkit import Chem + +# # Example peptide molecule (you can replace this with any RDKit peptide) +# smiles_string = "CC(=O)NC(=O)C" # Simple example peptide (Acetyl-Glycine) + +# mol = Chem.MolFromSmiles(smiles_string) + +# # Calculate liabilities +# liabilities = calculate_liabilities_from_rdkit_mol(mol) + +# # Output the identified liabilities +# if liabilities: +# for liability, details in liabilities.items(): +# print(f"Liability: {liability}") +# print(f"SMARTS Pattern: {details['SMARTS_pattern']}") +# print(f"Match Count: {details['match_count']}") +# print(f"P-H Stability Range: {details['pH_stability_range']}") +# print(f"P-H Instability Range: {details['pH_instability_range']}") +# print(f"References: {details['references']}") +# else: +# print("No liabilities detected in the sequence.") + + + +def calculate_liabilities_from_fasta(fasta_sequence): + """ + This function calculates the sequence liability based on the presence of specific amino acid sequences + in the input peptide sequence and includes pH stability and instability ranges. + + :param fasta_sequence: Input peptide sequence as a string (FASTA format) + :return: Dictionary of sequence liabilities with associated pH ranges + """ + + # Initialize a dictionary to store detected liabilities + detected_liabilities = {} + + # Convert the sequence to uppercase to handle both L- and D- amino acids + fasta_sequence_upper = fasta_sequence.upper() + + # Check each liability pattern against the sequence + for liability in liabilities: + # case of N-terminal histidine + if liability["liability"] == "N-terminal His oxidation": + if liability["fasta_pattern"].upper() == fasta_sequence_upper[0]: + detected_liabilities[liability["liability"]] = { + "liability": liability["liability"], + "fasta_pattern": liability["fasta_pattern"], + "match_count": 1, + "pH_stability_range": liability["pH_stability_range"], + "pH_instability_range": liability["pH_instability_range"], + "references": liability["references"] + } + # general case + else: + if liability["fasta_pattern"].upper() in fasta_sequence_upper: + detected_liabilities[liability["liability"]] = { + "liability": liability["liability"], + "fasta_pattern": liability["fasta_pattern"], + "match_count": fasta_sequence.count(liability["fasta_pattern"]), + "pH_stability_range": liability["pH_stability_range"], + "pH_instability_range": liability["pH_instability_range"], + "references": liability["references"] + } + + return detected_liabilities + + +# if __name__ == "__main__" +# # Example usage +# fasta_sequence = "MKTPIALDEKDPQCVLNTG" # Example peptide sequence + +# liabilities = calculate_liabilities_from_fasta(fasta_sequence) + +# # Output the identified liabilities +# if liabilities: +# for liability, details in liabilities.items(): +# print(f"Liability: {liability}") +# print(f"P-H Stability Range: {details['pH_stability_range']}") +# print(f"P-H Instability Range: {details['pH_instability_range']}") +# print(f"References: {details['references']}") +# else: +# print("No liabilities detected in the sequence.") + + + + +def calc_liabilities_from_dict(input_dict, input_type="structure"): + """ + Calculates liabilities from an input dictionary. + + Parameters: + input_dict (dict): A dictionary containing molecular data. + input_type (str): Defines the input type, either "structure" (RDKit Molecule) or "fasta" (Amino Acid Sequence). + + Returns: + dict_output (dict): A dictionary with liabilities for each molecule or peptide. + """ + dict_output = dict() + + if input_type == "structure": + # If the input is a structure (RDKit Molecule) + for mol_idx, mol_data in input_dict.items(): + mol_name = mol_data.get("mol_name", "Unnamed Molecule") + mol_object = mol_data.get("mol_obj") + + if mol_object is None: + raise ValueError(f"Molecule object for {mol_name} is missing.") + + # Calculate liabilities based on SMARTS patterns + liabilities = calculate_liabilities_from_mol(mol_object) + + # Store the result in the output dictionary + dict_output[mol_idx] = { + "mol_name": mol_name, + "liabilities": liabilities + } + + elif input_type == "fasta": + # If the input is a fasta sequence (peptide sequence) + for mol_idx, mol_data in input_dict.items(): + mol_name = mol_data.get("mol_name", "Unnamed Sequence") + fasta = mol_data.get("fasta") + + if fasta is None: + raise ValueError(f"FASTA sequence for {mol_name} is missing.") + + # Calculate liabilities based on FASTA sequence + liabilities = calculate_liabilities_from_fasta(fasta) + + # Store the result in the output dictionary + dict_output[mol_idx] = { + "mol_name": mol_name, + "liabilities": liabilities + } + + else: + raise ValueError("Unknown input_type. It must be either 'structure' or 'fasta'.") + + return dict_output + diff --git a/molecular_descriptors/molecular_descriptors.py b/molecular_descriptors/molecular_descriptors.py new file mode 100644 index 0000000..6867ddc --- /dev/null +++ b/molecular_descriptors/molecular_descriptors.py @@ -0,0 +1,148 @@ +from rdkit import Chem +from rdkit.Chem import Descriptors +from Bio.SeqUtils import molecular_weight +# from Bio.SeqUtils import gravy +from rdkit.Chem import Crippen + +def calc_molecular_descriptors_from_dict( + input_dict, + input_type="structure", +): + """ + Calculates the molecular weight and length of molecules (or peptides) from the input dictionary. + + Parameters: + input_dict (dict): A dictionary containing molecular data. + input_type (str): Defines the input type, either "structure" (RDKit Molecule) or "fasta" (Amino Acid Sequence). + + Returns: + dict_output (dict): A dictionary with molecular weights and lengths for each molecule or peptide. + """ + dict_output = dict() + + if input_type == "structure": + # If the input is a structure (SMILES or RDKit molecule) + for mol_idx in input_dict.keys(): + mol_name = input_dict[mol_idx].get("mol_name", "Unnamed Molecule") + mol_object = input_dict[mol_idx].get("mol_obj") + fasta = input_dict[mol_idx].get("fasta") + + if mol_object is None: + raise ValueError(f"Molecule object for {mol_name} is missing.") + + # Calculate the molecular weight using RDKit + mol_weight = Descriptors.MolWt(mol_object) + + # Calculate the GRAVY score + # gravy_score = gravy(fasta) + + # Calculate ClogP (logP) + logp = Crippen.MolLogP(mol_object) + + # Generate SMILES from RDKit mol object + smiles = Chem.MolToSmiles(mol_object) + + # Store the result in the output dictionary + dict_output[mol_idx] = { + "mol_name": mol_name, + "molecular_weight": mol_weight, + "seq_length": len(fasta), # Length of the molecule fasta + # "gravy_score": gravy_score, # GRAVY score + "logp":logp, + "fasta":fasta, + "smiles":smiles + } + + elif input_type == "fasta": + # If the input is a fasta sequence (protein or peptide sequence) + for mol_idx in input_dict.keys(): + mol_name = input_dict[mol_idx].get("mol_name", "Unnamed Sequence") + fasta = input_dict[mol_idx].get("fasta") + + if fasta is None: + raise ValueError(f"FASTA sequence for {mol_name} is missing.") + + # if nonnatural is given in fasta - skip it to allow further calcualtions. + if "X" in fasta: + raise ValueError(f"FASTA sequence for {mol_name} contains X. Please skip it or replace by similar amio-acid.") + #fasta = fasta.replace("X","") + + # if nonnatural is given in fasta - skip it to allow further calcualtions. + if not fasta.isalpha(): + raise ValueError(f"FASTA sequence for {mol_name} contains unknown letters. Please replace with known amio-acids.") + #fasta = fasta.replace("X","") + + + + # Calculate molecular weight for the peptide sequence + mol_weight = molecular_weight(fasta, seq_type='protein') + seq_length = len(fasta) # Length of the peptide sequence + + # Calculate the GRAVY score + # gravy_score = gravy(fasta) + + mol_from_fasta = Chem.MolFromSequence(fasta) + logp = Crippen.MolLogP(mol_from_fasta) + + # Generate SMILES from RDKit mol object + smiles = Chem.MolToSmiles(mol_from_fasta) + + # Store the result in the output dictionary + dict_output[mol_idx] = { + "mol_name": mol_name, + "molecular_weight": mol_weight, + "seq_length": seq_length, # Length of the peptide sequence + # "gravy_score": gravy_score, # GRAVY score + "logp":logp, + "fasta":fasta, + "smiles":smiles + } + + else: + raise ValueError("Unknown input_type. It must be either 'structure' or 'fasta'.") + + return dict_output + + +# def calculate_peptide_molecular_weight(fasta_sequence): +# """ +# Calculates the molecular weight of a peptide sequence. + +# Parameters: +# fasta_sequence (str): The peptide sequence in FASTA format (e.g., "ACDEFG"). + +# Returns: +# mol_weight (float): The molecular weight of the peptide. +# """ +# # Amino acid molecular weights (average) +# amino_acid_weights = { +# 'A': 71.08, # Alanine +# 'C': 103.14, # Cysteine +# 'D': 115.09, # Aspartic acid +# 'E': 129.12, # Glutamic acid +# 'F': 147.18, # Phenylalanine +# 'G': 57.05, # Glycine +# 'H': 137.14, # Histidine +# 'I': 113.16, # Isoleucine +# 'K': 128.17, # Lysine +# 'L': 113.16, # Leucine +# 'M': 131.19, # Methionine +# 'N': 114.11, # Asparagine +# 'P': 97.12, # Proline +# 'Q': 128.13, # Glutamine +# 'R': 156.19, # Arginine +# 'S': 87.08, # Serine +# 'T': 101.11, # Threonine +# 'V': 99.14, # Valine +# 'W': 186.21, # Tryptophan +# 'Y': 163.18, # Tyrosine +# } + +# mol_weight = 0.0 +# for aa in fasta_sequence: +# if aa in amino_acid_weights: +# mol_weight += amino_acid_weights[aa] +# else: +# raise ValueError(f"Invalid amino acid: {aa}") + +# return mol_weight diff --git a/pIChemiSt/pichemist/api.py b/pIChemiSt/pichemist/api.py index ba39a13..02f7aec 100644 --- a/pIChemiSt/pichemist/api.py +++ b/pIChemiSt/pichemist/api.py @@ -2,9 +2,11 @@ from pichemist.config import REFERENCE_PKA_SET from pichemist.core import calculate_isoelectric_interval_and_threshold from pichemist.core import calculate_pI_pH_and_charge_dicts +from pichemist.core import compile_frags_pkas_for_output from pichemist.core import merge_matched_and_calculated_pkas from pichemist.fasta.matcher import FastaPKaMatcher from pichemist.model import InputAttribute +from pichemist.model import InputFormat from pichemist.model import MODELS from pichemist.model import OutputAttribute from pichemist.model import PKaMethod @@ -13,8 +15,6 @@ from pichemist.pka.acd import ACDPKaCalculator from pichemist.pka.pkamatcher import PKaMatcher from pichemist.plot import output_ph_q_curve -from rdkit import Chem -from rdkit.Chem import Draw class ApiException(Exception): @@ -26,6 +26,13 @@ def fasta_pkas_from_list(smiles_list): return FastaPKaMatcher().get_aa_pkas_from_list(smiles_list) +def fasta_pkas_from_aa_list(aa_list, ionizable_nterm, ionizable_cterm): + """Match pKas from FASTA definitions for a single-letter amino acids list.""" + return FastaPKaMatcher().get_aa_pkas_from_aa_list( + aa_list, ionizable_nterm, ionizable_cterm + ) + + def calculated_pkas_from_list(smiles_list, method): """Calculates pKa values using ACD or pKa Matcher.""" if method not in MODELS[PKaMethod]: @@ -33,154 +40,39 @@ def calculated_pkas_from_list(smiles_list, method): "Invalid method. Only the formats " f"{MODELS[PKaMethod]} are accepted" ) if method == PKaMethod.ACD.value: - base_pkas, acid_pkas, diacid_pkas = ACDPKaCalculator().calculate_pka_from_list( - smiles_list - ) + base_pkas, acid_pkas = ACDPKaCalculator().calculate_pka_from_list(smiles_list) if method == PKaMethod.PKA_MATCHER.value: - base_pkas, acid_pkas, diacid_pkas = PKaMatcher().calculate_pka_from_list( - smiles_list - ) - return base_pkas, acid_pkas, diacid_pkas - - -def calc_frags_for_output_fasta(ionization_type, pkas_fasta): - - D_pka = dict() - D_count = dict() - pka_sets_cnt = 0 - for pka_set, list_for_pka_set in pkas_fasta.items(): - pka_sets_cnt += 1 - for v in list_for_pka_set: - pka = v[0] - AA = v[1] - if AA in D_pka.keys(): - D_pka[AA].append(pka) - else: - D_pka[AA] = list() - - if pka_sets_cnt == 1: - if AA in D_count.keys(): - D_count[AA] += 1 - else: - D_count[AA] = 1 - - frag_pkas_fasta = dict() - idx = 0 - for k, v in D_pka.items(): - idx += 1 - frag_pkas_fasta[idx] = { - "type": ionization_type, - "frag": k, - "count": D_count[k], - "pka": sum(v) / len(v), - } - - return frag_pkas_fasta - - -def smiles_to_image(smiles, image_path, image_size=(300, 300)): - """ - Convert a SMILES string to a chemical structure image with a specified size. - - Parameters: - - smiles (str): The SMILES string representing the molecule. - - image_path (str): The file path where the image will be saved. - - image_size (tuple): The size of the image (width, height). - - Returns: - - None - """ - try: - # Convert SMILES to a molecule object - molecule = Chem.MolFromSmiles(smiles) - - # Check if the molecule was successfully created - if molecule is None: - raise ValueError("Invalid SMILES string.") - - # Generate the image with the specified size - image = Draw.MolToImage(molecule, size=image_size) - - # Save the image to the specified file path - image.save(image_path) - # print(f"Image saved successfully to {image_path}") - except Exception as e: - print(f"An error occurred: {e}") - + base_pkas, acid_pkas = PKaMatcher().calculate_pka_from_list(smiles_list) + return base_pkas, acid_pkas -def calc_frags_for_output_calc(ionization_type, pkas_calc): - # D_pka = dict() - # D_count = dict() - # for k2,v2 in pkas_calc: - # pka = v2[0] - # smi = v2[1] - # D_pka[smi].append(pka) - # if smi in D_count.keys(): - # D_count[smi]+=1 - # else: - # D_count[smi]=1 - - # frag_pkas_calc = dict() - # for k,v in D_pka.items(): - # frag_pkas_calc[k] = {'type':ionization_type,'frag':k, 'count':D_count[k], 'pka':sum(v) / len(v)} - - # TODO need to handle cases with multiple ionization in the same fragment. Apparently could only be done - # TODO if the index of fragment or alike is stored in pka_calc dictionary. Requires, some code refurbishment. - # Solution for now is to do not average out pka of identical fragment and display all with count 1 - frag_pkas_calc = dict() - frg_idx = 0 - for v in pkas_calc: - frg_idx += 1 - pka = v[0] - smi = v[1] - # frag_pkas_calc[frg_idx] = {'type':ionization_type,'frag':smi, 'count':1, 'pka':pka} - - image_path = "fragment_" + str(frg_idx) + ".png" - image_size = (500, 500) # Set the desired image size - smiles_to_image(smi, image_path, image_size) - frag_pkas_calc[frg_idx] = { - "type": ionization_type, - "frag": image_path, - "count": 1, - "pka": pka, - } - - return frag_pkas_calc - - -def compile_frags_pkas_for_output( - base_pkas_fasta, - acid_pkas_fasta, - diacid_pkas_fasta, - base_pkas_calc, - acid_pkas_calc, - diacid_pkas_calc, - net_qs_and_frags, -): +def pkas_and_charges_from_aa_list(aa_list, ionizable_nterm, ionizable_cterm): """ - Produces dictionary with fragmets (known AA or smiles fragment), their occurences in the molecule, corresponding pKa - (average between pKa sets in case of known AA) + Produces the pKa values for a list of AA in single letter FASTA format """ - frag_acid_pkas_fasta = calc_frags_for_output_fasta("acid", acid_pkas_fasta) - - frag_base_pkas_fasta = calc_frags_for_output_fasta("base", base_pkas_fasta) - - frag_acid_pkas_calc = calc_frags_for_output_calc("acid", acid_pkas_calc) - - frag_base_pkas_calc = calc_frags_for_output_calc("base", base_pkas_calc) - - frag_Qs_calc = calc_frags_for_output_calc("constant charge", net_qs_and_frags) + ( + base_pkas_fasta, + acid_pkas_fasta, + diacid_pkas_fasta, + ) = fasta_pkas_from_aa_list(aa_list, ionizable_nterm, ionizable_cterm) + # sic - Keeping these empty dict in output for consistency # TODO: Diacid dictionaries are not used, they are # deprecated and should be removed from the code + base_pkas_calc = dict() + acid_pkas_calc = dict() + diacid_pkas_calc = dict() + net_qs_and_frags = dict() + return ( - frag_acid_pkas_fasta, - frag_base_pkas_fasta, - frag_acid_pkas_calc, - frag_base_pkas_calc, - frag_Qs_calc, + base_pkas_fasta, + acid_pkas_fasta, + diacid_pkas_fasta, + base_pkas_calc, + acid_pkas_calc, + diacid_pkas_calc, + net_qs_and_frags, ) @@ -199,7 +91,7 @@ def pkas_and_charges_from_list(smiles_list, method): ) = fasta_pkas_from_list(smiles_list) # Unknown fragment calculation - base_pkas_calc, acid_pkas_calc, diacid_pkas_calc = calculated_pkas_from_list( + base_pkas_calc, acid_pkas_calc = calculated_pkas_from_list( unknown_frags, method=method ) @@ -213,7 +105,6 @@ def pkas_and_charges_from_list(smiles_list, method): diacid_pkas_fasta, base_pkas_calc, acid_pkas_calc, - diacid_pkas_calc, net_qs_and_frags, ) @@ -224,38 +115,52 @@ def pichemist_from_dict( ph_q_curve_file_prefix=None, plot_ph_q_curve=False, print_fragments=False, + ionizable_nterm=True, + ionizable_cterm=True, + generate_fragment_images=False, ): """Runs the full logic for a given input dictionary.""" dict_output = dict() for mol_idx in input_dict.keys(): - # Prepare molecule and break into fragments mol_name = input_dict[mol_idx][InputAttribute.MOL_NAME.value] - mol = input_dict[mol_idx][InputAttribute.MOL_OBJECT.value] - mol = MolStandardiser().standardise_molecule(mol) - smiles_list = PeptideCutter().break_amide_bonds_and_cap(mol) + fasta = input_dict[mol_idx].get(InputAttribute.MOL_FASTA.value) + mol = input_dict[mol_idx].get(InputAttribute.MOL_OBJECT.value) - # Calculate pKas and charges - ( - base_pkas_fasta, - acid_pkas_fasta, - diacid_pkas_fasta, - base_pkas_calc, - acid_pkas_calc, - diacid_pkas_calc, - net_qs_and_frags, - ) = pkas_and_charges_from_list(smiles_list, method) - ( - base_pkas_dict, - acid_pkas_dict, - diacid_pkas_dict, - ) = merge_matched_and_calculated_pkas( - base_pkas_fasta, - base_pkas_calc, - acid_pkas_fasta, - acid_pkas_calc, - diacid_pkas_fasta, - diacid_pkas_calc, + # Check input validity + if not any([mol, fasta]): + raise ApiException( + "Invalid input format. Neither a structure not a FASTA were provided." + ) + + # MOL overrides FASTA + if mol: + mol = MolStandardiser().standardise_molecule(mol) + smiles_list = PeptideCutter().break_amide_bonds_and_cap(mol) + ( + base_pkas_fasta, + acid_pkas_fasta, + diacid_pkas_fasta, + base_pkas_calc, + acid_pkas_calc, + net_qs_and_frags, + ) = pkas_and_charges_from_list(smiles_list, method) + + elif fasta: + aa_list = [char for char in fasta] + ( + base_pkas_fasta, + acid_pkas_fasta, + diacid_pkas_fasta, + base_pkas_calc, + acid_pkas_calc, + diacid_pkas_calc, + net_qs_and_frags, + ) = pkas_and_charges_from_aa_list(aa_list, ionizable_nterm, ionizable_cterm) + + # Merge pKas + (base_pkas_dict, acid_pkas_dict,) = merge_matched_and_calculated_pkas( + base_pkas_fasta, base_pkas_calc, acid_pkas_fasta, acid_pkas_calc ) # Recomple fragments and pKa for table output @@ -268,16 +173,15 @@ def pichemist_from_dict( ) = compile_frags_pkas_for_output( base_pkas_fasta, acid_pkas_fasta, - diacid_pkas_fasta, base_pkas_calc, acid_pkas_calc, - diacid_pkas_calc, net_qs_and_frags, + generate_fragment_images=generate_fragment_images, ) # Calculate the curves pI_dict, q_dict, pH_q_dict = calculate_pI_pH_and_charge_dicts( - base_pkas_dict, acid_pkas_dict, diacid_pkas_dict, net_qs_and_frags + base_pkas_dict, acid_pkas_dict, net_qs_and_frags ) # Calculate isoelectric interval @@ -295,7 +199,6 @@ def pichemist_from_dict( } # Plot pH/Q curve - ###AIF###if plot_ph_q_curve and not ph_q_curve_file_prefix: if plot_ph_q_curve and not isinstance(ph_q_curve_file_prefix, str): raise ApiException( "A file prefix for the pH/Q curve plots must " "be specified." @@ -309,18 +212,6 @@ def pichemist_from_dict( dict_output[mol_idx].update({OutputAttribute.PKA_SET.value: REFERENCE_PKA_SET}) if print_fragments: - # No need to include diacids pkas as they - # are included as single apparent ionisations - dict_output[mol_idx].update( - { - OutputAttribute.BASE_PKA_FASTA.value: base_pkas_fasta, - OutputAttribute.ACID_PKA_FASTA.value: acid_pkas_fasta, - OutputAttribute.BASE_PKA_CALC.value: base_pkas_calc, - OutputAttribute.ACID_PKA_CALC.value: acid_pkas_calc, - OutputAttribute.CONSTANT_QS.value: net_qs_and_frags, - } - ) - dict_output[mol_idx].update( { OutputAttribute.FRAG_BASE_PKA_FASTA.value: frag_base_pkas_fasta, diff --git a/pIChemiSt/pichemist/charges.py b/pIChemiSt/pichemist/charges.py index 82e20ee..676b237 100644 --- a/pIChemiSt/pichemist/charges.py +++ b/pIChemiSt/pichemist/charges.py @@ -1,6 +1,6 @@ +from pichemist.molecule import MolStandardiser from rdkit import Chem from rdkit import RDLogger -from pichemist.molecule import MolStandardiser RDLogger.DisableLog("rdApp.info") @@ -18,8 +18,7 @@ def __init__(self): def _prepare_patterns(self): """Converts SMARTS strings into objects.""" - return {name: Chem.MolFromSmarts(s) - for name, s in self.smarts.items()} + return {name: Chem.MolFromSmarts(s) for name, s in self.smarts.items()} def _get_mol_from_smiles(self, smiles): """Get mol object from SMILES.""" @@ -57,36 +56,34 @@ def calculate_net_qs_from_smiles(self, smiles): class PKaChargeCalculator(object): """Calculate the molecule charge given its pKas.""" + def __init__(self): pass def _calculate_basic_charge(self, pH, pKa): """Calculate charge contribution by basic pKas.""" - return 1 / (1 + 10**(pH - pKa)) + return 1 / (1 + 10 ** (pH - pKa)) def _calculate_acidic_charge(self, pH, pKa): """Calculate charge contribution by acidic pKas.""" - return -1 / (1 + 10**(pKa - pH)) + return -1 / (1 + 10 ** (pKa - pH)) def _calculate_diacidic_charge(self, pH, pKa1, pKa2): """Calculate charge contribution by diacidic pKas.""" - Ka1 = 10**(-pKa1) - Ka2 = 10**(-pKa2) - H = 10**(-pH) - f1 = (H*Ka1) / (H**2 + H*Ka1 + Ka1*Ka2) # fraction of [AH-] - f2 = f1 * Ka2 / H # fraction of [A2-] - return -2*f2 + (-1)*f1 # average charge of phosphate - - def calculate_charge(self, base_pkas, acid_pkas, diacid_pkas, - pH, constant_q=0): + Ka1 = 10 ** (-pKa1) + Ka2 = 10 ** (-pKa2) + H = 10 ** (-pH) + f1 = (H * Ka1) / (H**2 + H * Ka1 + Ka1 * Ka2) # fraction of [AH-] + f2 = f1 * Ka2 / H # fraction of [A2-] + return -2 * f2 + (-1) * f1 # average charge of phosphate + + def calculate_charge(self, base_pkas, acid_pkas, pH, constant_q=0): """Calculate the molecule charge from all contributions.""" charge = constant_q for pka in base_pkas: charge += self._calculate_basic_charge(pH, pka) for pka in acid_pkas: charge += self._calculate_acidic_charge(pH, pka) - for pkas in diacid_pkas: - charge += self._calculate_diacidic_charge(pH, pkas) return charge def calculate_constant_charge(self, net_qs): diff --git a/pIChemiSt/pichemist/cli.py b/pIChemiSt/pichemist/cli.py index cc68def..fa05e8d 100644 --- a/pIChemiSt/pichemist/cli.py +++ b/pIChemiSt/pichemist/cli.py @@ -10,6 +10,7 @@ from pichemist.model import OutputFormat from pichemist.model import PKaMethod from pichemist.utils import get_logger +from pichemist.utils import str2bool from rdkit import RDLogger # Configure logging @@ -33,7 +34,7 @@ def arg_parser(args): dest="input_format", help="Format of the input", choices=MODELS[InputFormat], - default=InputFormat.SMILES_FILE, + default=InputFormat.SMILES_FILE.value, ) parser.add_argument("-o", dest="output_file", help="Output filepath", default=None) parser.add_argument( @@ -41,7 +42,7 @@ def arg_parser(args): dest="output_format", help="Format of the output", choices=MODELS[OutputFormat], - default=OutputFormat.CONSOLE, + default=OutputFormat.CONSOLE.value, ) parser.add_argument( "--plot_ph_q_curve", @@ -63,11 +64,36 @@ def arg_parser(args): dest="print_fragment_pkas", help="Print the fragments with corresponding " "pKas used in pI calcution.", ) + parser.add_argument( + "--generate_fragment_images", + default=False, + action="store_true", + dest="generate_fragment_images", + help="Generate 2D depiction of the frgament smiles in base64 format.", + ) + parser.add_argument( + "--ionizable_nterm", + type=str2bool, + default=True, + dest="ionizable_nterm", + help="Applies to FASTA input only. " + "If set to 'false' the N-terminus is capped. " + "If set to 'true' the N-terminus is free amine. ", + ) + parser.add_argument( + "--ionizable_cterm", + type=str2bool, + default=True, + dest="ionizable_cterm", + help="Applies to FASTA input only. " + "If set to 'false' the C-terminus is capped. " + "If set to 'true' the C-terminus is free amine. ", + ) parser.add_argument( "--method", choices=MODELS[PKaMethod], - default=PKaMethod.PKA_MATCHER, - help="Method for the prediction of the " "pKa of unknown fragments", + default=PKaMethod.PKA_MATCHER.value, + help="Method for the prediction of the pKa of unknown fragments", ) if not args: args = ["-h"] @@ -80,9 +106,12 @@ def run_pichemist(args): output_dict = pichemist_from_dict( input_dict, args.method, - args.ph_q_curve_file_prefix, - args.plot_ph_q_curve, - args.print_fragment_pkas, + ph_q_curve_file_prefix=args.ph_q_curve_file_prefix, + plot_ph_q_curve=args.plot_ph_q_curve, + print_fragments=args.print_fragment_pkas, + ionizable_nterm=args.ionizable_nterm, + ionizable_cterm=args.ionizable_cterm, + generate_fragment_images=args.generate_fragment_images, ) output_results( input_dict, diff --git a/pIChemiSt/pichemist/core.py b/pIChemiSt/pichemist/core.py index dc81bba..1377297 100644 --- a/pIChemiSt/pichemist/core.py +++ b/pIChemiSt/pichemist/core.py @@ -2,6 +2,8 @@ from pichemist.fasta.matcher import FastaPKaMatcher from pichemist.isoelectric import CurveCalculator from pichemist.isoelectric import IsoelectricCalculator +from pichemist.model import OutputFragAttribute +from pichemist.molecule import smiles_to_image from pichemist.pka.utils import merge_pkas_lists from pichemist.stats import mean from pichemist.stats import stddev @@ -28,8 +30,7 @@ def generate_stats_on_dict(input_dict, mean_title="mean"): return input_dict -def get_low_and_high_from_interval_lists(interval_low_list, - interval_high_list): +def get_low_and_high_from_interval_lists(interval_low_list, interval_high_list): """ Processes interval lists to yield their averages. If molecule permanently has a charge, the interval is @@ -39,28 +40,25 @@ def get_low_and_high_from_interval_lists(interval_low_list, if len(interval_low_list) > 0: interval_low = mean(interval_low_list) else: - interval_low = float('NaN') + interval_low = float("NaN") if len(interval_high_list) > 0: interval_high = mean(interval_high_list) else: - interval_high = float('NaN') + interval_high = float("NaN") return interval_low, interval_high -def merge_matched_and_calculated_pkas(base_pkas_fasta, base_pkas_calc, - acid_pkas_fasta, acid_pkas_calc, - diacid_pkas_fasta, diacid_pkas_calc): +def merge_matched_and_calculated_pkas( + base_pkas_fasta, base_pkas_calc, acid_pkas_fasta, acid_pkas_calc +): """Merge FASTA-matched and calculated pKas.""" base_pkas_list = [base_pkas_fasta, base_pkas_calc] acid_pkas_list = [acid_pkas_fasta, acid_pkas_calc] - diacid_pkas_list = [diacid_pkas_fasta, diacid_pkas_calc] - base_pkas_dict, acid_pkas_dict, diacid_pkas_dict = \ - merge_pkas_lists(base_pkas_list, acid_pkas_list, diacid_pkas_list) - return base_pkas_dict, acid_pkas_dict, diacid_pkas_dict + base_pkas_dict, acid_pkas_dict = merge_pkas_lists(base_pkas_list, acid_pkas_list) + return base_pkas_dict, acid_pkas_dict -def calculate_pI_pH_and_charge_dicts(base_pkas_dict, acid_pkas_dict, - diacid_pkas_dict, net_qs_and_frags): +def calculate_pI_pH_and_charge_dicts(base_pkas_dict, acid_pkas_dict, net_qs_and_frags): """Calculates the isoelectric point, charges, and pH charges.""" pI_dict = dict() q_dict = dict() @@ -71,20 +69,19 @@ def calculate_pI_pH_and_charge_dicts(base_pkas_dict, acid_pkas_dict, # Merge fasta and calculated pkas base_pkas = base_pkas_dict[pka_set] acid_pkas = acid_pkas_dict[pka_set] - diacid_pkas = diacid_pkas_dict[pka_set] # Calculate isoelectric point net_qs = get_net_qs_from_qs_and_frags(net_qs_and_frags) constant_q = PKaChargeCalculator().calculate_constant_charge(net_qs) - q = PKaChargeCalculator().calculate_charge(base_pkas, acid_pkas, - diacid_pkas, pH=7.4, - constant_q=constant_q) - pI = IsoelectricCalculator().calculate_pI(base_pkas, acid_pkas, - diacid_pkas, - constant_q=constant_q) - pH_q = CurveCalculator().calculate_charged_curve(base_pkas, acid_pkas, - diacid_pkas, - constant_q=constant_q) + q = PKaChargeCalculator().calculate_charge( + base_pkas, acid_pkas, pH=7.4, constant_q=constant_q + ) + pI = IsoelectricCalculator().calculate_pI( + base_pkas, acid_pkas, constant_q=constant_q + ) + pH_q = CurveCalculator().calculate_charged_curve( + base_pkas, acid_pkas, constant_q=constant_q + ) pI_dict[pka_set] = pI q_dict[pka_set] = q pH_q_dict[pka_set] = pH_q @@ -107,14 +104,113 @@ def calculate_isoelectric_interval_and_threshold(pH_q_dict): # Calculate intervals across all sets for pka_set in FastaPKaMatcher().get_pka_sets_names(): - pH_int = IsoelectricCalculator().calculate_interval( - pH_q_dict[pka_set]) + pH_int = IsoelectricCalculator().calculate_interval(pH_q_dict[pka_set]) if len(pH_int) > 1: interval_low_list.append(pH_int[0]) interval_high_list.append(pH_int[-1]) # Average and return results - interval_low, interval_high = \ - get_low_and_high_from_interval_lists(interval_low_list, - interval_high_list) + interval_low, interval_high = get_low_and_high_from_interval_lists( + interval_low_list, interval_high_list + ) return (interval_low, interval_high), threshold + + +def compile_frags_pkas_for_output( + base_pkas_fasta, + acid_pkas_fasta, + base_pkas_calc, + acid_pkas_calc, + net_qs_and_frags, + generate_fragment_images=False, +): + """ + Produces dictionary with fragmets (known AA or smiles fragment), their occurences in the molecule, corresponding pKa + (average between pKa sets in case of known AA) + + """ + frag_acid_pkas_fasta = calculate_frags_for_output_fasta("acid", acid_pkas_fasta) + frag_base_pkas_fasta = calculate_frags_for_output_fasta("base", base_pkas_fasta) + frag_acid_pkas_calc = calculate_frags_for_output_calc( + "acid", + acid_pkas_calc, + generate_fragment_images=generate_fragment_images, + ) + frag_base_pkas_calc = calculate_frags_for_output_calc( + "base", + base_pkas_calc, + generate_fragment_images=generate_fragment_images, + ) + frag_Qs_calc = calculate_frags_for_output_calc( + "constant charge", + net_qs_and_frags, + generate_fragment_images=generate_fragment_images, + ) + return ( + frag_acid_pkas_fasta, + frag_base_pkas_fasta, + frag_acid_pkas_calc, + frag_base_pkas_calc, + frag_Qs_calc, + ) + + +def calculate_frags_for_output_calc( + ionization_type, pkas_calc, generate_fragment_images=False +): + """ + Generates a dictionary of fragments with their pKas. + Images can additionally be included. + + """ + frag_pkas_calc = dict() + frg_idx = 0 + for v in pkas_calc: + frg_idx += 1 + pka = v[0] + smi = v[1] + + frag_pkas_calc[frg_idx] = { + OutputFragAttribute.TYPE: ionization_type, + OutputFragAttribute.FRAGMENT: smi, + OutputFragAttribute.COUNT: 1, + OutputFragAttribute.PKA: pka, + } + + base64_image = None + if generate_fragment_images: + frag_pkas_calc[frg_idx][OutputFragAttribute.IMAGE] = smiles_to_image(smi) + return frag_pkas_calc + + +def calculate_frags_for_output_fasta(ionization_type, pkas_fasta): + """Generates a dictionary of fragments with their pKas.""" + pka_dict = dict() + count_dict = dict() + pka_sets_count = 0 + for pka_set, list_for_pka_set in pkas_fasta.items(): + pka_sets_count += 1 + for v in list_for_pka_set: + pka = v[0] + aa = v[1] + if aa in pka_dict.keys(): + pka_dict[aa].append(pka) + else: + pka_dict[aa] = list() + if pka_sets_count == 1: + if aa in count_dict.keys(): + count_dict[aa] += 1 + else: + count_dict[aa] = 1 + + frag_pkas_fasta = dict() + idx = 0 + for k, v in pka_dict.items(): + idx += 1 + frag_pkas_fasta[idx] = { + OutputFragAttribute.TYPE: ionization_type, + OutputFragAttribute.FRAGMENT: k, + OutputFragAttribute.COUNT: count_dict[k], + OutputFragAttribute.PKA: sum(v) / len(v), + } + return frag_pkas_fasta diff --git a/pIChemiSt/pichemist/fasta/matcher.py b/pIChemiSt/pichemist/fasta/matcher.py index d36b824..9fb53c5 100755 --- a/pIChemiSt/pichemist/fasta/matcher.py +++ b/pIChemiSt/pichemist/fasta/matcher.py @@ -173,6 +173,78 @@ def _get_aa_pkas(self, smiles, unknown_fragments.append(smiles) return unknown_fragments, base_pka_dict, acid_pka_dict, diacid_pka_dict + + + def _get_aa_pkas_from_single_letter_aa(self, aa, + base_pka_dict, + acid_pka_dict, + diacid_pka_dict, # sic - not used + pka_sets, + aa_position_in_sequence, + ): + """ + For a given amino acids in single letter format, + it matches its pKa + value against a set of pKa sets. + """ + + # Middle + if aa_position_in_sequence == "middle": + CAPPED_IDX = 0 + for n, pka_set in pka_sets.items(): + self._add_pka_to_acidic_and_basic_dicts(aa, n, + base_pka_dict, + acid_pka_dict, + pka_set, + CAPPED_IDX) + + # N-term, sidechains + elif aa_position_in_sequence == "nterm sidechains": + NTERM_FREE_IDX = 1 + for n, pka_set in pka_sets.items(): + self._add_pka_to_acidic_and_basic_dicts(aa, n, + base_pka_dict, + acid_pka_dict, + pka_set, + NTERM_FREE_IDX) + + # N-term, nterm + elif aa_position_in_sequence == "nterm nterm": + NTERM_ION_IDX = 0 + for n, pka_set in pka_sets.items(): + self._add_terminus_ionizable_to_dict(aa, n, + base_pka_dict, + pka_set, + "N-term", + NTERM_ION_IDX) + + # C-term, sidechains + elif aa_position_in_sequence == "cterm sidechains": + CTERM_FREE_IDX = 2 + for n, pka_set in pka_sets.items(): + self._add_pka_to_acidic_and_basic_dicts(aa, n, + base_pka_dict, + acid_pka_dict, + pka_set, + CTERM_FREE_IDX) + + # C-term, cterm + elif aa_position_in_sequence == "cterm cterm": + CTERM_ION_IDX = 1 + for n, pka_set in pka_sets.items(): + self._add_terminus_ionizable_to_dict(aa, n, + acid_pka_dict, + pka_set, + "C-term", + CTERM_ION_IDX) + + else: + raise ValueError("aa_position_in_sequemce no known in function _get_aa_pkas_from_single_letter_aa" ) + + return base_pka_dict, acid_pka_dict, diacid_pka_dict + + + def get_aa_pkas_from_list(self, smiles_list): """ Matches a list of SMILES against @@ -194,3 +266,107 @@ def get_aa_pkas_from_list(self, smiles_list): acid_pka_dict, diacid_pka_dict, pka_sets) return unknown_fragments, base_pka_dict,\ acid_pka_dict, diacid_pka_dict + + + + def get_aa_pkas_from_aa_list(self,aa_list,ionizable_nterm,ionizable_cterm): + """ + Matches a list of sigle-letter aminoa acids against + the pKa values in a set of pKa sets. + + """ + # Initialise pKa sets + pka_sets = self._initialise_pka_sets() + + # Initialise results + base_pka_dict, acid_pka_dict, diacid_pka_dict = \ + self._initialise_pka_dicts(PKA_SETS_NAMES) + + # ionizable both N- and C-termini + if ionizable_cterm and ionizable_nterm: + aa_middle_list = aa_list[1:-1] + aa_nterm_ionizable_sidechain_list = [aa_list[0]] + aa_nterm_ionizable_nterm_list = [aa_list[0]] + aa_cterm_ionizable_sidechain_list = [aa_list[-1]] + aa_cterm_ionizable_cterm_list = [aa_list[-1]] + + # capped C-terminus, sidechain still ionizable + elif not ionizable_cterm and ionizable_nterm: + aa_middle_list = aa_list[1:-1] + aa_nterm_ionizable_sidechain_list = [aa_list[0]] + aa_nterm_ionizable_nterm_list = [aa_list[0]] + aa_cterm_ionizable_sidechain_list = [aa_list[-1]] + aa_cterm_ionizable_cterm_list = [] + + # capped N-terminus, sidechain still ionizable + elif ionizable_cterm and not ionizable_nterm: + aa_middle_list = aa_list[1:-1] + aa_nterm_ionizable_sidechain_list = [aa_list[0]] + aa_nterm_ionizable_nterm_list = [] + aa_cterm_ionizable_sidechain_list = [aa_list[-1]] + aa_cterm_ionizable_cterm_list = [aa_list[-1]] + + # capped both N- and C-termimi, sidechain still ionizable + elif not ionizable_cterm and not ionizable_nterm: + aa_middle_list = aa_list[1:-1] + aa_nterm_ionizable_sidechain_list = [aa_list[0]] + aa_nterm_ionizable_nterm_list = [] + aa_cterm_ionizable_sidechain_list = [aa_list[-1]] + aa_cterm_ionizable_cterm_list = [] + + # Middle + for aa in aa_middle_list: + aa_position_in_sequence = 'middle' + base_pka_dict,acid_pka_dict, diacid_pka_dict = self._get_aa_pkas_from_single_letter_aa( + aa, base_pka_dict, + acid_pka_dict, + diacid_pka_dict, + pka_sets, + aa_position_in_sequence + ) + + # N-term, sidechains + for aa in aa_nterm_ionizable_sidechain_list: + aa_position_in_sequence = 'nterm sidechains' + base_pka_dict,acid_pka_dict,diacid_pka_dict = self._get_aa_pkas_from_single_letter_aa( + aa, base_pka_dict, + acid_pka_dict, + diacid_pka_dict, + pka_sets, + aa_position_in_sequence + ) + + # N-term, termini + for aa in aa_nterm_ionizable_nterm_list: + aa_position_in_sequence = 'nterm nterm' + base_pka_dict,acid_pka_dict,diacid_pka_dict = self._get_aa_pkas_from_single_letter_aa( + aa, base_pka_dict, + acid_pka_dict, + diacid_pka_dict, + pka_sets, + aa_position_in_sequence + ) + + # C-term, sidechains + for aa in aa_cterm_ionizable_sidechain_list: + aa_position_in_sequence = 'cterm sidechains' + base_pka_dict,acid_pka_dict,diacid_pka_dict = self._get_aa_pkas_from_single_letter_aa( + aa, base_pka_dict, + acid_pka_dict, + diacid_pka_dict, + pka_sets, + aa_position_in_sequence + ) + + # C-term, termini + for aa in aa_cterm_ionizable_cterm_list: + aa_position_in_sequence = 'cterm cterm' + base_pka_dict,acid_pka_dict,diacid_pka_dict = self._get_aa_pkas_from_single_letter_aa( + aa, base_pka_dict, + acid_pka_dict, + diacid_pka_dict, + pka_sets, + aa_position_in_sequence + ) + + return base_pka_dict,acid_pka_dict,diacid_pka_dict diff --git a/pIChemiSt/pichemist/io.py b/pIChemiSt/pichemist/io.py index 2214543..332b079 100644 --- a/pIChemiSt/pichemist/io.py +++ b/pIChemiSt/pichemist/io.py @@ -20,7 +20,7 @@ class IOException(Exception): pass -def generate_input(input_format, input_data, fasta=None): +def generate_input(input_format, input_data): """Produces an input dictionary compatible with the API.""" input_dict = dict() if input_format == InputFormat.SMILES_FILE or input_format == InputFormat.SD_FILE: @@ -29,14 +29,16 @@ def generate_input(input_format, input_data, fasta=None): input_dict[1] = { InputAttribute.MOL_NAME.value: input_data, InputAttribute.MOL_OBJECT.value: Chem.MolFromSmiles(input_data), - InputAttribute.MOL_FASTA.value: fasta, + InputAttribute.MOL_FASTA.value: None, } if input_format == InputFormat.FASTA_STDIN: input_dict[1] = { InputAttribute.MOL_NAME.value: input_data, - InputAttribute.MOL_OBJECT.value: Chem.MolFromFASTA(input_data), - InputAttribute.MOL_FASTA.value: fasta, + InputAttribute.MOL_OBJECT.value: None, + InputAttribute.MOL_FASTA.value: input_data, } + if input_format == InputFormat.FASTA_FILE: + input_dict = read_fasta_file(input_data) return input_dict @@ -80,6 +82,40 @@ def read_structure_file(input_filepath): return dict_input +def read_fasta_file(input_filepath): + """ + Reads a file containing FASTA entries using BioPython. + + """ + # TODO: Move into utils + # filename, ext = os.path.splitext(inputFile) + _, ext = os.path.splitext(input_filepath) + + # Initialize file reader + if not ext == ".fasta": + raise Exception( + '!Warning: extension of file is not ".fasta". Assuming it is fasta formatted input. Continue. ' + ) + + # use BioPython + from Bio import SeqIO + + biosuppl = SeqIO.parse(open(input_filepath), "fasta") + + # Populate input and assign properties + dict_input = dict() + uuid = 1 + for biofasta in biosuppl: + dict_input[uuid] = { + InputAttribute.MOL_NAME.value: biofasta.id, + InputAttribute.MOL_OBJECT.value: None, + InputAttribute.MOL_FASTA.value: str(biofasta.seq), + } + uuid += 1 + + return dict_input + + def _format_results_for_console_output(prop_dict, prop): """Prints a formatted output for a dictionary of results.""" lj = 12 @@ -116,7 +152,6 @@ def _output_text_to_console(dict_output, method, print_fragments=False): ) int_tr = dict_mol[OutputAttribute.PI_INTERVAL_THRESHOLD.value] - pka_set = dict_mol[OutputAttribute.PKA_SET.value] print( "\npH interval with charge between %4.1f and %4.1f and " @@ -131,47 +166,54 @@ def _output_text_to_console(dict_output, method, print_fragments=False): ) if print_fragments: - base_pkas_fasta = dict_mol[OutputAttribute.BASE_PKA_FASTA.value] - acid_pkas_fasta = dict_mol[OutputAttribute.ACID_PKA_FASTA.value] - base_pkas_calc = dict_mol[OutputAttribute.BASE_PKA_CALC.value] - acid_pkas_calc = dict_mol[OutputAttribute.ACID_PKA_CALC.value] - constant_Qs_calc = dict_mol[OutputAttribute.CONSTANT_QS.value] - - # Merge fasta and calculated pKas - base_pkas = base_pkas_fasta[pka_set] + base_pkas_calc - acid_pkas = acid_pkas_fasta[pka_set] + acid_pkas_calc - all_base_pkas = list() - acid_pkas = list() - - # NOTE: Diacids prints disabled - # diacid_pkas_fasta = dict_mol["diacid_pkas_fasta"] - # diacid_pkas_calc = dict_mol["diacid_pkas_calc"] - # diacid_pkas = diacid_pkas_fasta[pka_set] + diacid_pkas_calc - # diacid_pkas = list() - - # Zip values and structures - all_base_pkas, all_base_pkas_smi = list(), list() - acid_pkas, all_acid_pkas_smi = list(), list() - if len(base_pkas) != 0: - all_base_pkas, all_base_pkas_smi = zip(*base_pkas) - if len(acid_pkas) != 0: - acid_pkas, all_acid_pkas_smi = zip(*acid_pkas) + frag_base_pkas_fasta = dict_mol[OutputAttribute.FRAG_BASE_PKA_FASTA.value] + frag_acid_pkas_fasta = dict_mol[OutputAttribute.FRAG_ACID_PKA_FASTA.value] + frag_base_pkas_calc = dict_mol[OutputAttribute.FRAG_BASE_PKA_CALC.value] + frag_acid_pkas_calc = dict_mol[OutputAttribute.FRAG_ACID_PKA_CALC.value] + frag_constant_Qs_calc = dict_mol[OutputAttribute.FRAG_CONSTANT_QS.value] # Print the results - print("\nList of calculated BASE pKa values with their fragments") - for pkas, smi in zip(all_base_pkas, all_base_pkas_smi): - s_pkas = ["%4.1f" % (pkas)] - print("smiles or AA, base pKa : %-15s %s" % (smi, " ".join(s_pkas))) - print("\nList of calculated ACID pKa values with their fragments") - for pkas, smi in zip(acid_pkas, all_acid_pkas_smi): - s_pkas = ["%4.1f" % (pkas)] - print("smiles or AA, acid pKa : %-15s %s" % (smi, " ".join(s_pkas))) - print("\nList of constantly ionized fragments") - for v in constant_Qs_calc: - pkas = v[0] - smi = v[1] - s_pkas = ["%4.1f" % (pkas)] - print("smiles, charge : %-15s %s" % (smi, " ".join(s_pkas))) + print("\nList of calculated pKa values or constant charges") + format_header = "{:15s} {:5s} {:17s} {:s}" + format_results = "{:15s} {:5d} {:17.1f} {:s}" + print( + format_header.format("Type", "Count", "pKa_or_constant_Q", "Fragment") + ) + + for _, frag in frag_base_pkas_fasta.items(): + print( + format_results.format( + frag["type"], frag["count"], frag["pka"], frag["frag"] + ) + ) + + for _, frag in frag_base_pkas_calc.items(): + print( + format_results.format( + frag["type"], frag["count"], frag["pka"], frag["frag"] + ) + ) + + for _, frag in frag_acid_pkas_fasta.items(): + print( + format_results.format( + frag["type"], frag["count"], frag["pka"], frag["frag"] + ) + ) + + for _, frag in frag_acid_pkas_calc.items(): + print( + format_results.format( + frag["type"], frag["count"], frag["pka"], frag["frag"] + ) + ) + + for _, frag in frag_constant_Qs_calc.items(): + print( + format_results.format( + frag["type"], frag["count"], frag["pka"], frag["frag"] + ) + ) def output_results( @@ -223,10 +265,6 @@ def _prepare_output_list(input_dict, output_dict): "pI mean", "%.2f" % output_dict[mi][OutputAttribute.PI.value]["pI mean"] ) mol.SetProp("pI std", "%.2f" % output_dict[mi][OutputAttribute.PI.value]["std"]) - # NOTE: String interval is disabled - # print(output_dict[mi][PI_INTERVAL.value]) - # mol.SetProp("pI interval", " - ".join( - # ["%.2f" % x for x in output_dict[mi][PI_INTERVAL.value]])) mol.SetProp( "pI interval lower bound", "%.2f" % output_dict[mi][OutputAttribute.PI_INTERVAL.value][0], diff --git a/pIChemiSt/pichemist/isoelectric.py b/pIChemiSt/pichemist/isoelectric.py index 64771fb..5779e05 100644 --- a/pIChemiSt/pichemist/isoelectric.py +++ b/pIChemiSt/pichemist/isoelectric.py @@ -1,5 +1,4 @@ import numpy as np - from pichemist.charges import PKaChargeCalculator from pichemist.utils import get_logger @@ -23,7 +22,7 @@ def _define_pH_range(self): def _define_charge_range(self): """Sets the charge range (Y axis).""" - return self.pH_range*0.0 + return self.pH_range * 0.0 def get_pH_span(self): """ @@ -33,13 +32,12 @@ def get_pH_span(self): """ return [self.pH_lower_bound, self.pH_upper_bound] - def calculate_charged_curve(self, base_pkas, acid_pkas, - diacid_pkas, constant_q=0): + def calculate_charged_curve(self, base_pkas, acid_pkas, constant_q=0): """Calculates the pH/Q curve.""" for i in range(len(self.pH_range)): charge = PKaChargeCalculator().calculate_charge( - base_pkas, acid_pkas, diacid_pkas, - self.pH_range[i], constant_q=constant_q) + base_pkas, acid_pkas, self.pH_range[i], constant_q=constant_q + ) self.q_range[i] = charge return np.vstack((self.pH_range, self.q_range)).T @@ -55,8 +53,7 @@ def __init__(self): self.lower_pH = self.pH_limit[0] self.higher_pH = self.pH_limit[1] - def calculate_pI(self, base_pkas, acid_pkas, - diacid_pkas, constant_q=0): + def calculate_pI(self, base_pkas, acid_pkas, constant_q=0): """ Uses the pKas and charge to iteratively calculate the isoelectric point of a molecule. @@ -65,22 +62,27 @@ def calculate_pI(self, base_pkas, acid_pkas, while True: self.middle_pH = 0.5 * (self.higher_pH + self.lower_pH) charge = PKaChargeCalculator().calculate_charge( - base_pkas, acid_pkas, diacid_pkas, - self.middle_pH, constant_q=constant_q) - na = len(acid_pkas) + len(diacid_pkas) + base_pkas, acid_pkas, self.middle_pH, constant_q=constant_q + ) + na = len(acid_pkas) nb = len(base_pkas) if na == 0 and nb != 0: - log.debug("Warning: no acidic ionizable groups, " - "only basic groups present in the " - "sequence. pI is not defined and thus " - "won't be calculated""") + log.debug( + "Warning: no acidic ionizable groups, " + "only basic groups present in the " + "sequence. pI is not defined and thus " + "won't be calculated" + "" + ) reference_charge = self.charge_tolerance * nb elif nb == 0 and na != 0: - log.debug("Warning: no basic ionizable groups, " - "only acidic groups present in the " - "sequence. pI is not defined and thus " - "won't be calculated""") + log.debug( + "Warning: no basic ionizable groups, " + "only acidic groups present in the " + "sequence. pI is not defined and thus " + "won't be calculated" + ) reference_charge = -self.charge_tolerance * na else: reference_charge = 0.0 @@ -105,5 +107,4 @@ def calculate_interval(self, pH_q): """Calculates the isoelectric interval.""" q = pH_q[:, 1] pH = pH_q[:, 0] - return (pH[(q > -self.interval_threshold) - & (q < self.interval_threshold)]) + return pH[(q > -self.interval_threshold) & (q < self.interval_threshold)] diff --git a/pIChemiSt/pichemist/model.py b/pIChemiSt/pichemist/model.py index 337c541..e4654e3 100644 --- a/pIChemiSt/pichemist/model.py +++ b/pIChemiSt/pichemist/model.py @@ -34,6 +34,7 @@ class InputFormat(BaseEnum): SMILES_STDIN = "smiles_stdin" SMILES_FILE = "smiles_file" FASTA_STDIN = "fasta_stdin" + FASTA_FILE = "fasta_file" SD_FILE = "sdf" @@ -51,11 +52,6 @@ class OutputAttribute(BaseEnum): PI_INTERVAL_THRESHOLD = "pI_interval_threshold" PLOT_FILENAME = "plot_filename" PKA_SET = "pKa_set" - BASE_PKA_FASTA = "base_pkas_fasta" - ACID_PKA_FASTA = "acid_pkas_fasta" - BASE_PKA_CALC = "base_pkas_calc" - ACID_PKA_CALC = "acid_pkas_calc" - CONSTANT_QS = "constant_Qs_calc" FRAG_BASE_PKA_FASTA = "frag_base_pkas_fasta" FRAG_ACID_PKA_FASTA = "frag_acid_pkas_fasta" FRAG_BASE_PKA_CALC = "frag_base_pkas_calc" @@ -63,6 +59,14 @@ class OutputAttribute(BaseEnum): FRAG_CONSTANT_QS = "frag_Qs_calc" +class OutputFragAttribute(BaseEnum): + TYPE = "type" + COUNT = "count" + PKA = "pka" + FRAGMENT = "frag" + IMAGE = "base64_image" + + class OutputFormat(BaseEnum): JSON = "json" SD_FILE = "sdf" diff --git a/pIChemiSt/pichemist/molecule.py b/pIChemiSt/pichemist/molecule.py index 42b267c..8719e80 100644 --- a/pIChemiSt/pichemist/molecule.py +++ b/pIChemiSt/pichemist/molecule.py @@ -1,7 +1,12 @@ +import base64 from enum import Enum +from io import BytesIO + +from pichemist.utils import get_logger from rdkit import Chem +from rdkit.Chem import Draw +from rdkit.Chem import rdDepictor from rdkit.Chem.MolStandardize import rdMolStandardize -from pichemist.utils import get_logger log = get_logger(__name__) @@ -25,8 +30,9 @@ def neutralise_molecule(self, mol): https://www.rdkit.org/docs/Cookbook.html """ - ION_SMARTS = "[+1!h0!$([*]~[-1,-2,-3,-4])" \ - ",-1!$([*]~[+1,+2,+3,+4])]" + ION_SMARTS = ( + "[+1!h0!$([*]~[-1,-2,-3,-4]),-1!$([*]~[+1,+2,+3,+4])]" # noqa: E501 + ) pattern = Chem.MolFromSmarts(ION_SMARTS) at_matches = mol.GetSubstructMatches(pattern) @@ -100,7 +106,7 @@ def break_amide_bonds_and_cap(self, mol): """ # Secondary and tertiary amide bonds - AMIDE_SMARTS = '[NX3,NX4;H0,H1][CX3](=[OX1])' + AMIDE_SMARTS = "[NX3,NX4;H0,H1][CX3](=[OX1])" amide_pattern = Chem.MolFromSmarts(AMIDE_SMARTS) amide_atoms = list() @@ -116,3 +122,15 @@ def break_amide_bonds_and_cap(self, mol): smiles_list = smiles.split(".") log.debug(f"Obtained {len(smiles_list)} fragments") return smiles_list + + +def smiles_to_image(smiles, b64encode=True): + mol = Chem.MolFromSmiles(smiles) + rdDepictor.Compute2DCoords(mol) + img = Draw.MolToImage(mol, kekulize=True) + buffered = BytesIO() + img.save(buffered, format="PNG") + img_byte_data = buffered.getvalue() + if b64encode: + base64_image = base64.b64encode(img_byte_data).decode("utf-8") + return base64_image diff --git a/pIChemiSt/pichemist/pka/acd.py b/pIChemiSt/pichemist/pka/acd.py index 954e73b..6d8c7fa 100644 --- a/pIChemiSt/pichemist/pka/acd.py +++ b/pIChemiSt/pichemist/pka/acd.py @@ -1,6 +1,6 @@ import os -import tempfile import subprocess +import tempfile from pichemist.config import ACD_METHOD from pichemist.config import PKA_LIMITS @@ -12,6 +12,7 @@ class ACDPKaException(Exception): class ACDPKaCalculator(object): """Uses ACD perceptabat to calculate pKa values.""" + def __init__(self): self.input_filepath = self._get_temp_filepath(".smi") self.output_filepath = self._get_temp_filepath(".out") @@ -22,8 +23,7 @@ def _get_pka_flag(self): def _get_temp_filepath(self, suffix): """Gets a temporary filepath and closes the file.""" - file = tempfile.NamedTemporaryFile( - suffix=suffix) + file = tempfile.NamedTemporaryFile(suffix=suffix) path = file.name file.close() return path @@ -38,19 +38,20 @@ def _prepare_temp_input_file(self, smi_list): def _get_temp_output_filepath(self): """Gets a temporary filepath and closes the file.""" - file = tempfile.NamedTemporaryFile( - suffix=".out") + file = tempfile.NamedTemporaryFile(suffix=".out") path = file.name file.close() return path def _build_command(self): """Builds the perceptabat command to run pKa prediction.""" - return ["perceptabat", - f"-TFNAME{self.output_filepath}", - self.pka_flag, - "-TPKA", - self.input_filepath] + return [ + "perceptabat", + f"-TFNAME{self.output_filepath}", + self.pka_flag, + "-TPKA", + self.input_filepath, + ] def _get_status_output(self, *args, **kwargs): p = subprocess.Popen(*args, **kwargs) @@ -58,16 +59,17 @@ def _get_status_output(self, *args, **kwargs): return p.returncode, stdout, stderr def _run_acd_exe(self, cmd): - status, stdout, stderr = \ - self._get_status_output(cmd, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) + status, stdout, stderr = self._get_status_output( + cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT + ) if status != 0: - raise ACDPKaException(f"""Error while running the ACD subprocess: + raise ACDPKaException( + f"""Error while running the ACD subprocess: status: {status} command: {cmd} stdout: {stdout} - stderr: {stderr}""") + stderr: {stderr}""" + ) def _check_existence_output(self): if not os.path.isfile(self.output_filepath): @@ -84,28 +86,20 @@ def _parse_output(self, smi_list): with open(self.output_filepath, "r") as f: base_pkas = list() acid_pkas = list() - diacid_pkas = list() - D = {} # sic - global variable unused f.readline() # skip first line for line in f.readlines(): ln = line.split() mol_idx = int(ln[0]) - if mol_idx not in D.keys(): - D[mol_idx] = {} # sic - global variable unused if "ACD_pKa_Apparent" in ln[1]: pka = float(ln[2]) if "ACD_pKa_DissType_Apparent" in ln[1]: if ln[2] in ["MB", "B"]: - if pka > PKA_LIMITS["base_1"] and \ - pka < PKA_LIMITS["base_2"]: - base_pkas.append( - (pka, smi_list[mol_idx-1])) + if pka > PKA_LIMITS["base_1"] and pka < PKA_LIMITS["base_2"]: + base_pkas.append((pka, smi_list[mol_idx - 1])) if ln[2] in ["MA", "A"]: - if pka > PKA_LIMITS["acid_1"] and \ - pka < PKA_LIMITS["acid_2"]: - acid_pkas.append( - (pka, smi_list[mol_idx-1])) - return (base_pkas, acid_pkas, diacid_pkas) + if pka > PKA_LIMITS["acid_1"] and pka < PKA_LIMITS["acid_2"]: + acid_pkas.append((pka, smi_list[mol_idx - 1])) + return (base_pkas, acid_pkas) def calculate_pka_from_list(self, smi_list): """Calculates the pKa values of a list of SMILES.""" diff --git a/pIChemiSt/pichemist/pka/pkamatcher.py b/pIChemiSt/pichemist/pka/pkamatcher.py index c397296..79778f5 100644 --- a/pIChemiSt/pichemist/pka/pkamatcher.py +++ b/pIChemiSt/pichemist/pka/pkamatcher.py @@ -1,9 +1,9 @@ -from rdkit import Chem -from pichemist.config import SKIP_SMARTS_NAMES from pichemist.config import PKA_LIMITS -from pichemist.smarts.pka_set import SS_SMARTS_PKA_SET +from pichemist.config import SKIP_SMARTS_NAMES from pichemist.model import MODELS from pichemist.model import PKaType +from pichemist.smarts.pka_set import SS_SMARTS_PKA_SET +from rdkit import Chem class PKaMatcher(object): @@ -12,6 +12,7 @@ class PKaMatcher(object): against input SMILES to match their pKa(s). """ + def __init__(self): self.smarts_set = SS_SMARTS_PKA_SET self.skip_names = SKIP_SMARTS_NAMES @@ -25,8 +26,7 @@ def _pka_dict_from_smiles(self, smiles: str): the SMILES are added to the results. """ - results = {PKaType.ACIDIC.value: list(), - PKaType.BASIC.value: list()} + results = {PKaType.ACIDIC.value: list(), PKaType.BASIC.value: list()} mol = Chem.MolFromSmiles(smiles) all_used_idxs_set = set() # Each group is described as a list of dicts @@ -34,36 +34,45 @@ def _pka_dict_from_smiles(self, smiles: str): for pka_dict in pka_group_list: # Skip if name is included in skip config - if pka_dict['name'] in self.skip_names: + if pka_dict["name"] in self.skip_names: continue # Match SMARTS against the input and store pKa - used_idx_list = list() # Used within larger scope + used_idx_list = list() # Used within larger scope used_idx_local = list() # Used within smaller scope - pat = Chem.MolFromSmarts(pka_dict['smarts']) + pat = Chem.MolFromSmarts(pka_dict["smarts"]) for match in mol.GetSubstructMatches(pat): - match_idx = match[pka_dict['idx']-1] + match_idx = match[pka_dict["idx"] - 1] used_idx_list += match match_idxs = set(match) available_idxs = match_idxs.difference(all_used_idxs_set) - pka = pka_dict['pka'] - if pka_dict['type'] not in MODELS[PKaType]: + pka = pka_dict["pka"] + if pka_dict["type"] not in MODELS[PKaType]: raise PKaMatcherException( - f"Unknown site type (got {pka_dict['type']})") + f"Unknown site type (got {pka_dict['type']})" + ) # Basic - if pka_dict['type'] == PKaType.BASIC.value: - if match_idx in available_idxs \ - and match_idx not in used_idx_local: - if pka > PKA_LIMITS["base_1"] \ - and pka < PKA_LIMITS["base_2"]: + if pka_dict["type"] == PKaType.BASIC.value: + if ( + match_idx in available_idxs + and match_idx not in used_idx_local + ): + if ( + pka > PKA_LIMITS["base_1"] + and pka < PKA_LIMITS["base_2"] + ): results["base"].append((pka, smiles)) # Acidic - if pka_dict['type'] == PKaType.ACIDIC.value: - if match_idx in available_idxs \ - and match_idx not in used_idx_local: - if pka > PKA_LIMITS["acid_1"] \ - and pka < PKA_LIMITS["acid_2"]: + if pka_dict["type"] == PKaType.ACIDIC.value: + if ( + match_idx in available_idxs + and match_idx not in used_idx_local + ): + if ( + pka > PKA_LIMITS["acid_1"] + and pka < PKA_LIMITS["acid_2"] + ): results["acid"].append((pka, smiles)) used_idx_local.append(match_idx) all_used_idxs_set = all_used_idxs_set.union(set(used_idx_list)) @@ -72,20 +81,18 @@ def _pka_dict_from_smiles(self, smiles: str): def calculate_pka_from_smiles(self, smiles: str): """Calculates the pKa values for a SMILES.""" results = self._pka_dict_from_smiles(smiles) - return {k: [t[0] for t in v] - for k, v in results.items()} + return {k: [t[0] for t in v] for k, v in results.items()} def calculate_pka_from_list(self, smiles_list: list): """Calculates the pKa values for a list of SMILES.""" base_pkas = list() acid_pkas = list() - diacid_pkas = list() # not used at the moment for smiles in smiles_list: results = self._pka_dict_from_smiles(smiles) base_pkas.extend(results[PKaType.BASIC.value]) acid_pkas.extend(results[PKaType.ACIDIC.value]) - return (base_pkas, acid_pkas, diacid_pkas) + return (base_pkas, acid_pkas) class PKaMatcherException(Exception): diff --git a/pIChemiSt/pichemist/pka/utils.py b/pIChemiSt/pichemist/pka/utils.py index c84adfc..c1c350b 100644 --- a/pIChemiSt/pichemist/pka/utils.py +++ b/pIChemiSt/pichemist/pka/utils.py @@ -16,24 +16,18 @@ def _unpack_pka_list(pka_list): return pka_list[0], pka_list[1] -def merge_pkas_lists(base_pkas_list, acid_pkas_list, diacid_pkas_list): +def merge_pkas_lists(base_pkas_list, acid_pkas_list): # Initialise the merged pKa lists base_pkas = dict() acid_pkas = dict() - diacid_pkas = dict() # Unpack the pKa values base_pkas_fasta, base_pkas_calc = _unpack_pka_list(base_pkas_list) acid_pkas_fasta, acid_pkas_calc = _unpack_pka_list(acid_pkas_list) - diacid_pkas_fasta, diacid_pkas_calc = _unpack_pka_list(diacid_pkas_list) # Merge FASTA and calculated values pka_sets_names = FastaPKaMatcher().get_pka_sets_names() for pka_set in pka_sets_names: - base_pkas[pka_set] = _merge_pka_list( - [base_pkas_fasta[pka_set], base_pkas_calc]) - acid_pkas[pka_set] = _merge_pka_list( - [acid_pkas_fasta[pka_set], acid_pkas_calc]) - diacid_pkas[pka_set] = _merge_pka_list( - [diacid_pkas_fasta[pka_set], diacid_pkas_calc]) - return base_pkas, acid_pkas, diacid_pkas + base_pkas[pka_set] = _merge_pka_list([base_pkas_fasta[pka_set], base_pkas_calc]) + acid_pkas[pka_set] = _merge_pka_list([acid_pkas_fasta[pka_set], acid_pkas_calc]) + return base_pkas, acid_pkas diff --git a/pIChemiSt/pichemist/utils.py b/pIChemiSt/pichemist/utils.py index 9f7cf96..099ee18 100644 --- a/pIChemiSt/pichemist/utils.py +++ b/pIChemiSt/pichemist/utils.py @@ -1,5 +1,6 @@ -import os +import argparse import logging +import os def get_logger(name): @@ -14,3 +15,17 @@ def get_logger(name): else: logging.basicConfig(level=logging.INFO) return log + + +def str2bool(v): + """ + Converts a string to a boolean. + """ + if isinstance(v, bool): + return v + if v.lower() in ("yes", "true", "t", "y", "1"): + return True + elif v.lower() in ("no", "false", "f", "n", "0"): + return False + else: + raise argparse.ArgumentTypeError("Boolean value expected.") diff --git a/pIChemiSt/test/examples/payload_1_out.json b/pIChemiSt/test/examples/payload_1_out.json index 349c3ca..b3b2e47 100644 --- a/pIChemiSt/test/examples/payload_1_out.json +++ b/pIChemiSt/test/examples/payload_1_out.json @@ -33,151 +33,6 @@ ], "pI_interval_threshold": 0.2, "pKa_set": "IPC2_peptide", - "base_pkas_fasta": { - "IPC2_peptide": [ - [ - 8.165, - "K" - ], - [ - 7.947, - "F_N-term" - ] - ], - "IPC_peptide": [ - [ - 10.517, - "K" - ], - [ - 9.564, - "F_N-term" - ] - ], - "ProMoST": [ - [ - 9.8, - "K" - ], - [ - 6.96, - "F_N-term" - ] - ], - "Gauci": [ - [ - 10, - "K" - ], - [ - 7.5, - "F_N-term" - ] - ], - "Grimsley": [ - [ - 10.5, - "K" - ], - [ - 7.7, - "F_N-term" - ] - ], - "Thurlkill": [ - [ - 10.4, - "K" - ], - [ - 8, - "F_N-term" - ] - ], - "Lehninger": [ - [ - 10.5, - "K" - ], - [ - 9.69, - "F_N-term" - ] - ], - "Toseland": [ - [ - 10.45, - "K" - ], - [ - 8.71, - "F_N-term" - ] - ] - }, - "acid_pkas_fasta": { - "IPC2_peptide": [ - [ - 2.977, - "A_C-term" - ] - ], - "IPC_peptide": [ - [ - 2.383, - "A_C-term" - ] - ], - "ProMoST": [ - [ - 3.75, - "A_C-term" - ] - ], - "Gauci": [ - [ - 3.55, - "A_C-term" - ] - ], - "Grimsley": [ - [ - 3.3, - "A_C-term" - ] - ], - "Thurlkill": [ - [ - 3.67, - "A_C-term" - ] - ], - "Lehninger": [ - [ - 2.34, - "A_C-term" - ] - ], - "Toseland": [ - [ - 3.19, - "A_C-term" - ] - ] - }, - "base_pkas_calc": [ - [ - 10.4, - "CC(=O)N[C@@H](CCCN)C(C)=O" - ] - ], - "acid_pkas_calc": [ - [ - 3.46, - "CC(=O)N[C@@](C)(CC(=O)O)C(C)=O" - ] - ], - "constant_Qs_calc": [], "frag_base_pkas_fasta": { "1": { "type": "base", @@ -203,7 +58,7 @@ "frag_base_pkas_calc": { "1": { "type": "base", - "frag": "fragment_2.png", + "frag": "CC(=O)N[C@@H](CCCN)C(C)=O", "count": 1, "pka": 10.4 } @@ -211,7 +66,7 @@ "frag_acid_pkas_calc": { "1": { "type": "acid", - "frag": "fragment_1.png", + "frag": "CC(=O)N[C@@](C)(CC(=O)O)C(C)=O", "count": 1, "pka": 3.46 } diff --git a/pIChemiSt/test/examples/payload_1_out.txt b/pIChemiSt/test/examples/payload_1_out.txt index 29bb8cb..0770929 100644 --- a/pIChemiSt/test/examples/payload_1_out.txt +++ b/pIChemiSt/test/examples/payload_1_out.txt @@ -34,11 +34,10 @@ IPC2_peptide 0.63 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 8.6 - 9.4 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : K 8.2 -smiles or AA, base pKa : F_N-term 7.9 -smiles or AA, base pKa : CC(=O)N[C@@H](CCCN)C(C)=O 10.4 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 10.3 K +base 1 8.3 F_N-term +base 1 10.4 CC(=O)N[C@@H](CCCN)C(C)=O +acid 1 3.2 A_C-term +acid 1 3.5 CC(=O)N[C@@](C)(CC(=O)O)C(C)=O diff --git a/pIChemiSt/test/examples/payload_1_out_images.json b/pIChemiSt/test/examples/payload_1_out_images.json new file mode 100644 index 0000000..0ff19ce --- /dev/null +++ b/pIChemiSt/test/examples/payload_1_out_images.json @@ -0,0 +1,78 @@ +{ + "1": { + "mol_name": "Phe-Ornithine-aMeAsp-Lys-dAla", + "pI": { + "IPC2_peptide": 8.046875, + "IPC_peptide": 9.8125, + "ProMoST": 8.375, + "Gauci": 8.6875, + "Grimsley": 8.9375, + "Thurlkill": 9.0625, + "Lehninger": 9.859375, + "Toseland": 9.40625, + "pI mean": 9.0234375, + "std": 1.721588565104915, + "err": 0.6086734743994516 + }, + "QpH7": { + "IPC2_peptide": 0.6314906212267486, + "IPC_peptide": 0.9915539516610472, + "ProMoST": 0.26174063515548607, + "Gauci": 0.5540630760817584, + "Grimsley": 0.6645409545014482, + "Thurlkill": 0.797542965316429, + "Lehninger": 0.9932283675959863, + "Toseland": 0.9515959465104951, + "Q at pH7.4 mean": 0.7307195647561748, + "std": 0.6749606913955383, + "err": 0.23863464096007284 + }, + "pI_interval": [ + 8.624999999999998, + 9.362499999999997 + ], + "pI_interval_threshold": 0.2, + "pKa_set": "IPC2_peptide", + "frag_base_pkas_fasta": { + "1": { + "type": "base", + "frag": "K", + "count": 1, + "pka": 10.309571428571429 + }, + "2": { + "type": "base", + "frag": "F_N-term", + "count": 1, + "pka": 8.303428571428572 + } + }, + "frag_acid_pkas_fasta": { + "1": { + "type": "acid", + "frag": "A_C-term", + "count": 1, + "pka": 3.169 + } + }, + "frag_base_pkas_calc": { + "1": { + "type": "base", + "frag": "CC(=O)N[C@@H](CCCN)C(C)=O", + "count": 1, + "pka": 10.4, + "base64_image": "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" + } + }, + "frag_acid_pkas_calc": { + "1": { + "type": "acid", + "frag": "CC(=O)N[C@@](C)(CC(=O)O)C(C)=O", + "count": 1, + "pka": 3.46, + "base64_image": "iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAIAAAD2HxkiAAAr90lEQVR4nO3deVxUVf8H8M8wrCIICCqbMJgm5JIiKlopiai57zypufxyyT1TeaLH7cmlzNR8UgNzSTINU1TMSihXQg1wC1BRAQVBUUDWgRnm/P6YCREu4DIzZ5j5vl/8YXPPzP0GfDj33nPvOSLGGAgh/BjxLoAQQ0chJIQzCiEhnFEICeGMQkgIZxRCQjijEBLCGYWQEM4ohIRwRiEkhDMKISGcUQgJ4YxCSAhnFEJCOKMQEsIZhZAQziiEhHBGISSEMwohIZxRCAnhjEJICGcUQkI4oxASwhmFkBDOKISEcEYhJIQzCiEhnFEICeGMQkgIZxRCQjijEBLCGYWQaNGVKwgOxhtvoHVrODqifXuMHIlt21BSItD4k0/Qvz+WL6/10zIy0L8/+vfHxYsaq1grGCFaUFLCJk1iRkYMEPhydGRHjlR/S9++DGCDBtX6mcnJqrcfP67R2jWNekKieeXl6N8fu3ZBoYCfH374AYmJuHULZ89i2TLY2iIrC8OHY98+3oXyYcy7AGIAli/H6dMA8MUXWLjwyeseHujZE9Omwd8fycmYNg3dukEi4VUmL9QTEg179AgbNwJAYOBTCazk5IQDB2BmhsJCfPGFdovTCRRComF796K0FACCg2tt4+mJUaMAICwMMpmWCtMZFEKiYWfPAoCbG9q3r6vZ0KEAUFSES5e0UJROoXNComFJSQDQoUM9zTp2fNLex+fJ61Ip7t4Vfkt29stXpwsohETD8vIAwM6unmZNm6r+kZv71OvR0WjZUgNl6RAKIdEwuRwAjOv7TTMxUf2jvPyp183MYGMj/JaKCjx8+HLF6QQKIdGwJk2QnY3CwnqaFRSo/mFr+9TrffsiMlL4LdeuwdPzpevjjy7MEA1zcQGAW7fqaZaSovqHq6tm69E9FEKiYV27AsDff+Px47qaxcQAgEikam9IKIREw4YMAYCyMvzwQ61tZDJ89x0AvPHGkys0BoNCSDSse3d07w4AS5ciM1O4zZo1uHkTAD78UHuF6QwKIdG80FCYmeHhQ7z1luom0kolJfj4Y9XzSsOGYfhwHvVxRldHiea1b48DBzBmDG7fRq9eaNsW3t6wsMC9ezh9GkVFANC3L3bv5l0oHxRCohUDB+LiRfznPzh8GNeu4dq1J5tcXPDvf2PatCdDhQZGxBjjXQMxJEVFiIlBVhaKi2FvDy+vWu8pTU9HURGsrGq9Y6a8XDWw4e4OS0tNFax5FEJCOKPDUcJJdja2boWJCf7zH96lcEY9IeHk9m20agVXV9y5w7sUziiEhBO5HBYWUChQUgIzM97V8ETjhIQTY2M4O0OhqPVxQYNBIST8KOd0SkvjXAZvFELCjzKEqam86+CMQkj4oRACoBASniiEACiEhCcKIQAKIeGJQgiAxgkJT4yhUSNIpSgsROPGvKvhhnpCwo9IBDc3AEhP510KTxRCwhUdkVIICWcUQgoh4YxCSCEknFEIKYSEMwohDVEQznJz0bQprKyeTINveKgnJFzZ2aFJExQWVl+MyZBQCAlv7u6AQR+RUggJbwZ/WkghJLxRCHkXQAwehZB3AcTgUQh5F0AMnsGHkMYJCW/FxbCygpkZiothZIi9giH+PxPdYmn5f127OhkbZ2Zl8S6FDwoh4S8RyCoqSjPUuQ8phIQ/iUQCINVQTwsphIQ/CiEhnFEICeGMQkgIZwYeQhonJPzJZDILCwsApaWlJoa3cj31hIQ/ExMTZ2fnioqKuwa5TBqFkOgEQz4ipRASneDu7g4KISEcUU9ICGcUQkI4oxASwpkhh5DGCYlOUCgUjRo1KisrKyoqsrS05F2OVlFPSHSCkZFRy5YtAaQb3jJpxrwL0HkVFYiORnQ0bt9GQQEaNYKLC/z8MGAADOwPtqZJJJKUlJTU1FQvLy/etWgVhbBOJ09i1iwkJVV/fcsWtGiBNWswaRKHqvSUwZ4WUghr99NPGDcO5eWwsMC4cejVC82aIS8PFy5g925kZ2PyZKSlYfly3oXqCWUIU1JSeBeibXRhphY3b6JTJxQVwcsLx46pVnWulJeH0aPx++8QiRAZiYEDOVWpV8LDw8eOHSsWi/38/Pz9/f39/Tt37iwSiXjXpXEUwlq8+y727oWVFa5erZ5ApaIitG+PtDR4eiIxEQbwu6Jpf/31V9euXau+0rJly379+vXv379Pnz5NmjThVZjGMVLTw4fMxIQBbMGCupp9+y0DGMBOndJWZfosJycHgLW1dXh4+LRp05ydnSt/S8Visbe3d1BQ0JkzZyoqKnhXqmbUEwqJjMSQIQBw9ix69qy12ePHsLODQoEVK7B0qdaq02PW1taFhYW5ubm2trYAEhMTjx49Gh0dffr06fLycmUbe3t75fHqwIEDqwa1AeP9V0AnffopA5hIxIqK6mnZujUD2IgRWilL/7m6ugKIiIio9npRUVFUVNTcuXOVD1tU8vLyCgoKioqKKisr41GvelAIhcyfzwBmaVl/y549GcB69dJ4SQbg+PHjRkZGAL766qs6miUnJ2/YsKFfv37Kh/GVmjRpsmf2bBYayu7c0VrB6kIhFDJjBgOYnV39Lf39GcC6dtV8TXpu8eLFyguhlpaWRfUegDDGGCspKYmKigoKCvL29haJRNfefFN1iu7hwaZNY+HhrLBQ02WrBYVQSFAQA5iZWf0tu3VjAOvbV/M16S2ZTBYUFKRMoKOjY1pa2gt8SFpaWvGOHWzECNakiSqKAGvUiA0YwL76il27pvay1YhCKOTLL1U/xezselq2aMEANmGCVsrSQ3fv3u3evTsAsVj8/vvvKxSKl/1EuZzFxbHPPmM9ezIjoyeBlEhU3WNenhrqVisKoZDTp1U/uSNH6mqWlqZqtmmTtirTK7///nvz5s0rz+vUPw6Rk8PCw9m0aczZ+UkaxWLm7c2WLWNxcezlM68ONEQhRCqFszNycxEYiL17a222ciWWLIFIhOvX0bq1Futr8Bhja9euDQ4OVigUPXv2fOutt86cOXPu3Dm5XK5s0Lx584CAgH79+gUEBDg4OKhhl4mJOHoU0dE4fRr/jHbAwQG9e8PfH4MHw9Gx+lukUsTEIDUVjx7BygqurnjzTdjYqKGYanj/FdBVixYxgBkZsbNnhRvcvas6/RgwQLuVNXg5OTkBAQEAxGLxsmXLKju9ynEIt6dvUVLzOER+PjtwgE2dylq2fNI9Ghmxd9+tWiKbN481avSkQWUvOmoUu35dDWVUQSGsRX6+6odka8t++6361itXWJs2qlN/df9I9Nvp06ednJwAODg4HD9+vLZmt27dCgkJGT16dOPGjSvTaGlp6e/vv3Hjxhe7eCO4GxYSwkaPZo0bP7k76sYNJpGoUteyJRs/nn34IZs8mb32mupFKyuBX4mXQCGsXUICa95c9X3v1o19/DFbv54tW8b69WPGxgxgFhbs8GHeVTYYCoVi48aNygm233rrrczMzGd5V9VxiKrdo4eHx7Rp08LDwwvVMg5RUsIePmSMsaKiJ39ed+2qftIYHc2cnFRjyOr740shrFNaGhs7lolE1Q9LlAP0CQm862swHj9+PGrUKAAikWju3Lnl5eUv8CGpqanffPPNsGHDrKysKtPYqFGj4nffZZs2qScVwcGqm6V++UW4wbVrzNKSASwgQA27Y4zRhZnqEhLAGJ7+o4t793D8OG7fxsOHsLGBqyv69EGbNpxKbHguXrw4evToW7duWVtb79ixY+TIkS/5gRUVFZcuXYqMjDx69GjjnJyTd+6oNkgk6NsX/v4ICMALPHVRVgYXFzx8iBEjcOBArc2WL8eKFRCJkJSEtm1f8P+hKnWlWU/0788Atns37zr0x3fffae8v6xz5863bt1S++eX3L/Pdu9m48YxB4cnxymmpszPj332Gbt48TnGIc6cUb29xs2rT6kcmtqw4WWrZ4zR4ehTUlKYkRGzsGCPHvEuRR+UlJRMmTJF+bd+woQJJSUlGt/l33+zzz5j/v7M1PRJIB0c2OjRLCSE3btXz9vXr1e9JSurnpbKgceqF1RfAoWwig8/ZAB7/33edeiDa9eutWvXDkDjxo1/+OEHbe++qIhFRbG5c5mb21PjEN7eLCiIRUUxwZPSxYsZwExM6v98X18GsLffVkuxFMJ/lJQwOzsGsLg4ga2PHrGOHdnGjVovq0H6/vvvlUMLbdu2vXr1KudqlOMQgwYxc/MngWzcmA0axEJCnnrq4oMPGMBsbOr/zIAABjBvb7UUSCH8x7ZtDGA9eghvXbeOxuWfhVQqnTt3rvIQdNy4cc/4PISWFBezY8fY3LmqQYjKr8rhyo8+YgAzN6//o5RPbKjpETYK4T+8vRnAvv9eYJNCofqxHT2q9bIakvT09G7dugEwMzPbqONHDbdvq4bp7e1Zfr7qxVWrVLEsKKjn7crfh+HD1VILhZAxxlhMjOoMvrRUYOuxYwxgbm5MLtd6ZQ1GZGSkck4KNze38+fP8y7nmVX9mR49qgrh6dN1vaWgQPV8xooVaimBpsEHAGzeDABTp8LcvNatM2dCLNZqVQ2EXC5fvnz50KFD8/LyBg8efPHixWqTpum0qj9TX1+YmADAoUN1veXQISgUANCrl3pqUEuUG7YHD5iZGROLWWqqwNa0NCYWMzMzdv++tgtrCO7fv9+nTx8AxsbGVe/GbqgCAxnArK1ZRoZwg7Iy5uXFANamjbqehKIQMrZyJQPYsGHCW5WPU0ycqNWSGogTJ044OjoCcHZ2Plvb4yYNS1ISs7BgAPPxUd1NWlVZmSqlADt0SF37NPgQyuWqoaSoKIGtUqnqPowLF7RemU5TKBSfffaZWCwG4Ofnl1Xv6HYDsnOn6pSvaVO2bBk7eZIlJ7M//2QbNqgm16t3QtrnZPAhjIhgAGvdWvjQYudOBrDOnbVelk57+PDhgAEDAIhEoqCgILn+Xa+KiHjqYfyqX1ZWbP169e7N4BeEUV50mT1beB77LVsA4J+BLwIgLi5uzJgxqamp9vb2YWFh/fv3512RBgwbhoAA7N+P48dx6xYePoS1Ndzc8PbbGDsWzZqpd2+G/RRFSgpefRUWFsjIgK1t9a0JCfD2hq0tMjLQqBGP+nROaGjonDlzysvLfXx8wsPDq03FS16MYQ9RfP01GMP48QIJBLBpEwBMnUoJBFBYWBgYGDh9+vTy8vJp06adPXuWEqguBtwTlpTAxQV5eYiPR+fO1bc+egQXF5SXIyUFHh486tMhycnJo0aNSkpKsrKy2r59++jRo3lXpFcMuCcMC0NeHt54QyCBALZvh1SKAQMogbt37+7SpUtSUtLrr7+ekJBACVQ/9V7naUg6dWIA27tXYFNFhWqqn2PHtF6WDiktLZ06dary92TChAnFxcW8K9JPhhpC5fS+LVowwVn0IiMZwFq1Yg39/o+XcOPGjQ4dOgAwNzfftm0b73L0maEOUSjHHqZOhampwFbluMUHH8DIQA/XDx06NHny5Pz8/DZt2uzfv1+ZRqIpvP8K8JCVxUxNmbExu3tXYOvNm6pJLmretWQAqi7PMnz48PzKx3yIxhhkT7htG8rLMXIkXFwEtm7dCoUC//oXmjbVemWcZWRkjBkzJjY21tjYeOXKlUFBQbwrMgy8/wponUzGXFwYwH7/XWBrSQlr2pQB7K+/tF4ZZ9HR0crlWVxdXWNjY3mXY0AM75zn8GFkZMDTE35+Alv37sWjR+jeHV26aL0ybioqKpYvXx4QEHD//v2BAwdeunRJuVwZ0Q6DC+HqiIiUN96Q13az6NatADBzppar4ignJ+edd95ZsWKFSCRatmzZkSNH7OzseBdlYHh3xVqVlJQkEokaN24sfL0hNpYBzN5eeJILfbRp0yblwmN1L89CNMqwLsxs2bKFMTZhwoQmgnOkK0cm3n9feJIL/aJQKIYNGxYZGQmgZ8+e+/fvd6y5QB/RCgO6d7SoqMjFxeXx48dXrlxp3759ta0FDx82bt/eKCcHN2/CAG5Nnjhx4u7duwH06NHjxIkTpoLjpUQrDOicMCws7PHjx7169aqZQABbt293ePz4yIwZhpBAAEeOHAEwduzYmJgYSiBfBhTCrVu3ApgpdNFFoVCEhITklpaaDxmi9br4UC7Solyvk/BlKCE8derU1atXHR0dhw8fXnPr0aNHU1NTW7Vq5e/vr/3auFDG7/r167wLIQYTws2bNwOYNm2acqVYwa2zZs0yMpibRQcOHAigRYsWvAshhhHCrKysQ4cOGRsbVz6YU9XNmzejo6MtLCwmTpyo/dp48fHxAXDv3j3ehRDDCGFoaKhMJhs+fLizs3PNrZs3b1YoFOPGjTOoQWqJRAIgNTWVdyHEAIYo5HK5u7t7ZmbmiRMnevfuXW1raWmpi4tLbm5uXFycd7VVsvVacXGxlZWVmZlZcXGx4RyE6yb9/+5HRERkZmZ6enr2Elo5YM+ePbm5uT169DCoBAKwtLR0cHCQSqXZ2dm8azF0+h9C5UWX2bNni4RuFv3mm29Qy7iF3qMjUh2h5yFMSko6ffq0lZXV+PHja279888/4+PjHRwcRo4cqf3auKMQ1uHOnTta25eeh3Dz5s2Msffee8/a2lpwK4CpU6eaG8DNojVRCGtz+fLlVq1aCV5L1wR9DmFhYeH3338PYMaMGTW35uTkHDhwQCwWa+17rWsohLVZtGiRXC4XvstfA/Q5hLt37y4oKPDz82vXrl3NraGhoWVlZYMHDzbYmaQphIIiIiKioqLs7OyCg4O1tEu+T1JplDJ7+/fvr7lJOW4BIEpwRTTDcPPmTQBubm68C9EhZWVlrVu3xj8nMtqhtyH8448/ADg6OpaXl9fcGhERAaB169YKNS222hCVl5eLxWKxWCz4LTJMa9euBeDp6SmTybS2U709HFVedJkxY0bdN4sKjlsYCBMTE2dn54qKirt37/KuRSfk5OSsWrUKwIYNG4yNtfi8u9birk2ZmZkmJiYmJiYZQiuP37hxQyQSNWrUKDc3V/u16RTlDQzR0dG8C9EJygt4AwcO1PJ+9bMnDAkJkclkI0aMELxZ9Ouvv2aMjR8/3lZwRTRDQtdmKiUlJX377bfGxsaff/65lnethyGUyWTbt28HMGvWrJpbS0pKwsLCAEyfPl3blekeCmGlDz/8UC6Xz5o167XXXtPyrvUwhAcPHszMzPTy8rKxsfn222/nzJkTERHB/rlP/fvvv8/Ly3vjjTc6C66IZmAohEqRkZHHjx+3tbVdsmSJ9veuD7OtSaXSe/fu3f7Hrl27ANy+fbtyGZOvv/46ICDgt99+AxASEoJaOkkDRCEEIJPJFi1aBGDFihVNeax90JAeZZJKpWlpaan/qPx3bm6uYHvltRkLC4tHjx4ZGRlFR0ebmJi8+eabDg4Od+/eNTMz03L9OigzM9PFxaV58+aG/CzFhg0bFixY0LZt2ytXrgheS9c0He0J8/LybteQlpamUChqNjYzM3N2dvZ4WqtWrWxsbJQNPvnkk9WrVwcGBvr6+gKYPn06JVDJycnJ3Nz8/v37xcXFlpaWvMvhIDc3Vzks8eWXX3JJILj3hDXDdu/evdTU1NLS0pqNTUxMXF1dHR0dnZycqubN3d297sdSFQrFgAEDjh8/bmRkZGRklJqa6iK4HpNBevXVV2/cuJGYmOjl5cW7Fg5mz569efPmPn36REdH86pBSz1haWlpVlZWtbzduHGjsLBQsL2tra1HDS1btnyxIVQjI6OwsLD27ds/ePDglVdeoQRWJZFIbty4kZqaaoAhTE5ODg0NFYvFGzdu5FiGmkNYXl6ekZFRs3PLysoSbK8MW7XOrW3btmo/NGrWrNmhQ4d69eqVkpJy6NChYcOGqffzGy5DvjazYMECmUw2a9YswVv8teYFQyiXyx88eFCzc3uu07ZXXnlFa0+LAPD19V21atXixYunTJnSoUMHDw8Pre1alxlsCI8dO/brr7/a2NgsX76cbyXPGsLLly9HRkZWXpnMyMiQy+U1m5mamrq5uUkkEolE4u7uLvmHcukf7hYuXBgbGxsRETFixIjY2FjlLNQGzjBDKJfLFy9eDGDp0qX29vZ8i3nWEMbHx1cbxxQ8bXNzcxOLxRqoUz1EItGOHTsuX758+fLlhQsXKm/jNnCGGcKtW7cmJia2atVKF6YXetaro0lJSWFhYZX9m5ubW8NdReTy5cu+vr6lpaW7d++eMGEC73I4e/Tokb29fZMmTfLz83nXoiV5eXlt2rR5+PDhkSNHBg8ezLscPX2Kol7KxWEsLS0TExN518KfcgIew3mmZN68eQDefvtt3oWoGGgIGWPvvfcegFdffbWgoIB3LZwp7++Lj4/nXYg2XLt2zcTERCwWX758mXctKnp4A/cz2rJli5eX1/Xr1+lxCoM6Lfzoo49kMtnUqVMrby3mznBDaGlpGRERYWVltXfv3tDQUN7l8GQ4Ifzjjz9+/vlnKyurZcuW8a7lCcMNIYA2bdoo4zd37tz4+Hje5XBjICGsqKiYP38+gKVLl+rUmnAGHUIAgYGBM2bMKCsrGzlyZG1PY+g9AwlhSEjI1atXPTw85syZw7uWpxh6CAFs3LjR29s7PT190qRJrOE82KVGhhDCgoKC//73vwDWrVunc8/Q8L4ypBPS0tKUT3OuW7eOdy0cFBUVATA3N9fjCSAXLFgAoHfv3rwLEdCQHurVqKNHjw4ZMkQsFv/xxx9vvvkm73K0rVmzZjk5Offu3XN0dORdi/rdunXrtddek8lkFy5c0ME18OhwVGXQoEELFy6Uy+Vz567JyeFdjdbp9xHpRx99VFZWNmXKFB1MICiEVa1evXrcuE2ZmUfHjYPQoyD6TLkogF6G8MSJE4cPH7ayslKeE+ogCuETxsbG69bNMTY2ioqCrv68NEVfe0KFQrFw4UIAwcHBOnukTSF8SosW2LMHYjE+/RS//sq7Gi3S1xB+++23CQkJEolEOUKomyiE1fn5YdkyKBQYNw7p6byr0Ra9DGFhYaHyzpi1a9fq8jqwFEIBn3yCAQOQm4uxY1FezrsardDLEK5cuTI7O7tHjx46vhw6DVEIy82FtzfS0rBgAb78knc1mldeXm5hYWFkZFRSUsJr5j/1Sk1NVa5wdu7cOR8fH97l1IV6QmF2dvjxR5iaYsMGHDjAuxrNMzU1dXJyksvlGRkZvGtRj0WLFpWVlU2cOFHHEwgKYR26dsXatWAMkyfj+nXe1WiePh2RxsTEHDx4sHHjxitXruRdS/0ohHWZNw+jRqGwEGPGoKSEdzUapjchVCgU8+fPZ4wFBQU5OTnxLqd+FMJ67NyJtm1x5QrmzeNdiobpTQh37twZFxfn5OSkvF9U91EI69G4McLD0agRvv0Wu3bxrkaT9COERUVFwcHBAJo1a6bLwxJVUQjr1749/vc/APjgA1y6xLkYzdGPEK5evfrBgwcmJiaXLl1avXo173KeDeenOBqOyZMZwFq3Zo8f8y5FM+7cuQOgRYsWvAt5cbGxsSKRSCQSbd68WSwWGxkZ/fbbb7yLqh+F8FmVlrJOnRjAxozhXYpmVFRUmJmZiUSi4uJi3rU8t+vXr+/atUs5l7aHhwdjbOnSpQCaNWuWkZHBu7p60GD9c7h5E1264PFj/O9/mD2bdzUa0Lp165s3byYlJXl6evKuRVhZWVlmZmbV5U+uX79+8+bNkn8uXotEovPnz/v4+CgUinfeeee3337z9fU9deqULt+BQCF8PocPY/hwGBvj5En06MG7GnULCAiIior6+eef33nnHb6VlJeXp6enV1uSOTU1NaeWZz1FIpG5ubm9vX1oaGj//v2VL+bk5HTq1CkzM3Px4sWff/65Fst/Pjq6Uq/OGjoUc+Zg0yYEBiIhAbyXElEzLtdmBFdlTk9Pr6ioqNnY1NTUxcVFufCJRCLZu3fvlStXunXrdvbs2ZprVzo4OPz000+9evX64osvunfvPnz4cK38Dz03CuFzW7cO8fGIicHEiYiMRJ1rBDcwGg1h1bApl6y8fft2cnJySS23QQiuOFRtVeYpU6Z07tz5/PnzS5cuFbwW2r1791WrVi1atGjKlCkdO3bUzfXw6HD0Rdy9i86d8fAhVq/Gxx/zrkZ9fvzxx8DAwBEjRhx4iftlpVLpvXv3qvVsKSkpBQUFgu1fclXm2NjYXr16yeXygwcPCq79yhgbNWrUwYMHO3bsqJvr4VEIX9Avv2DQIMycqRpC1A8XLlzo1q1bp06dEhIS6m1cbVXmys4tNTVV8JfK3Ny86nrMSm3atLGysnrJsteuXRsUFGRraxsfH6/szKvJz8/v0qXLrVu3ZsyYoVwLSKdQCF/c1ato3553EWqVk5PTrFmzmsukPddpm+CqzB4eHra2thoqmzE2cuTIiIgIHx+fM2fOCE4reuXKle7du5eWln733XfKtYB0B4XwKenpKCyEtTVathRuUF6OGzcAQCKBpSUAlJQgORkAbG0heMbBGJT9ikQCOzuNlK0u9+/f9/DwKCkpWbp0aVZWlvKC5J07d2QyWc3GJiYmrq6uNVdl5jLDfH5+vre39+3bt2fNmvX1118LtgkNDZ0+fbqlpeX58+dfe+01LVdYBwrhUwICEBWFQYMQGSnc4No1KIfQjh9H374AEBcH5QNr1tZISoKzc/W3yOVQjlGFhWH8eE1V/lzqPm2zsrIqLCys2v4lT9u041nWfp00adJ3333Xpk2buLi4lz8MVhcd+iY2dAUFWLgQe/fyrqMKqVRaOchWdbSttlU37OzsJBKJr6+vhYVFZf/m7u7eIO6E7tix45dffjlz5syZM2d6e3t7eXnVbLN169ZLly5dvnx52rRpe3XmR0UhVKd9+zBpEvr147BrwdO2tLQ0hdAMqoKnba1atbKxsdF64er0wQcfnDt3bvfu3WPGjDl//ryl8oShCgsLi/DwcB8fn3379vXq1WvGjBlc6qyGQqg2Q4bgyBHMmoWrV6G5y+DZ2UhNVX2lpSE1FQrFsLNnj9V22iZ5mrJza968eR27SEpKEuxGGoQtW7bExcUlJiZOnTr1hx9+qNlAuR5eYGDg/PnzfXx8dGFObgqh2ixZgpMncesWVq/Gp5++7KdJpbh3D7dvP/V14waePlkDAF9fM5lMpsbTtsuXLzfcEFpaWh48eNDHx2fv3r1+fn5Tp06t2Wbs2LGnT5/esmXLyJEj4+PjlWsB8cTpxnEd1bcvA9igQbU2SE5mAAPY8eOqV/76S/VKWhpbu5YBzNSUJSU9eYtMpmoQFibwgaWlLCmJ/fwz+/pr9tFHbMQI1rkzs7VVvaXml70969KFjR7NFi9mW7eyX39lN248kkqlav02NHjK8z1zc/P4+HjBBuXl5b6+vgAGDRrEfS0q6gnVad48bN+O69cxYwZOnoRIJNDm558RG6s6kkxNRVaW8EdZWkIiEfgSuqSn2+MePAQGBp48eTIkJGTMmDFxcXE1z3VNTEz27dvXuXPno0ePrlu3btGiRTzKVKEQCkhMxNy5wpvy8up6o6kp1q/HwIE4fRq7d2PiRIE2+/bh+++f/KeJCVxd4eEBR0c4OcHDQ/UlkQhnWAt++umn+Pj4NWvW8Nm9mnz11VdxcXHx8fHvvffe4cOHRTW+my1btty5c+fQoUODg4Pf6dnzNY4PxfDtiHWN8nD0Wb4ED0eVhg1jAGvalOXkMFbjcPTAAbZsGdu1i506xe7cYRUVPP4/6/To0aPs7GzeVahB5dqvX375ZW1tlgYHn/X3Z46O7N49bdZWFQ3WP0U5WO/lhcmThRvk5GDtWkBosD4tDW5uAHDnDry8UFyM6dPxzTe6OFhvOOpf+7WiAv37Izoafn6IioJYrPUaqSd82ktemKm0Zg0DmJERi4ur58KMDsrNzQ0LC1Peh60HlEujtWjRIisrS7hFdjZzdGQAW7JEu6Wp6NHDcLpkwQJ4ekKhwEcf8S7l+eXl5f3yyy95dZ/+Nhxr1qx58803s7Ozx40bJ3jHOZo3xw8/QCzGqlX45RetF0hTHmqGqSm++QYiEU6dwqFDvKt5Th4eHnv27OnUqRPvQtTD2Ng4PDzc0dHxjz/++LS2AdzevbFiBRQKjB+PtDSt1kch1Jy33sK//gUAwcG8SzF4LVq0CAsLE4vF9w4erIiOFm4UHIyhQ7ksiEch1KD162Fjg5QU3nU8J7lc/vrrr9vY2JTr0eKMffr0iVm/PvT6dfG770Jw5SmRCDt3QiLBhQsICtJmbRRCDWreHMuX8y7i+RkbG4eFhaWnp5uamvKuRZ26zZ6Nt99GTg5Gjxbu62xtsW8fTE2xcSN++klrhVEINWv2bDTEc6v27ds3adKEdxXqZmSEPXvg7o5z52o9SejaFV98AQCTJ+PaNe3URXfMPKVrVxgbo0uXWhs0bowBAwA8mezQ2hr+/gAg+MydWIwtW7BkCQA4Oqq5Ws05ceLEtWvXrK2tx40bx7sWtbKzw759eOstrF8PX18ILqM9dy4uXMCePRgzBufOoVEjTRdFg/VEwPz586VSaY8ePXRtOhb12LgRH34IKyv89RdefVWgQVERunZFcjKmTMH27Zouh0JIDNLo0fjpJ3TogHPnhJ/+/PtvdOuGkhLs2FHr/VNqQueEpFYymUwqlfKuQjN27Khn8dd27bBtGwDMnImLFzVaC4WQCFi5cqVEIrGystqzZw/vWjTDykq1+Ou2bfjuO+E2776LKVMglWLsWDx+rLla6HCUCLh9+zYAV1dXXV7MSA22b8f778PCArGx6NhRoIFUih49cPEiRo9GeLiGqqAQEsM2eTJ27UKbNvjrL1hbCzSoXBBv0ybMmaOJEiiERMDdu3djY2OV8yOuWbNGc5Nn8yeVwtcXly5hzBj8+KNwmyNHMGwYjI1x4gR69lR7CXROSARcvHhx//79jx496tixo5jLI3ZaY26O8HBYWyM8HFu2CLcZMgRz50Imw7/+hYcP1V4C9YSEAOHhGDsWJiY4dQq+vgINZDL4+SEmBgMG4OhR9S6IRz0hqUtBQYGW1wzlY8wYzJ4NmQyBgXj0SKCBiQn27YO9PX75BZ99pt6dUwiJgKtXr3bp0qVp06bOzs7zahtJ0zPr16NHD9y5g4kTIXh46OKCsDAYGWHvXvU+60SHo0RAUVFRcnKyRCKx17MFwetWufjrZ5/V+jTTgQPo1w+NG6txtxRCQqo4dgyDB0Mkwm+/oU8f7eyTQkgEyOXyU6dOVa7i1Ldv38kavn9ShwQHY80aNG+OhAQ4OWlhhxRCIkAul/fr169yabRu3bq1bt2ad1HaolCgXz9ER6N3b0RHa2ESRAohITVkZ6NTJ2Rn45NPsHJlrc1yc/HgAWQyNG2KFi1eeNyCro6SuigUioyMjDNnzjzW5B3MOqdFC+zbBycn9O4tsDUvD0uWoG1bNG0KT0906ABnZzRvjgkT8PffL7A36gmJsEmTJv3555937txp2rSpRCIJDQ1tuOulvaCyMpiZVX8xJgZDh6rGEpULiZiZISNDtWadkRFWrcK///1c+6EQEmEXLlxo0qSJu7u7Wc1fRIN15Qq6d0dpKZo1w6pVGDtWtUpWRQVOnEBQEBISAGDduuea9ZlCSMizUSjQqROuXEGzZoiJwSuvVG9QUoIBA3D6NMzMcPmy8MQZQiiERFhKSkpiYmLlKEV+fv6ZM2d4F8XVL7/gnXeAOlf2SU/Hq6+irAwffFDr7eA1UAiJsBUrViQkJFQudu/h4dGuXTveRXGlfPLQ3h6ZmahjRtaxYxEeDnt7PHjwjEtMUggJeTZt2+L6dQwZgsOH62oWEoIZMwDgxg082+AqzTtK6lFaWqo8IrWxsempgUdaG4z0dABo06aeZm3bqv6RlvaMIaRxQiIsIiKiR48ejo6OdnZ2I0eO3Lx5c2JiIu+i+JFKoZx4TnAKjKoqZy5/5rXlqCckwl5//fUvvvhCIpE4OjrWXPDd4BgbQyQCY1Ao6mlZuQTiM8+RRSEkwpTXY3hXoTOMjWFpiaKi+vu3ygY2Ns/62S9eFtFrxcXFCQkJqU/76quvhg8fzrs0Ttq0QUICkpLqaVZ559ozjxNSCImwa9euffzxx8r+sFevXpMmTZJIJC4uLrzr4qd7dyQkIDYWxcWwtKy12fHjAODm9uyPQdEQBSHPJjYWPXoAwFdfYe5c4TZJSejQARUVWLIE//3vM34whZDU7/79+8rD0fT09KCgIMO9TuPnh5MnYW2NEyfQuXP1rY8fw98fcXGwtUVSElq0eMZPpSEKIqy4uHjw4MHt2rWztLRs3779vHnzDh06lJ+fr09raD+3HTtgZ4eCAvTujc8/R3a26vXSUhw4gK5dERcHkQhbtjx7AkE9IakNY+zo0aPKh+sbq3Veo4YtMRGDB6NyGkgHB5iYICcHMhkA1Qoz7777XB9JISTPRyqVmgsuSmw4pFKEhODHH3HhwpNRwdatMWgQFi58gWlpKISkVtevX09JSUlLS6s6StGzZ8+ff/6Zd2m6QSZT9YEODi+zqjaFkNRq8ODBFRUVkirc3d3t7Ox416VvKISEcEaD9aR+5eXl6enplcel/fr16y04AxJ5IRRCUquNGzcePHgwLS3twYMHLi4uyiulEomEjkjViw5HSa3OnTsnlUqVd6vp+SqFXFEIyfOpqKjIyMhwdnY2NqbDKPWg7yOpVX5+fnJycrUhiszMzGbNmsXExLi6uvIuUE9QT0hqtW3btu3bt1eeCiqHKNzc3EzrmOaIPD8KISGc0eEoeSa5ublVj0vFYvGmTZt4F6UnKISkVlevXl22bJkydfhnwguJROLp6enp6cm7Ov1Bh6OkVtnZ2TExMXS3mqZRCAnhjB7qJYQzCiEhnFEICeGMQkgIZxRCQjijEBLCGYWQEM4ohIRwRiEkhDMKISGcUQgJ4YxCSAhnFEJCOKMQEsIZhZAQziiEhHBGISSEMwohIZxRCAnhjEJICGcUQkI4oxASwhmFkBDOKISEcEYhJIQzCiEhnFEICeGMQkgIZxRCQjijEBLC2f8DneSWgEe1ebYAAAAASUVORK5CYII=" + } + }, + "frag_Qs_calc": {} + } +} diff --git a/pIChemiSt/test/examples/payload_2_out.txt b/pIChemiSt/test/examples/payload_2_out_fasta.txt similarity index 81% rename from pIChemiSt/test/examples/payload_2_out.txt rename to pIChemiSt/test/examples/payload_2_out_fasta.txt index 75f8be2..289d97f 100644 --- a/pIChemiSt/test/examples/payload_2_out.txt +++ b/pIChemiSt/test/examples/payload_2_out_fasta.txt @@ -34,9 +34,8 @@ IPC2_peptide -0.24 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 3.8 - 6.7 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : C_N-term 7.9 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.3 C_N-term +acid 2 8.1 C +acid 1 3.2 N_C-term diff --git a/pIChemiSt/test/examples/payload_2_out_fasta_all_capped.txt b/pIChemiSt/test/examples/payload_2_out_fasta_all_capped.txt new file mode 100644 index 0000000..c658eb6 --- /dev/null +++ b/pIChemiSt/test/examples/payload_2_out_fasta_all_capped.txt @@ -0,0 +1,39 @@ + +====================================================================================================================================================== +pI +--------------------------------- + pI mean 6.9 + err 0.86 + std 2.44 +IPC2_peptide 8.12 + IPC_peptide 7.0 + ProMoST 6.88 + Gauci 7.75 + Grimsley 5.5 + Thurlkill 7.25 + Lehninger 7.06 + Toseland 5.62 + + +====================================================================================================================================================== +Q at pH7.4 +--------------------------------- +Q at pH7.4 mean -0.51 + err 0.62 + std 1.75 +IPC2_peptide -0.02 + IPC_peptide -0.23 + ProMoST -0.32 + Gauci -0.05 + Grimsley -1.6 + Thurlkill -0.13 + Lehninger -0.21 + Toseland -1.54 + + +pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher +pI interval: -1.0 - 7.2 + +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +acid 2 8.1 C diff --git a/pIChemiSt/test/examples/payload_2_out_fasta_capped_cterm.txt b/pIChemiSt/test/examples/payload_2_out_fasta_capped_cterm.txt new file mode 100644 index 0000000..e1d5f06 --- /dev/null +++ b/pIChemiSt/test/examples/payload_2_out_fasta_capped_cterm.txt @@ -0,0 +1,40 @@ + +====================================================================================================================================================== +pI +--------------------------------- + pI mean 7.76 + err 0.62 + std 1.77 +IPC2_peptide 8.52 + IPC_peptide 8.25 + ProMoST 7.83 + Gauci 7.56 + Grimsley 6.72 + Thurlkill 8.05 + Lehninger 8.3 + Toseland 6.86 + + +====================================================================================================================================================== +Q at pH7.4 +--------------------------------- +Q at pH7.4 mean 0.26 + err 0.63 + std 1.79 +IPC2_peptide 0.76 + IPC_peptide 0.77 + ProMoST 0.52 + Gauci 0.06 + Grimsley -0.93 + Thurlkill 0.67 + Lehninger 0.78 + Toseland -0.59 + + +pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher +pI interval: 7.6 - 7.9 + +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.3 C_N-term +acid 2 8.1 C diff --git a/pIChemiSt/test/examples/payload_2_out_fasta_capped_nterm.txt b/pIChemiSt/test/examples/payload_2_out_fasta_capped_nterm.txt new file mode 100644 index 0000000..0aa3692 --- /dev/null +++ b/pIChemiSt/test/examples/payload_2_out_fasta_capped_nterm.txt @@ -0,0 +1,40 @@ + +====================================================================================================================================================== +pI +--------------------------------- + pI mean 2.38 + err 0.5 + std 1.43 +IPC2_peptide 2.25 + IPC_peptide 1.62 + ProMoST 2.88 + Gauci 2.81 + Grimsley 2.56 + Thurlkill 2.94 + Lehninger 1.56 + Toseland 2.44 + + +====================================================================================================================================================== +Q at pH7.4 +--------------------------------- +Q at pH7.4 mean -1.51 + err 0.62 + std 1.75 +IPC2_peptide -1.02 + IPC_peptide -1.22 + ProMoST -1.32 + Gauci -1.05 + Grimsley -2.6 + Thurlkill -1.13 + Lehninger -1.21 + Toseland -2.54 + + +pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher +pI interval: -1.0 - 2.5 + +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +acid 2 8.1 C +acid 1 3.2 N_C-term diff --git a/pIChemiSt/test/examples/payload_2_out_smiles.txt b/pIChemiSt/test/examples/payload_2_out_smiles.txt new file mode 100644 index 0000000..41b7e50 --- /dev/null +++ b/pIChemiSt/test/examples/payload_2_out_smiles.txt @@ -0,0 +1,41 @@ + +====================================================================================================================================================== +pI +--------------------------------- + pI mean 5.09 + err 0.24 + std 0.68 +IPC2_peptide 5.0 + IPC_peptide 5.0 + ProMoST 5.5 + Gauci 5.0 + Grimsley 4.88 + Thurlkill 5.5 + Lehninger 5.0 + Toseland 4.88 + + +====================================================================================================================================================== +Q at pH7.4 +--------------------------------- +Q at pH7.4 mean -0.74 + err 0.63 + std 1.79 +IPC2_peptide -0.24 + IPC_peptide -0.23 + ProMoST -0.48 + Gauci -0.94 + Grimsley -1.93 + Thurlkill -0.33 + Lehninger -0.22 + Toseland -1.59 + + +pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher +pI interval: 3.8 - 6.7 + +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.3 C_N-term +acid 1 3.2 N_C-term +acid 2 8.1 C diff --git a/pIChemiSt/test/examples/payload_3_out.txt b/pIChemiSt/test/examples/payload_3_out.txt index 84b57df..bcd8d28 100644 --- a/pIChemiSt/test/examples/payload_3_out.txt +++ b/pIChemiSt/test/examples/payload_3_out.txt @@ -34,12 +34,10 @@ IPC2_peptide 0.76 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 8.6 - 9.4 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : Y_N-term 7.9 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.3 Y_N-term +acid 1 9.9 Y ====================================================================================================================================================== pI @@ -76,12 +74,11 @@ IPC2_peptide -0.24 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 3.8 - 7.5 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : Y_N-term 7.9 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.3 Y_N-term +acid 1 9.9 Y +acid 1 3.2 M_C-term ====================================================================================================================================================== pI @@ -118,12 +115,10 @@ IPC2_peptide 0.76 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 8.6 - 9.4 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : Y_N-term 7.9 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.3 Y_N-term +acid 1 9.9 Y ====================================================================================================================================================== pI @@ -160,12 +155,11 @@ IPC2_peptide -0.24 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 3.8 - 7.5 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : Y_N-term 7.9 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.3 Y_N-term +acid 1 9.9 Y +acid 1 3.2 M_C-term ====================================================================================================================================================== pI @@ -202,13 +196,12 @@ IPC2_peptide -1.14 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 4.3 - 5.7 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : CC(=O)C[C@H](N)C(=O)O 7.9 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 6.3 H +base 1 7.9 CC(=O)C[C@H](N)C(=O)O +acid 1 3.1 H_C-term +acid 1 3.5 CC(=O)C[C@H](N)C(=O)O ====================================================================================================================================================== pI @@ -245,13 +238,12 @@ IPC2_peptide -1.12 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 4.5 - 5.7 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : D_N-term 7.9 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 6.3 H +base 1 8.4 D_N-term +acid 1 3.1 H_C-term +acid 1 3.7 D ====================================================================================================================================================== pI @@ -288,13 +280,11 @@ IPC2_peptide -0.48 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 4.1 - 6.9 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : CC(=O)[C@@H](N)CSSC[C@H](N)C(C)=O 7.9 -smiles or AA, base pKa : CC(=O)[C@@H](N)CSSC[C@H](N)C(C)=O 7.9 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 7.9 CC(=O)[C@@H](N)CSSC[C@H](N)C(C)=O +base 1 7.9 CC(=O)[C@@H](N)CSSC[C@H](N)C(C)=O +acid 2 3.1 G_C-term ====================================================================================================================================================== pI @@ -331,13 +321,11 @@ IPC2_peptide -0.44 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 4.5 - 7.3 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : G_N-term 7.9 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 2 8.4 G_N-term +acid 1 3.5 CC(=O)N[C@@H](CSSC[C@H](NC(C)=O)C(=O)O)C(=O)O +acid 1 3.5 CC(=O)N[C@@H](CSSC[C@H](NC(C)=O)C(=O)O)C(=O)O ====================================================================================================================================================== pI @@ -374,13 +362,11 @@ IPC2_peptide -0.48 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 4.1 - 6.9 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : CC(=O)[C@@H](N)CSSC[C@H](N)C(C)=O 7.9 -smiles or AA, base pKa : CC(=O)[C@@H](N)CSSC[C@H](N)C(C)=O 7.9 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 7.9 CC(=O)[C@@H](N)CSSC[C@H](N)C(C)=O +base 1 7.9 CC(=O)[C@@H](N)CSSC[C@H](N)C(C)=O +acid 2 3.1 G_C-term ====================================================================================================================================================== pI @@ -417,13 +403,12 @@ IPC2_peptide -0.48 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 4.5 - 6.9 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : N[C@@H](CSSC[C@H](N)C(=O)O)C(=O)O 7.9 -smiles or AA, base pKa : N[C@@H](CSSC[C@H](N)C(=O)O)C(=O)O 7.9 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 7.9 N[C@@H](CSSC[C@H](N)C(=O)O)C(=O)O +base 1 7.9 N[C@@H](CSSC[C@H](N)C(=O)O)C(=O)O +acid 1 3.5 N[C@@H](CSSC[C@H](N)C(=O)O)C(=O)O +acid 1 3.5 N[C@@H](CSSC[C@H](N)C(=O)O)C(=O)O ====================================================================================================================================================== pI @@ -460,13 +445,11 @@ IPC2_peptide 1.08 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 10.4 - 11.5 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : R 11.5 -smiles or AA, base pKa : H 6.4 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 12.2 R +base 1 6.2 H +acid 1 10.0 Y ====================================================================================================================================================== pI @@ -503,13 +486,12 @@ IPC2_peptide 0.08 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 6.9 - 9.2 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : R 11.5 -smiles or AA, base pKa : H 6.4 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 12.2 R +base 1 6.2 H +acid 1 3.2 G_C-term +acid 1 10.0 Y ====================================================================================================================================================== pI @@ -546,15 +528,15 @@ IPC2_peptide -1.22 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 4.3 - 4.5 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : R 11.5 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 4.2 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 1 12.1 R +base 1 4.2 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 2 3.8 D +acid 1 3.1 R_C-term +acid 1 3.5 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -591,14 +573,14 @@ IPC2_peptide -2.22 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 4.1 - 4.2 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 4.2 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 1 4.2 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 2 4.3 E +acid 1 3.3 E_C-term +acid 1 3.5 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -635,14 +617,14 @@ IPC2_peptide -3.22 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 3.7 - 3.8 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 4.2 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 1 4.2 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 3 3.8 D +acid 1 3.3 D_C-term +acid 1 3.5 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -679,18 +661,16 @@ IPC2_peptide -4.06 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 4.9 - 5.0 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : K 8.2 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 4.2 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 1 10.3 K +base 3 6.2 H +base 1 4.2 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 5 4.3 E +acid 1 3.3 E_C-term +acid 1 3.5 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -727,23 +707,14 @@ IPC2_peptide 0.67 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 7.6 - 8.1 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 4.2 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 9 6.3 H +base 1 4.2 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 1 3.1 H_C-term +acid 1 3.5 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -780,18 +751,15 @@ IPC2_peptide -3.82 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 5.3 - 5.4 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 4.2 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 4 6.2 H +base 1 4.2 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 4 4.3 E +acid 1 3.3 E_C-term +acid 1 3.5 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -828,17 +796,17 @@ IPC2_peptide 1.2 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 8.7 - 8.9 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : K 8.2 -smiles or AA, base pKa : K 8.2 -smiles or AA, base pKa : CC(=O)NCCCC[C@H](N)C(C)=O 7.9 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 4.2 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 2 10.2 K +base 1 7.9 CC(=O)NCCCC[C@H](N)C(C)=O +base 1 4.2 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 1 4.3 E +acid 3 9.9 Y +acid 1 3.1 Y_C-term +acid 1 3.5 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -875,18 +843,15 @@ IPC2_peptide -2.82 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 5.8 - 5.9 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 4.2 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 4 6.3 H +base 1 4.2 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 3 4.3 E +acid 1 3.1 H_C-term +acid 1 3.5 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -923,16 +888,15 @@ IPC2_peptide 1.43 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 9.4 - 9.5 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : K 8.2 -smiles or AA, base pKa : K 8.2 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 4.2 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 2 10.2 K +base 1 4.2 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 1 3.1 K_C-term +acid 3 9.9 Y +acid 1 3.5 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -969,18 +933,16 @@ IPC2_peptide 0.08 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 7.2 - 7.9 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : R 11.5 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 4.2 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 1 12.1 R +base 3 6.2 H +base 1 4.2 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 1 4.3 E +acid 1 3.1 R_C-term +acid 1 3.5 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -1017,17 +979,16 @@ IPC2_peptide 1.17 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 8.5 - 8.7 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : K 8.2 -smiles or AA, base pKa : CC(=O)NCCCC[C@H](N)C(C)=O 7.9 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 4.2 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 2 8.4 G_N-term +base 1 10.3 K +base 1 7.9 CC(=O)NCCCC[C@H](N)C(C)=O +base 1 4.2 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 1 4.4 E +acid 1 3.3 E_C-term +acid 1 3.5 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -1064,16 +1025,15 @@ IPC2_peptide 1.45 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 9.5 - 9.6 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : K 8.2 -smiles or AA, base pKa : K 8.2 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 4.2 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 2 10.2 K +base 1 4.2 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 1 3.1 K_C-term +acid 2 9.9 Y +acid 1 3.5 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -1110,15 +1070,15 @@ IPC2_peptide -2.12 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 4.6 - 4.7 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 4.2 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 1 6.3 H +base 1 4.2 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 2 4.3 E +acid 1 3.1 H_C-term +acid 1 3.5 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -1155,16 +1115,16 @@ IPC2_peptide -0.12 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 6.8 - 7.8 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : R 11.5 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 4.2 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 1 12.1 R +base 1 6.2 H +base 1 4.2 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 1 4.3 E +acid 1 3.1 R_C-term +acid 1 3.5 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -1201,16 +1161,15 @@ IPC2_peptide 1.47 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 9.7 - 9.8 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : K 8.2 -smiles or AA, base pKa : K 8.2 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 4.2 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 2 10.2 K +base 1 4.2 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 1 3.1 K_C-term +acid 1 10.0 Y +acid 1 3.5 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -1247,16 +1206,15 @@ IPC2_peptide -1.02 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 6.2 - 6.4 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 4.2 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 2 6.3 H +base 1 4.2 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 1 4.3 E +acid 1 3.1 H_C-term +acid 1 3.5 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -1293,13 +1251,13 @@ IPC2_peptide 1.62 pH interval with charge between -0.2 and 0.2 and prediction tool: pkamatcher pI interval: 9.9 - 10.1 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : K 8.2 -smiles or AA, base pKa : R 11.5 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 4.2 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 1 10.3 K +base 1 12.1 R +base 1 4.2 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 1 3.1 R_C-term +acid 1 10.0 Y +acid 1 3.5 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 diff --git a/pIChemiSt/test/examples/payload_5_out.txt b/pIChemiSt/test/examples/payload_5_out.txt index b8a616b..366e7ba 100644 --- a/pIChemiSt/test/examples/payload_5_out.txt +++ b/pIChemiSt/test/examples/payload_5_out.txt @@ -34,18 +34,15 @@ IPC2_peptide -3.82 pH interval with charge between -0.2 and 0.2 and prediction tool: acd pI interval: 5.3 - 5.4 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 3.1 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 4 6.2 H +base 1 3.1 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 4 4.3 E +acid 1 3.3 E_C-term +acid 1 4.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -82,17 +79,17 @@ IPC2_peptide 1.25 pH interval with charge between -0.2 and 0.2 and prediction tool: acd pI interval: 8.8 - 9.0 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : K 8.2 -smiles or AA, base pKa : K 8.2 -smiles or AA, base pKa : CC(=O)NCCCC[C@H](N)C(C)=O 8.0 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 3.1 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 2 10.2 K +base 1 8.0 CC(=O)NCCCC[C@H](N)C(C)=O +base 1 3.1 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 1 4.3 E +acid 3 9.9 Y +acid 1 3.1 Y_C-term +acid 1 4.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -129,18 +126,15 @@ IPC2_peptide -2.82 pH interval with charge between -0.2 and 0.2 and prediction tool: acd pI interval: 5.9 - 6.0 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 3.1 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 4 6.3 H +base 1 3.1 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 3 4.3 E +acid 1 3.1 H_C-term +acid 1 4.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -177,16 +171,15 @@ IPC2_peptide 1.43 pH interval with charge between -0.2 and 0.2 and prediction tool: acd pI interval: 9.4 - 9.5 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : K 8.2 -smiles or AA, base pKa : K 8.2 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 3.1 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 2 10.2 K +base 1 3.1 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 1 3.1 K_C-term +acid 3 9.9 Y +acid 1 4.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -223,18 +216,16 @@ IPC2_peptide 0.08 pH interval with charge between -0.2 and 0.2 and prediction tool: acd pI interval: 7.2 - 7.9 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : R 11.5 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 3.1 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 1 12.1 R +base 3 6.2 H +base 1 3.1 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 1 4.3 E +acid 1 3.1 R_C-term +acid 1 4.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -271,17 +262,16 @@ IPC2_peptide 1.23 pH interval with charge between -0.2 and 0.2 and prediction tool: acd pI interval: 8.4 - 8.6 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : K 8.2 -smiles or AA, base pKa : CC(=O)NCCCC[C@H](N)C(C)=O 8.0 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 3.1 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 2 8.4 G_N-term +base 1 10.3 K +base 1 8.0 CC(=O)NCCCC[C@H](N)C(C)=O +base 1 3.1 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 1 4.4 E +acid 1 3.3 E_C-term +acid 1 4.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -318,16 +308,15 @@ IPC2_peptide 1.45 pH interval with charge between -0.2 and 0.2 and prediction tool: acd pI interval: 9.5 - 9.6 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : K 8.2 -smiles or AA, base pKa : K 8.2 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 3.1 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 2 10.2 K +base 1 3.1 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 1 3.1 K_C-term +acid 2 9.9 Y +acid 1 4.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -364,15 +353,15 @@ IPC2_peptide -2.12 pH interval with charge between -0.2 and 0.2 and prediction tool: acd pI interval: 4.5 - 4.6 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 3.1 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 1 6.3 H +base 1 3.1 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 2 4.3 E +acid 1 3.1 H_C-term +acid 1 4.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -409,16 +398,16 @@ IPC2_peptide -0.12 pH interval with charge between -0.2 and 0.2 and prediction tool: acd pI interval: 6.8 - 7.8 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : R 11.5 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 3.1 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 1 12.1 R +base 1 6.2 H +base 1 3.1 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 1 4.3 E +acid 1 3.1 R_C-term +acid 1 4.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -455,16 +444,15 @@ IPC2_peptide 1.47 pH interval with charge between -0.2 and 0.2 and prediction tool: acd pI interval: 9.7 - 9.8 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : K 8.2 -smiles or AA, base pKa : K 8.2 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 3.1 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 2 10.2 K +base 1 3.1 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 1 3.1 K_C-term +acid 1 10.0 Y +acid 1 4.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -501,16 +489,15 @@ IPC2_peptide -1.02 pH interval with charge between -0.2 and 0.2 and prediction tool: acd pI interval: 6.2 - 6.4 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : H 6.4 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 3.1 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 2 6.3 H +base 1 3.1 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 1 4.3 E +acid 1 3.1 H_C-term +acid 1 4.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 ====================================================================================================================================================== pI @@ -547,13 +534,13 @@ IPC2_peptide 1.62 pH interval with charge between -0.2 and 0.2 and prediction tool: acd pI interval: 9.9 - 10.1 -List of calculated BASE pKa values with their fragments -smiles or AA, base pKa : G_N-term 7.9 -smiles or AA, base pKa : K 8.2 -smiles or AA, base pKa : R 11.5 -smiles or AA, base pKa : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 3.1 - -List of calculated ACID pKa values with their fragments - -List of constantly ionized fragments -smiles, charge : CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 1.0 +List of calculated pKa values or constant charges +Type Count pKa_or_constant_Q Fragment +base 1 8.4 G_N-term +base 1 10.3 K +base 1 12.1 R +base 1 3.1 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +acid 1 3.1 R_C-term +acid 1 10.0 Y +acid 1 4.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 +constant charge 1 1.0 CC(=O)Nc1ccc(-c2c3ccc(=[N+](C)C)cc-3oc3cc(N(C)C)ccc23)c(C(=O)O)c1 diff --git a/pIChemiSt/test/test_cli.py b/pIChemiSt/test/test_cli.py index 8d74512..b7caf03 100644 --- a/pIChemiSt/test/test_cli.py +++ b/pIChemiSt/test/test_cli.py @@ -96,6 +96,27 @@ def test_console_json_output(): assert result == expected +def test_console_json_output_images(): + """Validity of console JSON output.""" + args = arg_parser( + [ + "-i", + f"{examples_dir}/payload_1.smi", + "-of", + "json", + "--print_fragment_pkas", + "--generate_fragment_images", + "--method", + "pkamatcher", + ] + ) + result = stdout_to_variable(run_pichemist, args) + result = json.loads(result) + with open(f"{examples_dir}/payload_1_out_images.json", "r") as f: + expected = json.load(f) + assert result == expected + + def test_file_csv_output(): """Validity of CSV file output.""" tmp_filepath = tempfile.NamedTemporaryFile(suffix=".csv").name @@ -232,9 +253,7 @@ def test_smiles_stdin_input_2(): args = arg_parser( [ "-i", - "N[C@@]([H])(CS)C(=O)N[C@@]([H])(CC(=O)N)" - "C(=O)N[C@@]([H])(CS)C(=O)N[C@@]([H])(CC" - "(=O)N)C(=O)O", + "N[C@@]([H])(CS)C(=O)N[C@@]([H])(CC(=O)N)C(=O)N[C@@]([H])(CS)C(=O)N[C@@]([H])(CC(=O)N)C(=O)O", # noqa: E501 "-if", "smiles_stdin", "--print_fragment_pkas", @@ -243,7 +262,7 @@ def test_smiles_stdin_input_2(): ] ) result = stdout_to_variable(run_pichemist, args) - with open(f"{examples_dir}/payload_2_out.txt", "r") as f: + with open(f"{examples_dir}/payload_2_out_smiles.txt", "r") as f: expected = f.read() assert result == expected @@ -262,7 +281,72 @@ def test_fasta_stdin_input(): ] ) result = stdout_to_variable(run_pichemist, args) - with open(f"{examples_dir}/payload_2_out.txt", "r") as f: + with open(f"{examples_dir}/payload_2_out_fasta.txt", "r") as f: + expected = f.read() + assert result == expected + + +def test_fasta_stdin_capped_cterm_input(): + """Validity of FASTA stdin input and text output.""" + args = arg_parser( + [ + "-i", + "CNCN", + "-if", + "fasta_stdin", + "--print_fragment_pkas", + "--method", + "pkamatcher", + "--ionizable_cterm", + "false", + ] + ) + result = stdout_to_variable(run_pichemist, args) + with open(f"{examples_dir}/payload_2_out_fasta_capped_cterm.txt", "r") as f: + expected = f.read() + assert result == expected + + +def test_fasta_stdin_capped_nterm_input(): + """Validity of FASTA stdin input and text output.""" + args = arg_parser( + [ + "-i", + "CNCN", + "-if", + "fasta_stdin", + "--print_fragment_pkas", + "--method", + "pkamatcher", + "--ionizable_nterm", + "false", + ] + ) + result = stdout_to_variable(run_pichemist, args) + with open(f"{examples_dir}/payload_2_out_fasta_capped_nterm.txt", "r") as f: + expected = f.read() + assert result == expected + + +def test_fasta_stdin_all_capped_input(): + """Validity of FASTA stdin input and text output.""" + args = arg_parser( + [ + "-i", + "CNCN", + "-if", + "fasta_stdin", + "--print_fragment_pkas", + "--method", + "pkamatcher", + "--ionizable_nterm", + "false", + "--ionizable_cterm", + "false", + ] + ) + result = stdout_to_variable(run_pichemist, args) + with open(f"{examples_dir}/payload_2_out_fasta_all_capped.txt", "r") as f: expected = f.read() assert result == expected diff --git a/pIChemiSt/test/test_pkamatcher.py b/pIChemiSt/test/test_pkamatcher.py index e1b3c44..01197c0 100644 --- a/pIChemiSt/test/test_pkamatcher.py +++ b/pIChemiSt/test/test_pkamatcher.py @@ -4,11 +4,12 @@ def test_pka_matcher_list(): - smiles = ["CC(=O)N[C@@H](CCCN)C(C)=O", - "CC(=O)N[C@@](C)(CC(=O)O)C(C)=O"] + smiles = ["CC(=O)N[C@@H](CCCN)C(C)=O", "CC(=O)N[C@@](C)(CC(=O)O)C(C)=O"] res = matcher.calculate_pka_from_list(smiles) - expected = ([(10.4, "CC(=O)N[C@@H](CCCN)C(C)=O")], - [(3.46, "CC(=O)N[C@@](C)(CC(=O)O)C(C)=O")], []) + expected = ( + [(10.4, "CC(=O)N[C@@H](CCCN)C(C)=O")], + [(3.46, "CC(=O)N[C@@](C)(CC(=O)O)C(C)=O")], + ) assert res == expected, f"got {res}" diff --git a/pI_fasta/AUTHORS.md b/pI_fasta/AUTHORS.md deleted file mode 100644 index 822a48b..0000000 --- a/pI_fasta/AUTHORS.md +++ /dev/null @@ -1,2 +0,0 @@ -pI_fasta_v1.4/ - Andrey I. Frolov diff --git a/pI_fasta/README.md b/pI_fasta/README.md deleted file mode 100644 index fce21f3..0000000 --- a/pI_fasta/README.md +++ /dev/null @@ -1,33 +0,0 @@ -![Maturity level-0](https://img.shields.io/badge/Maturity%20Level-ML--0-red) - -pI_fasta.py - -Program calculates isoelectic point of protein/peptide based on the FASTA sequence. The following sets of amino-acid pKa values are implemented:'IPC_peptide','ProMoST','Gauci_calib','Bjellqvist','Rodwell','Grimsley','Thurlkill','Solomon','Lehninger','EMBOSS' as described in http://isoelectric.org -The mean value and variation between different sets are also calculated. The program can plot the corresponding titration curves. Also the total charge at pH 7.4 is reported. - - -HOW TO RUN - - module load matplotlib - cd TEST - - # input a single sequence file and plot the charge versus pH curves - python3 ../pI_fasta.py -i P43220.fasta -x - - # input sequence as a string and output into JSON formated text - python3 ../pI_fasta.py -s AKD -j - - # input multiple sequences from a file and output into a csv file - python3 ../pI_fasta.py -i multi.fasta -o multi_OUTPUT.csv - - -DEPENDENCIES - - python3 or later - matplotlib/3.0.3 (tested with) - Biopython/1.73 (tested with) - -PLATFORM - - Tested on linux CentOS - diff --git a/pI_fasta/TEST/P43220.fasta b/pI_fasta/TEST/P43220.fasta deleted file mode 100644 index 74d3ec7..0000000 --- a/pI_fasta/TEST/P43220.fasta +++ /dev/null @@ -1,9 +0,0 @@ ->sp|P43220|GLP1R_HUMAN Glucagon-like peptide 1 receptor OS=Homo sapiens OX=9606 GN=GLP1R PE=1 SV=2 -MAGAPGPLRLALLLLGMVGRAGPRPQGATVSLWETVQKWREYRRQCQRSLTEDPPPATDL -FCNRTFDEYACWPDGEPGSFVNVSCPWYLPWASSVPQGHVYRFCTAEGLWLQKDNSSLPW -RDLSECEESKRGERSSPEEQLLFLYIIYTVGYALSFSALVIASAILLGFRHLHCTRNYIH -LNLFASFILRALSVFIKDAALKWMYSTAAQQHQWDGLLSYQDSLSCRLVFLLMQYCVAAN -YYWLLVEGVYLYTLLAFSVLSEQWIFRLYVSIGWGVPLLFVVPWGIVKYLYEDEGCWTRN -SNMNYWLIIRLPILFAIGVNFLIFVRVICIVVSKLKANLMCKTDIKCRLAKSTLTLIPLL -GTHEVIFAFVMDEHARGTLRFIKLFTELSFTSFQGLMVAILYCFVNNEVQLEFRKSWERW -RLEHLHIQRDSSMKPLKCPTSSLSSGATAGSSMYTATCQASCS diff --git a/pI_fasta/TEST/multi.fasta b/pI_fasta/TEST/multi.fasta deleted file mode 100644 index 0db064f..0000000 --- a/pI_fasta/TEST/multi.fasta +++ /dev/null @@ -1,8 +0,0 @@ -# Dummy fasta file with multiple entries - ->test1 -PEPTIDE ->test2 -PICHEMIST ->test3 -AAAAAAAAAAA diff --git a/pI_fasta/TEST/multi_OUTPUT.csv b/pI_fasta/TEST/multi_OUTPUT.csv deleted file mode 100644 index da49bd4..0000000 --- a/pI_fasta/TEST/multi_OUTPUT.csv +++ /dev/null @@ -1,4 +0,0 @@ -mol_name,fasta,pI mean,pI std,pI interval -test1,PEPTIDE,3.3214111328125,0.8192578757090565,2.80 - 3.20 -test2,PICHEMIST,5.2900390625,0.3181016498982185,4.80 - 5.50 -test3,AAAAAAAAAAA,5.75390625,0.6001912130209005,3.00 - 8.90 diff --git a/pI_fasta/pI_fasta.py b/pI_fasta/pI_fasta.py deleted file mode 100755 index cf06ea4..0000000 --- a/pI_fasta/pI_fasta.py +++ /dev/null @@ -1,1064 +0,0 @@ -#!/usr/bin/env python -### -### Last update: Andrey Frolov, AstraZeneca, Molndal. 29/01/2021 -### First verion: Andrey Frolov, AstraZeneca, Molndal. 11/02/2016 -### -import json -import math -import optparse -import os -import sys -from copy import copy -from itertools import cycle -from json import encoder - -import numpy as np -from matplotlib.pyplot import * - -encoder.FLOAT_REPR = lambda o: format(o, ".2f") - -from pka_sets_fasta import * - -import csv - -# Turns a dictionary into a class -class Dict2Class(object): - def __init__(self, my_dict): - for key in my_dict: - setattr(self, key, my_dict[key]) - - -def list_to_comma_seprated_string(l): - s = "" - for v in l: - s += str(v) + "," - return s[:-1] - - -# http://www.petercollingridge.co.uk/sites/files/peter/predictPI.txt -# def calculateAminoAcidCharge(amino_acid, pH, pKa): -# q = charges[amino_acid] -# if q>0: -# return q / (1 + 10**(pH - pKa[amino_acid])) -# else: -# return q / (1 + 10**(pKa[amino_acid] - pH)) - - -def calculateBasicAminoAcidCharge(pH, pKa): - return 1 / (1 + 10 ** (pH - pKa)) - - -def calculateAcidicAminoAcidCharge(pH, pKa): - return -1 / (1 + 10 ** (pKa - pH)) - - -def calculatePhosphateCharge(pH, pKa1, pKa2): - Ka1 = 10 ** (-pKa1) - Ka2 = 10 ** (-pKa2) - H = 10 ** (-pH) - - f1 = (H * Ka1) / (H**2 + H * Ka1 + Ka1 * Ka2) # fraction of [AH-] - f2 = f1 * Ka2 / H # fraction of [A2-] - - return -2 * f2 + (-1) * f1 # average charge of phosphate group - - -# def calculateProteinCharge(IonizableTerminiOfNTermRes, NTermRes, MiddleSeq, CTermRes, IonizableTerminiOfCTermRes, pH,pKa_basic,pKa_acidic,pKa_TerminusIonizableGroup, NPhosphateGroups, NAlkylLysGroups, NDiAlkylLysGroups): -def calculateProteinCharge(pH): - - global seq, IonizableTerminiOfNTermRes, NTermRes, MiddleSeq, CTermRes, IonizableTerminiOfCTermRes, mid_pH, pKa_basic, pKa_acidic, pKa_TerminusIonizableGroup, NPhosphateGroups, NAlkylLysGroups, NDiAlkylLysGroups, na, nb, lCyclic, lPrintpKaSets, lIgnoreC, tolerance - - protein_charge = 0 - - # Middle sequence - for AA in pKa_basic.keys(): - pKa = pKa_basic[AA][0] - protein_charge += MiddleSeq.count(AA) * calculateBasicAminoAcidCharge(pH, pKa) - for AA in pKa_acidic.keys(): - pKa = pKa_acidic[AA][0] - protein_charge += MiddleSeq.count(AA) * calculateAcidicAminoAcidCharge(pH, pKa) - - # Terminus residues - for AA in NTermRes + CTermRes: - if AA in pKa_basic.keys(): - pKa = pKa_basic[AA][1] - protein_charge += calculateBasicAminoAcidCharge(pH, pKa) - if AA in pKa_acidic.keys(): - pKa = pKa_acidic[AA][1] - protein_charge += calculateAcidicAminoAcidCharge(pH, pKa) - - # Ionizable terminus groups - for AA in IonizableTerminiOfNTermRes: - pKa = pKa_TerminusIonizableGroup[AA][0] - protein_charge += calculateBasicAminoAcidCharge(pH, pKa) - - for AA in IonizableTerminiOfCTermRes: - pKa = pKa_TerminusIonizableGroup[AA][1] - protein_charge += calculateAcidicAminoAcidCharge(pH, pKa) - - # PTMs - ### Now all phosphorilated AAs have the same pKa s for phosphate group - if NPhosphateGroups != 0: - protein_charge += NPhosphateGroups * calculatePhosphateCharge( - pH, pKa_noncanonical["pKa1_phosphate"], pKa_noncanonical["pKa2_phosphate"] - ) - if NAlkylLysGroups != 0: - protein_charge += NAlkylLysGroups * calculateBasicAminoAcidCharge( - pH, pKa_basic["K"][0] + pKa_noncanonical["dpKa_alkylLys"] - ) - if NDiAlkylLysGroups != 0: - protein_charge += NDiAlkylLysGroups * calculateBasicAminoAcidCharge( - pH, pKa_basic["K"][0] + pKa_noncanonical["dpKa_dialkylLys"] - ) - - return protein_charge - - -# Define pH span tocalcualte itration curve and where to search for pI. -def define_pH_span(): - pH_llim = -1 - pH_hlim = 15 - return [pH_llim, pH_hlim] - - -# def calculateIsoelectricPoint(IonizableTerminiOfNTermRes, NTermRes, MiddleSeq, CTermRes, IonizableTerminiOfCTermRes,pKa_basic,pKa_acidic,pKa_TerminusIonizableGroup, NPhosphateGroups, NAlkylLysGroups, NDiAlkylLysGroups): -def calculateIsoelectricPoint(): - - global seq, IonizableTerminiOfNTermRes, NTermRes, MiddleSeq, CTermRes, IonizableTerminiOfCTermRes, mid_pH, pKa_basic, pKa_acidic, pKa_TerminusIonizableGroup, NPhosphateGroups, NAlkylLysGroups, NDiAlkylLysGroups, na, nb, lCyclic, lPrintpKaSets, lIgnoreC, tolerance - - # tolerance=0.01 - charge_tol = 0.05 - # min_pH, max_pH = 0 , 14 - pH_lim = define_pH_span() - min_pH0 = pH_lim[0] - max_pH0 = pH_lim[1] - - min_pH = min_pH0 - max_pH = max_pH0 - - while True: - mid_pH = 0.5 * (max_pH + min_pH) - # protein_charge = calculateProteinCharge(IonizableTerminiOfNTermRes, NTermRes, MiddleSeq, CTermRes, IonizableTerminiOfCTermRes, mid_pH,pKa_basic,pKa_acidic,pKa_TerminusIonizableGroup, NPhosphateGroups, NAlkylLysGroups, NDiAlkylLysGroups) - protein_charge = calculateProteinCharge(mid_pH) - - if na == 0 and nb != 0: - refcharge = charge_tol * nb - - elif nb == 0 and na != 0: - refcharge = -charge_tol * na - - else: - refcharge = 0.0 - - if protein_charge > refcharge + tolerance: - min_pH = mid_pH - elif protein_charge < refcharge - tolerance: - max_pH = mid_pH - else: - return mid_pH - - if mid_pH <= min_pH0: - return min_pH0 - elif mid_pH >= max_pH0: - return max_pH0 - - -# def CalcChargepHCurve(IonizableTerminiOfNTermRes, NTermRes, MiddleSeq, CTermRes, IonizableTerminiOfCTermRes): -# def CalcChargepHCurve(): -# from numpy import arange -# global seq,IonizableTerminiOfNTermRes, NTermRes, MiddleSeq, CTermRes, IonizableTerminiOfCTermRes, mid_pH,pKa_basic,pKa_acidic,pKa_TerminusIonizableGroup, NPhosphateGroups, NAlkylLysGroups, NDiAlkylLysGroups, na, nb, lCyclic, lPrintpKaSets, lIgnoreC, tolerance -# -# pH_a=arange(0,14,0.1) -# Q_a=pH_a*0.0 - -# for i in range(len(pH_a)): -# #Q = calculateProteinCharge(IonizableTerminiOfNTermRes, NTermRes, MiddleSeq, CTermRes, IonizableTerminiOfCTermRes,pH_a[i]) -# Q = calculateProteinCharge(pH_a[i]) -# Q_a[i]=Q -# -# return pH_a, Q_a - - -def CalcChargepHCurve(): - global seq, IonizableTerminiOfNTermRes, NTermRes, MiddleSeq, CTermRes, IonizableTerminiOfCTermRes, mid_pH, pKa_basic, pKa_acidic, pKa_TerminusIonizableGroup, NPhosphateGroups, NAlkylLysGroups, NDiAlkylLysGroups, na, nb, lCyclic, lPrintpKaSets, lIgnoreC, tolerance - pH_lim = define_pH_span() - pH_a = np.arange(pH_lim[0], pH_lim[1], 0.1) - Q_a = pH_a * 0.0 - for i in range(len(pH_a)): - # Q = calculateMolCharge(base_pkas, acid_pkas, diacid_pkas, pH_a[i],constant_q=constant_q) - Q = calculateProteinCharge(pH_a[i]) - Q_a[i] = Q - pH_Q = np.vstack((pH_a, Q_a)) - return pH_Q - - -def separateTerminalRes(sequence): - NTermRes = sequence[0] - CTermRes = sequence[-1] - MiddleSeq = sequence[1:-1] - return NTermRes, MiddleSeq, CTermRes - - -def split_sequence(sequence): - - # global IonizableTerminiOfNTermRes, NTermRes, CTermRes, IonizableTerminiOfCTermRes - global seq, IonizableTerminiOfNTermRes, NTermRes, MiddleSeq, CTermRes, IonizableTerminiOfCTermRes, mid_pH, pKa_basic, pKa_acidic, pKa_TerminusIonizableGroup, NPhosphateGroups, NAlkylLysGroups, NDiAlkylLysGroups, na, nb, lCyclic, lPrintpKaSets, lIgnoreC, tolerance - global titAdd - titAdd = "" - - if not lCyclic: - ### Assume linear, not branched peptide sequence - - ### If custom - # if NTermRes == '_' and CTermRes == '_' and (IonizableTerminiOfNTermRes == '_' or IonizableTerminiOfNTermRes == '') and (IonizableTerminiOfCTermRes == '_' or IonizableTerminiOfCTermRes == ''): - # MiddleSeq = sequence[1:-1] - # else: - # print("---NOTE! custom termini residues and/or ionizable termini given. No termini residues would be identified from the given sequence. Custom given residues will be used instead.") - # if NTermRes == '_': - # print('---Error! custom termini specified => NTermRes thus must be specified explicitly ') - # sys.exit(1) - # if CTermRes == '_': - # print('---Error! custom termini specified => CTermRes thus must be specified explicitly ') - # sys.exit(1) - # if IonizableTerminiOfNTermRes == '_': - # print('---Error! custom termini specified => IonizableTerminiOfNTermRes thus must be specified explicitly ') - # sys.exit(1) - # if IonizableTerminiOfCTermRes == '_': - # print('---Error! custom termini specified => IonizableTerminiOfCTermRes thus must be specified explicitly ') - # sys.exit(1) - # MiddleSeq = sequence - - MiddleSeq = sequence[1:-1] - - if IonizableTerminiOfNTermRes == "_": - IonizableTerminiOfNTermRes = sequence[0] - else: - if IonizableTerminiOfNTermRes == "": - titAdd += ", capped N-terminus" - else: - titAdd += ( - ", custom ionizable termini -NH2: " + IonizableTerminiOfNTermRes - ) - - if NTermRes == "_": - NTermRes = sequence[0] - else: - titAdd += ", custom N termini residues: " + NTermRes - - if CTermRes == "_": - CTermRes = sequence[-1] - else: - titAdd += ", custom C termini residues: " + CTermRes - - if IonizableTerminiOfCTermRes == "_": - IonizableTerminiOfCTermRes = sequence[-1] - else: - if IonizableTerminiOfCTermRes == "": - titAdd += ", capped C-terminus" - else: - titAdd += ( - ", custom ionizable termini -COOH: " + IonizableTerminiOfCTermRes - ) - - else: - ### Assume cyclic peptide: no ionizable termini, no terminal residues - MiddleSeq = sequence - titAdd += ", cyclic" - NTermRes = "" - CTermRes = "" - IonizableTerminiOfNTermRes = "" - IonizableTerminiOfCTermRes = "" - - if NPhosphateGroups > 0: - titAdd += ", " + str(NPhosphateGroups) + " phosphorilated res" - if NAlkylLysGroups > 0: - titAdd += ", " + str(NAlkylLysGroups) + " monoalkyl Lys" - if NDiAlkylLysGroups > 0: - titAdd += ", " + str(NDiAlkylLysGroups) + " dialkyl Lys" - - return ( - IonizableTerminiOfNTermRes, - NTermRes, - MiddleSeq, - CTermRes, - IonizableTerminiOfCTermRes, - ) - - -def mean(lst): - """calculates mean""" - return sum(lst) / len(lst) - - -def stddev(lst): - """returns the standard deviation of lst""" - mn = mean(lst) - variance = sum([(e - mn) ** 2 for e in lst]) - return math.sqrt(variance) - - -def stddev(lst): - """returns the standard deviation of lst""" - mn = mean(lst) - variance = sum([(e - mn) ** 2 for e in lst]) - return math.sqrt(variance) - - -def stderr(lst): - """returns the standard error of the mean of lst""" - mn = mean(lst) - variance = sum([(e - mn) ** 2 for e in lst]) - return math.sqrt(variance) / math.sqrt(len(lst)) - - -def print_pka_set(): - print() - print() - print( - "----------------------------------------------------------------------------" - ) - print("--- Used pKa values for each set: (http://isoelectric.ovh.org/theory.html) ") - print(json.dumps(pKa_sets_short, indent=2)) - print() - print( - "----------------------------------------------------------------------------" - ) - print( - "For the following sets the pKa depends on the Residue poistion in the sequence, also the termini group pKa change among different terminal Residue." - ) - print("See references details. ") - # print 'Therefore 3 pKa values are given for each residue: middle, N-terminal, C-terminal positions in the sequence' - # print 'Also, the pKas of the termini -NH2 and -COOH depend on the residue. Thus for each residue 2 values are given: pKa of N-term and pKa of C-term. ' - # print - print( - "ProMoST set: see http://isoelectric.ovh.org/theory.html and http://proteomics.mcw.edu/promost_adv.html for details" - ) - # print - # print json.dumps(pKa_sets['ProMoST'], indent=2) - - # print - print( - "Gauci_calibrated set: see Gauci et al. Proteomics 2008, 8, 4898 and https://github.com/ypriverol/pIR for details" - ) - # print json.dumps(pKa_sets['Gauci_calib'], indent=2) - - print("--------------------------------------------------------------") - print("Supported nonatural aminoacids (teh same for all sets of pKa):") - print() - print(" Phosphate pKa1 " + str(pKa_noncanonical["pKa1_phosphate"])) - print(" Phosphate pKa2 " + str(pKa_noncanonical["pKa2_phosphate"])) - print() - print( - " Alkylated Lys: addition to Lys pKa " - + str(pKa_noncanonical["dpKa_alkylLys"]) - + " data from ACD lab: pKa of amine: 10.69. The delta for methylated amine compared to amine. ### Zhang, Vogel, J. Bio. Chem. 1993, 268, 30, 22420 (Table III, Lys75) pKas of methylated 10.87, dimethylated 10.12" - ) - print() - print( - " Dialkylated Lys: addition to Lys pKa " - + str(pKa_noncanonical["dpKa_dialkylLys"]) - + " data from Zhang, Vogel et al. (ACD lab: pKa of dimethylamine: 9.83 +- 0.28 - error too high. The delta for methylated amine compared to amine. ### Zhang, Vogel, J. Bio. Chem. 1993, 268, 30, 22420 (Table III, Lys75) pKas of methylated 10.87, dimethylated 10.12" - ) - print() - - return - - -def print_output(dict_pI_fasta, args): - for molid_ind in dict_pI_fasta.keys(): - dict_single = dict_pI_fasta[molid_ind] - print_output_dict(dict_single["pI"], "pI", dict_single["plot_title_info"]) - print_output_dict( - dict_single["QpH7"], "Q at pH7.4", dict_single["plot_title_info"] - ) - if args.lPrintpKa: - print_pka_set() - return - - -def print_output_dict(out_dict, prop, title_info): - # global tit - lj = 12 - keys = list(out_dict.keys()) - keys.remove("std") - keys.insert(0, "std") - keys.remove("err") - keys.insert(0, "err") - keys.remove(prop + " mean") - keys.insert(0, prop + " mean") - - # tit="sequence: "+seq+titAdd - p = out_dict - print(" ") - print( - "======================================================================================================================================================" - ) - print(prop + " for " + title_info) - print("---------------------------------") - for k in keys: - print(k.rjust(lj) + " " + str(round(p[k], 2)).ljust(lj)) - print(" ") - - return - - -def options_parser(): - # Parse options - usage = """pI_fasta.py is the program for calculation of peptide isoelectric points using Henderson-Hasselbalch equations. Various sets of pKa data are supported (see below). - -Sequence input: python pI_fasta.py -s GGKGD -FASTA file input: python pI_fasta.py -i example.fasta -With plot: python pI_fasta.py -s GGKGD -x -Cyclic peptide: python pI_fasta.py -s GGKGD -r -x -Capped N terminus: python pI_fasta.py -s GGKGD -b \"\" -x -Capped C terminus: python pI_fasta.py -s GGKGD -a \"\" -x -Phosphorylated residue: python pI_fasta.py -s GXD -p 1 -x -Monoalkylated Lys: python pI_fasta.py -s GXD -l 1 -x -Dialkylated Lys: python pI_fasta.py -s GXD -d 1 -x -Branched peptide (custom terminal residues): - python pI_fasta.py -s GGKGD -c AX -n E -a AX -b E -x -Use custom pKa set: python pI_fasta.py -s GGKGD -m IPC2_peptide,ProMoST,Gauci -x -Help: python pI_fasta.py -h -Most extended. All defaults listed. Mind: \"_\" indicates that the residue is automatically deduced from the given sequence: - python pI_fasta.py -s GGKGD -t 0.001 -c _ -n _ -a _ -b _ -p 0 -l 0 -d 0 -m IPC2_peptide,IPC_peptide,ProMoST,Gauci,Grimsley,Thurlkill,Lehninger,Toseland - ---- JSON fomatting -JSON formated input: python pI_fasta.py -g \'{\"1\":{\"mol_name\":\"name1\",\"fasta\":\"GGKGD\"}}\' -JSON formated output: python pI_fasta.py -s GGKGD -j - -Nested structure of JSON, top level - unique IDs of the molecules, bottom level data fields for each molecule "mol_name" and "fasta" - -See help for all the options. - ---- For theory and pKa sets see: http://isoelectric.ovh.org/theory.html -For ProMoST and Gauchi sets pKa depends on whether the residue sits at the termini or in the middle of the sequence -Also, the pKa of ionizable termini depends on the type of termini residue. -The rest of the sets position invariant. -for ProMoST set: see http://proteomics.mcw.edu/promost_adv.html -for Gauci set: see Gauci et al. Proteomics 2008, 8, 4898 and https://github.com/ypriverol/pIR -Supported nonatural aminoacids (the same for all sets of pKa): Monoalkylated Lys, DiAlkylated Lys, phosphorilations -derived from literature, ACDlab predictions, see -z for more details. - -Andrey Frolov, AstraZeneca, Molndal. 04/03/2016 -Last updated 25/10/2022 - -""" - - parser = optparse.OptionParser(usage=usage) - parser.add_option( - "-s", action="store", dest="seq", help="peptide sequence", default="" - ) - parser.add_option( - "-i", - action="store", - dest="inputFile", - help="input file name in fasta format", - default="", - ) - parser.add_option( - "-g", - action="store", - dest="inputJSON", - help="input file name in JSON format", - default="", - ) - parser.add_option( - "-o", - action="store", - dest="outputFile", - help="output file name in csv format", - default="", - ) - parser.add_option( - "-t", - action="store", - type="float", - dest="tol", - help="tolerance on total protein charge. default = 0.001", - default=0.001, - ) - - parser.add_option( - "-c", - action="store", - type="string", - dest="CTermRes", - help="Custom list of C terminus residues. By default it is set to the last residues of the given sequence. This option is useful if you have a branched peptide with several terminus residues", - default="_", - ) - parser.add_option( - "-n", - action="store", - type="string", - dest="NTermRes", - help="Custom list of N terminus residues. By default it is set to the first residues of the given sequence. This option is useful if you have a branched peptide with several terminus residues", - default="_", - ) - - parser.add_option( - "-a", - action="store", - type="string", - dest="IonizableTerminiOfCTermRes", - help="Custom list of residues with ionizable C terminus (-COOH). By default it is set to the last residue of the given sequence. This option is useful if you want to cap the termini (exclude them from calculations) or you have a branched peptide with several terminus residues", - default="_", - ) - parser.add_option( - "-b", - action="store", - type="string", - dest="IonizableTerminiOfNTermRes", - help="Custom list of residues with ionizable N terminus (-NH2). By default it is set to the first residue of the given sequence. This option is useful if you want to cap the termini (exclude them from calculations) or you have a branched peptide with several terminus residues", - default="_", - ) - - parser.add_option( - "-p", - action="store", - type="int", - dest="NPhosphateGroups", - help="Number of phosphorilated residues. Phosphorilated residues must be denoted as X in the sequence. default = 0", - default=0, - ) - parser.add_option( - "-l", - action="store", - type="int", - dest="NAlkylLysGroups", - help="Number of monoalkylated Lys residues. These residues should be denoted as X in the sequence. default = 0", - default=0, - ) - parser.add_option( - "-d", - action="store", - type="int", - dest="NDiAlkylLysGroups", - help="Number of dialkylated Lys residues. These residues should be denoted as X in the sequence. default = 0", - default=0, - ) - - parser.add_option( - "-m", - action="store", - type="string", - dest="pka_set_list", - help="List of pKa sets to use in calculation (comma separated). default = " - + list_to_comma_seprated_string(pKa_sets_to_use), - default="", - ) - parser.add_option( - "-r", - action="store_true", - dest="lCyclic", - help="Is it cyclic? No termini residues are derived from sequence and also no ionizable termini (-NH2 and -COOH) of the terminal residues are derived from sequence (However, custom values are not overwritten). default = False", - default=False, - ) - parser.add_option( - "-x", - action="store_true", - dest="lPlot", - help="plot charge/pH curves. Requires NumPy and Matplotlib. default = False", - default=False, - ) - parser.add_option( - "-q", - action="store_true", - dest="lIgnoreC", - help="ignore cysteins, assume they are protected. default = False", - default=False, - ) - parser.add_option( - "-z", - action="store_true", - dest="lPrintpKa", - help="print used pKa values in the output. default = False", - default=False, - ) - parser.add_option( - "-j", - action="store_true", - dest="l_json", - help="use JSON as an output format. default = False", - default=False, - ) - - (options, args) = parser.parse_args() - - return options.__dict__ - - -### PLOT titration curve -def plot_titration_curve(pH_Q_dict, figFileName): - matplotlib.rcParams.update({"font.size": 16}) - lines = ["-", "--", "-.", ":"] - w1 = 4.0 - w2 = 3.0 - w3 = 2.0 - w4 = 1.0 - linew = [w1, w1, w2, w2, w3, 3, w4, w4] - linecycler = cycle(lines) - linewcycler = cycle(linew) - - figure(figsize=(8, 6)) - i = 0 - for pKaset in pKa_sets_to_use: - i += 1 - pH_Q = pH_Q_dict[pKaset] - l = plot( - pH_Q[:, 0], - pH_Q[:, 1], - next(linecycler), - label=pKaset, - linewidth=next(linewcycler), - ) - if pKaset == "IPC2_peptide": - setp(l, linewidth=8, linestyle="-", color="k") - - # Store data for output - if i == 1: - pH = pH_Q[:, 0] - Q_M = pH_Q[:, 1] - else: - Q_M = np.column_stack([Q_M, pH_Q[:, 1]]) - - plot(pH, pH * 0, "k-") - plot([7, 7], [np.min(Q_M), np.max(Q_M)], "k-") - # xlim([np.min(pH),np.max(pH)]) - xlim([2, 12]) - ylim([np.min(Q_M), np.max(Q_M)]) - - legend( - loc="center right", bbox_to_anchor=[1.1, 0.5], ncol=1, shadow=True, fontsize=10 - ).get_frame().set_alpha(1) - ylabel("peptide charge") - xlabel("pH") - - title("Titration curve") - - minorticks_on() - grid(True) - - # show() - savefig(figFileName) - return - - -# def plot_titration_curve(fig_file_name='OUT_titration_curve.png'): -# from numpy import arange, column_stack -# from matplotlib.pyplot import plot, figure,setp,legend,ylabel,xlabel,title,minorticks_on,grid,savefig -# #matplotlib.rcParams.update({'font.size': 16}) -# from itertools import cycle -# global seq,IonizableTerminiOfNTermRes, NTermRes, MiddleSeq, CTermRes, IonizableTerminiOfCTermRes, mid_pH,pKa_basic,pKa_acidic,pKa_TerminusIonizableGroup, NPhosphateGroups, NAlkylLysGroups, NDiAlkylLysGroups, na, nb, lCyclic, lPrintpKaSets, lIgnoreC, tolerance, tit -# lines = ["-","--","-.",":"] -# w1=4.0 -# w2=3.0 -# w3=2.0 -# w4=1.0 -# linew = [w1,w1, w2,w2, w3,3, w4,w4] -# linecycler = cycle(lines) -# linewcycler = cycle(linew) - -# figure() - -# i=0 -# for pKaset in pKa_sets_to_use: -# i+=1 -# pKa_basic=pKa_sets[pKaset]['pKa_basic'] -# pKa_acidic=pKa_sets[pKaset]['pKa_acidic'] -# pKa_TerminusIonizableGroup=pKa_sets[pKaset]['pKa_TerminusIonizableGroup'] - -# #pH,Q = CalcChargepHCurve(IonizableTerminiOfNTermRes, NTermRes, MiddleSeq, CTermRes, IonizableTerminiOfCTermRes) -# pH,Q = CalcChargepHCurve() -# -# l=plot(pH,Q,next(linecycler),label=pKaset,linewidth=next(linewcycler)) -# if pKaset == 'ProMoST': -# setp(l,linewidth=8,linestyle='-',color='k') - -# # Store data for output -# if i==1: Q_M = pH -# Q_M=column_stack([Q_M,Q]) - - -# plot(pH,pH*0,'k-') -# plot([7,7],[min(Q),max(Q)],'k-') - -# legend(loc="center right", bbox_to_anchor=[1.1, 0.5],ncol=1, shadow=True).get_frame().set_alpha(1) -# ylabel('peptide charge') -# xlabel('pH') -# -# title(tit) -# -# minorticks_on() -# grid(True) - -# #show() -# #savefig("OUT_titration_curve.png") -# savefig(fig_file_name) -# #pltsave("OUT_titration_curve", ext="png", close=True, verbose=True) - -# return - - -def read_fasta_file(inputFile): - - filename, ext = os.path.splitext(inputFile) - - # Initialize file reader - if not ext == ".fasta": - raise Exception( - '!Warning: extension of file is not ".fasta". Assuming it is fasta formatted input. Continue. ' - ) - - from Bio import SeqIO - - biosuppl = SeqIO.parse(open(inputFile), "fasta") - - mol_supply_json = {} - mol_unique_ID = 0 - for biofasta in biosuppl: - mol_unique_ID += 1 - # unique index, mol title, RDkit mol object, mol fasta - mol_supply_json[mol_unique_ID] = { - "mol_name": biofasta.id, - "mol_obj": None, - "fasta": str(biofasta.seq), - } - - return mol_supply_json - - -def calc_pI_fasta( - options={ - "inputFile": "", - "inputDict": {}, - "inputJSON": "", - "outputFile": "", - "sequenceList": "", - "seq": "", - "tol": 0.001, - "CTermRes": "_", - "NTermRes": "_", - "IonizableTerminiOfCTermRes": "_", - "IonizableTerminiOfNTermRes": "_", - "lCyclic": False, - "NPhosphateGroups": 0, - "NAlkylLysGroups": 0, - "NDiAlkylLysGroups": 0, - "lPrintpKa": False, - "lPlot": False, - "lIgnoreC": False, - "plot_filename": "OUT_titration_curve.png", - "l_json": False, - } -): - - args = Dict2Class(options) - - # Get options - if len(args.seq) != 0: - # assume single fasta input - mol_unique_ind = 1 - mol_name = "unknown" - fasta = args.seq - mol_supply_json = {} - mol_supply_json[mol_unique_ind] = { - "mol_name": mol_name, - "mol_obj": None, - "fasta": fasta, - } - - elif len(args.inputFile) != 0: - # Assume filename as input - inputFile = args.inputFile - mol_supply_json = read_fasta_file(inputFile) - - elif len(args.inputJSON) != 0: - # Assume molecule JSON supply as input - mol_supply_json = json.loads(args.inputJSON) - elif args.inputDict: # if not an empty dictionary - # Assume Dict molecule supply as input - mol_supply_json = args.inputDict - else: - raise Exception( - "Error: either fasta, input file *.fasta or JSON should be given for pI_fasta.py. Exit. " - ) - sys.exit(1) - - dict_out_pI_fasta = {} - for mol_unique_ind in mol_supply_json.keys(): - options_single = copy(options) - options_single["seq"] = mol_supply_json[mol_unique_ind]["fasta"] - dict_pI_fasta_single = calc_pI_fasta_single_sequence(options_single) - dict_pI_fasta_single["mol_name"] = mol_supply_json[mol_unique_ind]["mol_name"] - dict_out_pI_fasta[mol_unique_ind] = dict_pI_fasta_single - - return dict_out_pI_fasta - - -def calc_pI_fasta_single_sequence( - options={ - "seq": "", - "tol": 0.001, - "CTermRes": "_", - "NTermRes": "_", - "IonizableTerminiOfCTermRes": "_", - "IonizableTerminiOfNTermRes": "_", - "lCyclic": False, - "NPhosphateGroups": 0, - "NAlkylLysGroups": 0, - "NDiAlkylLysGroups": 0, - "lPrintpKa": False, - "lPlot": False, - "lIgnoreC": False, - "plot_filename": "OUT_titration_curve.png", - "l_json": False, - "pka_set_list": "", - } -): - - global seq, IonizableTerminiOfNTermRes, NTermRes, MiddleSeq, CTermRes, IonizableTerminiOfCTermRes, mid_pH, pKa_basic, pKa_acidic, pKa_TerminusIonizableGroup, NPhosphateGroups, NAlkylLysGroups, NDiAlkylLysGroups, na, nb, lCyclic, lPrintpKaSets, lIgnoreC, tolerance, tit, pKa_sets_to_use - - if len(options["seq"]) == 0: - raise Exception("no sequence given. See --help for more information") - - if options["pka_set_list"] != "": - pKa_sets_to_use = options["pka_set_list"].split(",") - - for set in pKa_sets_to_use: - if set not in all_known_pKa_sets: - raise Exception( - "---Error! pKa set " - + set - + " is not known. Check your -m option. Exit." - ) - - # Get options - orig_seq = options["seq"] - seq = orig_seq.upper() - sequence = seq - IonizableTerminiOfNTermRes = options["IonizableTerminiOfNTermRes"] - IonizableTerminiOfCTermRes = options["IonizableTerminiOfCTermRes"] - NTermRes = options["NTermRes"] - CTermRes = options["CTermRes"] - tolerance = options["tol"] - NPhosphateGroups = options["NPhosphateGroups"] - NAlkylLysGroups = options["NAlkylLysGroups"] - NDiAlkylLysGroups = options["NDiAlkylLysGroups"] - lIgnoreC = options["lIgnoreC"] - lPrintpKaSets = options["lPrintpKa"] - lPlot = options["lPlot"] - lCyclic = options["lCyclic"] - - lsaveplotdata = False - lCalc = True - - if len(seq) < 2: - raise Exception( - "---!Error: number of residues in sequence is less than 2. Not yet supported. Exiting." - ) - sys.exit(1) - - for R in seq: - if R not in known_res: - raise Exception( - "---!Error: residue " - + R - + " is not known. Please use X if this is a noncaninical residue. Exiting." - ) - sys.exit(1) - - if lIgnoreC: - sequence = sequence.replace("C", "X") - - ##### Calc pI - - ( - IonizableTerminiOfNTermRes, - NTermRes, - MiddleSeq, - CTermRes, - IonizableTerminiOfCTermRes, - ) = split_sequence(sequence) - - nb = 0 - na = 0 - for R in NTermRes + MiddleSeq + CTermRes: - if R in known_basic_res: - nb += 1 - if R in known_acidic_res: - na += 1 - for R in IonizableTerminiOfNTermRes: - nb += 1 - for R in IonizableTerminiOfCTermRes: - na += 1 - - if na == 0 and nb == 0: - print( - "---!Warning: no ionizable groups in the sequence. pI is not defined or = any pH. Exiting." - ) - sys.exit(0) - - charge_tol = 0.05 - if na == 0 and nb != 0: - print( - "---!Warning: no acidic ionizable groups, only basic groups present in the sequence. pI is not defined and thus won't be calculated. However, will estimate pH when peptide has charge less than " - + str(charge_tol * 100) - + "% of the peptide maximum possible charge (by absolute value). Continue." - ) - # lPlot = True - # lCalc = True - - if nb == 0 and na != 0: - print( - "---!Warning: no basic ionizable groups, only acidic groups present in the sequence. pI is not defined and thus won't be calculated. However, will estimate pH when peptide has charge less than " - + str(charge_tol * 100) - + "% of the peptide maximum possible charge (by absolute value). Continue." - ) - # lPlot = True - # lCalc = True - - tit = "sequence: " + orig_seq + titAdd - ### Calculate pI - if lCalc: - - seq_dict = {} - pI_dict = {} - Q_dict = {} - pH_Q_dict = {} - - # for pKaset in pKa_sets.keys(): - for pKaset in pKa_sets_to_use: - - pKa_basic = pKa_sets[pKaset]["pKa_basic"] - pKa_acidic = pKa_sets[pKaset]["pKa_acidic"] - pKa_TerminusIonizableGroup = pKa_sets[pKaset]["pKa_TerminusIonizableGroup"] - - pI = calculateIsoelectricPoint() - pI_dict[pKaset] = pI - - Q_pH74 = calculateProteinCharge(7.4) - Q_dict[pKaset] = Q_pH74 - - # pH_Q = CalcChargepHCurve(all_base_pkas, all_acid_pkas, all_diacid_pkas, constant_q = molecule_constant_charge) - pH_Q = CalcChargepHCurve() - pH_Q = pH_Q.T - - pH_Q_dict[pKaset] = pH_Q - - # pI - pIl = [] - for k in pI_dict.keys(): - pIl += [pI_dict[k]] - pI_dict["pI mean"] = mean(pIl) - pI_dict["std"] = stddev(pIl) - pI_dict["err"] = stderr(pIl) - - # charge at pH=7.4 - Ql = [] - for k in Q_dict.keys(): - Ql += [Q_dict[k]] - Q_dict["Q at pH7.4 mean"] = mean(Ql) - Q_dict["std"] = stddev(Ql) - Q_dict["err"] = stderr(Ql) - - # print isoelectric interval - pKaset = "IPC2_peptide" - int_tr = 0.2 # TODO define it elsewhere - pH_Q = pH_Q_dict[pKaset] - Q = pH_Q[:, 1] - pH = pH_Q[:, 0] - pH_int = pH[(Q > -int_tr) & (Q < int_tr)] - pH_Q = pH_Q_dict[pKaset] - - # isoelectric interval - pH range where the charge is within the given threshold. If molecule permanently has a charge the interval is not defined and NaN are provided. - if len(pH_int) > 1: - interval = (pH_int[0], pH_int[-1]) - else: - interval = (float("NaN"), float("NaN")) - - ### Plot titration curve - plot_filename = "" - if lPlot: - if "plot_filename" in options.keys(): - plot_filename = options["plot_filename"] - else: - plot_filename = "OUT_titration_curve_pI_fasta.png" - - # plot_titration_curve(pH_Q_dict,fig_file_name=plot_filename) - plot_titration_curve(pH_Q_dict, plot_filename) - - dict_pI_fasta = { - "sequence": orig_seq, - "pI": pI_dict, - "QpH7": Q_dict, - "pI_interval": interval, - "plot_filename": plot_filename, - "plot_title_info": tit, - } - - return dict_pI_fasta - - -#####====================================================================================================================================================== - -if __name__ == "__main__": - - options = options_parser() - args = Dict2Class(options) - - dict_out_pI_fasta = calc_pI_fasta(options) - - ### ---------------------------------------------------------------------- - # Output - if args.outputFile == "": # output plain text - if args.l_json: - print(json.dumps(dict_out_pI_fasta, indent=2)) - else: - print_output(dict_out_pI_fasta, args) - - else: # output file - - known_out_file_types = [".csv"] - filename, out_fext = os.path.splitext(args.outputFile) - if out_fext not in known_out_file_types: - raise Exception( - "Error! Output file extention not in supported file types:" - + str(known_file_types) - ) - sys.exit(1) - - elif out_fext == ".csv": - with open(args.outputFile, "w") as csv_f: - csv_w = csv.writer(csv_f) - count = 0 - for mi in dict_out_pI_fasta.keys(): - count += 1 - if count == 1: - header = [ - "mol_name", - "fasta", - "pI mean", - "pI std", - "pI interval", - ] - csv_w.writerow(header) - - row = [] - row += [dict_out_pI_fasta[mi]["mol_name"]] - row += [dict_out_pI_fasta[mi]["sequence"]] - row += [dict_out_pI_fasta[mi]["pI"]["pI mean"]] - row += [dict_out_pI_fasta[mi]["pI"]["std"]] - row += [ - " - ".join( - ["%.2f" % x for x in dict_out_pI_fasta[mi]["pI_interval"]] - ) - ] - csv_w.writerow(row) - - # print info - dict_file = { - "outputFile": args.outputFile, - "outputInfo": "Number of molecules processed:" - + str(len(dict_out_pI_fasta.keys())), - } - print(json.dumps(dict_file)) diff --git a/pI_fasta/pka_sets_fasta.py b/pI_fasta/pka_sets_fasta.py deleted file mode 100755 index 6fffcfe..0000000 --- a/pI_fasta/pka_sets_fasta.py +++ /dev/null @@ -1,517 +0,0 @@ -### -### Last update: Andrey Frolov, AstraZeneca, Molndal. 08/01/2020 -### First verion: Andrey Frolov, AstraZeneca, Molndal. 11/02/2016 -### -import optparse -import sys - -# import numpy as np -# import pylab - -# import json -# from json import encoder -# encoder.FLOAT_REPR = lambda o: format(o, '.2f') - - -###### -###### Some global definitions -###### - -all_known_pKa_sets = [ - "ProMoST", - "IPC_peptide", - "IPC2_peptide", - "Gauci", - "Bjellqvist", - "Rodwell", - "Grimsley", - "Thurlkill", - "EMBOSS", - "DTASelect", - "Solomon", - "Sillero", - "Lehninger", - "Toseland", - "Nozaki", - "Dawson", -] - - -def list_to_comma_seprated_string(l): - s = "" - for v in l: - s += str(v) + "," - return s[:-1] - - -### Preselected set of pKa to display -# pKa_sets_to_use=['IPC_peptide','ProMoST','Gauci_calib','Bjellqvist','Rodwell','Grimsley','Thurlkill','Solomon','Lehninger','EMBOSS'] -# pKa_sets_to_use=['IPC_peptide','ProMoST','Gauci','Bjellqvist','Grimsley','Thurlkill','Lehninger','Toseland'] -pKa_sets_to_use = [ - "IPC2_peptide", - "IPC_peptide", - "ProMoST", - "Gauci", - "Grimsley", - "Thurlkill", - "Lehninger", - "Toseland", -] - -known_basic_res = ["K", "R", "H"] -known_acidic_res = ["D", "E", "C", "Y", "U"] -known_res = [ - "G", - "A", - "S", - "P", - "V", - "T", - "C", - "I", - "L", - "N", - "D", - "Q", - "K", - "E", - "M", - "H", - "F", - "R", - "Y", - "W", - "X", - "Z", - "B", - "U", -] - - -def FillMissingAAtopKa_TerminusIonizableGroup(pKa_TerminusIonizableGroup): - - # Calc average - sumNterm = 0 - sumCterm = 0 - # for k,v in pKa_TerminusIonizableGroup.iteritems(): - for k in pKa_TerminusIonizableGroup.keys(): - v = pKa_TerminusIonizableGroup[k] - sumNterm += v[0] - sumCterm += v[1] - avNterm = sumNterm / len(pKa_TerminusIonizableGroup.keys()) - avCterm = sumCterm / len(pKa_TerminusIonizableGroup.keys()) - - for R in known_res: - if R not in pKa_TerminusIonizableGroup.keys(): - if R == "X": - pKa_TerminusIonizableGroup[R] = [avNterm, avCterm] - elif R == "Z": - pKa_TerminusIonizableGroup[R] = [ - ( - pKa_TerminusIonizableGroup["E"][0] - + pKa_TerminusIonizableGroup["Q"][0] - ) - / 2, - ( - pKa_TerminusIonizableGroup["E"][1] - + pKa_TerminusIonizableGroup["Q"][1] - ) - / 2, - ] - elif R == "B": - pKa_TerminusIonizableGroup[R] = [ - ( - pKa_TerminusIonizableGroup["N"][0] - + pKa_TerminusIonizableGroup["D"][0] - ) - / 2, - ( - pKa_TerminusIonizableGroup["N"][1] - + pKa_TerminusIonizableGroup["D"][1] - ) - / 2, - ] - elif R == "U": - # copy of X - pKa_TerminusIonizableGroup[R] = [avNterm, avCterm] - else: - print( - "---!Error: data for specific -NH2 and -COOH termini pKa values for residue " - + R - + " is not given in the " - + SetName - + " pKa set. Set this residue identical to X (average of all available). Check set. Exit." - ) - sys.exit(1) - - return pKa_TerminusIonizableGroup - - -###------------------------------------------------------------------------------------------ -### Sets of pKa - -pKa_sets = {} -pKa_sets_short = {} - -pKa_sets_short["EMBOSS"] = { - "K": 10.8, - "R": 12.5, - "H": 6.5, - "D": 3.9, - "E": 4.1, - "C": 8.5, - "Y": 10.1, - "Nterm": 8.6, - "Cterm": 3.6, -} - - -pKa_sets_short["IPC2_peptide"] = { - "K": 8.165, - "R": 11.493, - "H": 6.439, - "D": 3.969, - "E": 4.507, - "C": 9.439, - "Y": 9.153, - "Nterm": 7.947, - "Cterm": 2.977, -} - - -pKa_sets_short["IPC_peptide"] = { - "K": 10.517, - "R": 12.503, - "H": 6.018, - "D": 3.887, - "E": 4.317, - "C": 8.297, - "Y": 10.071, - "Nterm": 9.564, - "Cterm": 2.383, -} - -# Amino acid NH2 COOH C D E H K R Y -pKa_sets_short["DTASelect"] = { - "Nterm": 8.0, - "Cterm": 3.1, - "C": 8.5, - "D": 4.4, - "E": 4.4, - "H": 6.5, - "K": 10.0, - "R": 12.0, - "Y": 10.0, -} - -pKa_sets_short["Bjellqvist"] = { - "Nterm": 7.5, - "Cterm": 3.55, - "C": 9.0, - "D": 4.05, - "E": 4.45, - "H": 5.98, - "K": 10.0, - "R": 12.0, - "Y": 10.0, -} - -pKa_sets_short["Solomon"] = { - "Nterm": 9.6, - "Cterm": 2.4, - "C": 8.3, - "D": 3.9, - "E": 4.3, - "H": 6.0, - "K": 10.5, - "R": 12.5, - "Y": 10.1, -} - -pKa_sets_short["Sillero"] = { - "Nterm": 8.2, - "Cterm": 3.2, - "C": 9.0, - "D": 4.0, - "E": 4.5, - "H": 6.4, - "K": 10.4, - "R": 12.0, - "Y": 10.0, -} - - -pKa_sets_short["Rodwell"] = { - "Nterm": 8.0, - "Cterm": 3.1, - "C": 8.33, - "D": 3.68, - "E": 4.25, - "H": 6.0, - "K": 11.5, - "R": 11.5, - "Y": 10.07, -} - -pKa_sets_short["Lehninger"] = { - "Nterm": 9.69, - "Cterm": 2.34, - "C": 8.33, - "D": 3.86, - "E": 4.25, - "H": 6.0, - "K": 10.5, - "R": 12.4, - "Y": 10.0, -} - -pKa_sets_short["Grimsley"] = { - "Nterm": 7.7, - "Cterm": 3.3, - "C": 6.8, - "D": 3.5, - "E": 4.2, - "H": 6.6, - "K": 10.5, - "R": 12.04, - "Y": 10.3, -} - -pKa_sets_short["Toseland"] = { - "Nterm": 8.71, - "Cterm": 3.19, - "C": 6.87, - "D": 3.6, - "E": 4.29, - "H": 6.33, - "K": 10.45, - "R": 12.0, - "Y": 9.61, -} - - -pKa_sets_short["Thurlkill"] = { - "Nterm": 8.0, - "Cterm": 3.67, - "C": 8.55, - "D": 3.67, - "E": 4.25, - "H": 6.54, - "K": 10.4, - "R": 12.0, - "Y": 9.84, -} - - -pKa_sets_short["Nozaki"] = { - "Nterm": 7.5, - "Cterm": 3.8, - "C": 9.5, - "D": 4.0, - "E": 4.4, - "H": 6.3, - "K": 10.4, - "R": 12.0, - "Y": 9.6, -} - - -pKa_sets_short["Dawson"] = { - "Nterm": 8.2, - "Cterm": 3.2, - "C": 8.3, - "D": 3.9, - "E": 4.3, - "H": 6, - "K": 10.5, - "R": 12.0, - "Y": 10.0, -} - - -def ConvertpKaSetIntoProMoSTformat(pKaset): - pKa_basic1 = {} - pKa_acidic1 = {} - pKa_TerminusIonizableGroup1 = {} - - for R in known_basic_res: - if R in pKa_sets_short[pKaset].keys(): - pKa = pKa_sets_short[pKaset][R] - pKa_basic1[R] = [pKa, pKa, pKa] - - for R in known_acidic_res: - if R in pKa_sets_short[pKaset].keys(): - pKa = pKa_sets_short[pKaset][R] - pKa_acidic1[R] = [pKa, pKa, pKa] - - for R in known_res: - pKa_Cterm = pKa_sets_short[pKaset]["Cterm"] - pKa_Nterm = pKa_sets_short[pKaset]["Nterm"] - pKa_TerminusIonizableGroup1[R] = [pKa_Nterm, pKa_Cterm] - - pKa_sets[pKaset] = { - "pKa_acidic": pKa_acidic1, - "pKa_basic": pKa_basic1, - "pKa_TerminusIonizableGroup": pKa_TerminusIonizableGroup1, - } - return - - -for pKaset in pKa_sets_short.keys(): - # for pKaset in ['EMBOSS']: - ConvertpKaSetIntoProMoSTformat(pKaset) - - -### Calibrated ExPASY - from Gauci et al. Proteomics 2008, 8, 4898 as implemented in pIR -SetName = "Gauci" - -# Acidic_Amino_Acids -# AA Primary N-Terminal C-Terminal -pKa_acidic1 = { - "D": [4.05, 4.05, 4.05], - "C": [9.0, 9.0, 9.0], - "E": [4.45, 4.45, 4.45], - "Y": [10.0, 10.0, 10.0], - "U": [ - 5.43, - 5.20, - 5.60, - ], # pK for U was taken from Byun et al. Biopolymers 2011, 95, 345 -} - - -# Basic_Amino_Acids -# AA Primary N-Terminal C-Terminal -pKa_basic1 = {"R": [12.0, 12.0, 12.0], "H": [5.98, 5.98, 5.98], "K": [10.0, 10.0, 10.0]} - - -# Terminal_Amino_Acids -# AA N-term C-Term -pKa_TerminusIonizableGroup1 = { - "A": [7.59, 3.55], - "R": [7.5, 3.55], - "N": [6.7, 3.55], - "D": [7.5, 4.55], - "C": [6.5, 3.55], - "E": [7.7, 4.75], - "Q": [7.5, 3.55], - "G": [7.5, 3.55], - "H": [7.5, 3.55], - "I": [7.5, 3.55], - "L": [7.5, 3.55], - "K": [7.5, 3.55], - "M": [7.0, 3.55], - "F": [7.5, 3.55], - "P": [8.3599, 3.55], - "S": [6.93, 3.55], - "T": [6.82, 3.55], - "W": [7.5, 3.55], - "Y": [7.5, 3.55], - "V": [7.44, 3.55], -} - - -pKa_sets[SetName] = { - "pKa_acidic": pKa_acidic1, - "pKa_basic": pKa_basic1, - "pKa_TerminusIonizableGroup": FillMissingAAtopKa_TerminusIonizableGroup( - pKa_TerminusIonizableGroup1 - ), -} - - -### -### Set ProMoST From http://proteomics.mcw.edu/promost_adv.html -### - -# Acidic_Amino_Acids -# AA Primary N-Terminal C-Terminal -pKa_acidic1 = { - "D": [4.07, 3.57, 4.57], - "E": [4.45, 4.15, 4.75], - "C": [8.28, 8.00, 9.00], - "Y": [9.84, 9.34, 10.34], - "U": [5.43, 5.20, 5.60], -} # pK for U was taken from Byun et al. Biopolymers 2011, 95, 345 - -# Basic_Amino_Acids -# AA Primary N-Terminal C-Terminal -pKa_basic1 = { - "K": [9.8, 10.00, 10.30], - "R": [12.5, 11.50, 11.50], - "H": [6.08, 4.89, 6.89], -} - -# Terminal_Amino_Acids -# AA N-term C-Term -pKa_TerminusIonizableGroup1 = { - "G": [7.50, 3.70], - "A": [7.58, 3.75], - "S": [6.86, 3.61], - "P": [8.36, 3.40], - "V": [7.44, 3.69], - "T": [7.02, 3.57], - "C": [8.12, 3.10], - "I": [7.48, 3.72], - "L": [7.46, 3.73], - "N": [7.22, 3.64], - "D": [7.70, 3.50], - "Q": [6.73, 3.57], - "K": [6.67, 3.40], - "E": [7.19, 3.50], - "M": [6.98, 3.68], - "H": [7.18, 3.17], - "F": [6.96, 3.98], - "R": [6.76, 3.41], - "Y": [6.83, 3.60], - "W": [7.11, 3.78], - "X": [7.26, 3.57], - "U": [7.26, 3.57], ### copy of X - "Z": [6.96, 3.54], - "B": [7.46, 3.57], -} - -pKa_sets["ProMoST"] = { - "pKa_acidic": pKa_acidic1, - "pKa_basic": pKa_basic1, - "pKa_TerminusIonizableGroup": pKa_TerminusIonizableGroup1, -} - - -### Noncanonical AAs. These values used for all sets of pKa available for standard AAs. -# PTM. Not complete... to exdend upon request -pKa_noncanonical = { - "pKa1_phosphate": 1.2, - "pKa2_phosphate": 6.9, - "dpKa_alkylLys": 0.15, # data from ACD lab: pKa of amine: 10.69. The delta for methylated amine compared to amine. ### Zhang, Vogel, J. Bio. Chem. 1993, 268, 30, 22420 (Table III, Lys75) pKas of methylated 10.87, dimethylated 10.12, - "dpKa_dialkylLys": 0.15 - 0.75, -} # data from Zhang, Vogel et al. (ACD lab: pKa of dimethylamine: 9.83 +- 0.28 - error too high. The delta for methylated amine compared to amine. ### Zhang, Vogel, J. Bio. Chem. 1993, 268, 30, 22420 (Table III, Lys75) pKas of methylated 10.87, dimethylated 10.12, - - -# Ala A Alanine -# Arg R Arginine -# Asn N Asparagine -# Asp D Aspartic acid -# Cys C Cysteine -# Gln Q Glutamine -# Glu E Glutamic acid -# Gly G Glycine -# His H Histidine -# Ile I Isoleucine -# Leu L Leucine -# Lys K Lysine -# Met M Methionine -# Phe F Phenylalanine -# Pro P Proline -# Pyl O Pyrrolysine -# Ser S Serine -# Sec U Selenocysteine -# Thr T Threonine -# Trp W Tryptophan -# Tyr Y Tyrosine -# Val V Valine -# Asx B Aspartic acid or Asparagine -# Glx Z Glutamic acid or Glutamine -# Xaa X Any amino acid -# Xle J Leucine or Isoleucine -# TERM termination codon diff --git a/peptide_tools_master/peptools/cli.py b/peptide_tools_master/peptools/cli.py index afd916c..9d98c0b 100755 --- a/peptide_tools_master/peptools/cli.py +++ b/peptide_tools_master/peptools/cli.py @@ -5,6 +5,7 @@ from peptools.io import generate_input from peptools.io import generate_output from peptools.io import generate_parameter_set +from peptools.utils import str2bool from peptools.wrapper import run_peptide_master @@ -22,7 +23,6 @@ def arg_parser(args): required=True, ) - ### pIChemiSt.py keys parser.add_argument( "--print_fragment_pkas", action="store_true", @@ -30,6 +30,15 @@ def arg_parser(args): help="Print the fragments with corresponding pKas used in pI calcution.", default=False, ) + + parser.add_argument( + "--generate_fragment_images", + default=False, + action="store_true", + dest="generate_fragment_images", + help="Generate 2D depiction of the frgament smiles in base64 format.", + ) + parser.add_argument( "--print_pka_set", action="store_true", @@ -38,20 +47,24 @@ def arg_parser(args): default=False, ) - ### pI_fasta.py keys + ### keys for fasta input parser.add_argument( - "--ionized_Cterm", - dest="ionized_Cterm", - action="store_true", - help="is C-terminus ionized [COO-]?", + "--ionizable_nterm", + type=str2bool, default=True, + dest="ionizable_nterm", + help="Applies to FASTA input only. " + "If set to 'false' the N-terminus is capped. " + "If set to 'true' the N-terminus is free amine. ", ) parser.add_argument( - "--ionized_Nterm", - dest="ionized_Nterm", - action="store_true", - help="is N-terminus ionized [N+]?", + "--ionizable_cterm", + type=str2bool, default=True, + dest="ionizable_cterm", + help="Applies to FASTA input only. " + "If set to 'false' the C-terminus is capped. " + "If set to 'true' the C-terminus is free amine. ", ) parser.add_argument( "-p", @@ -87,7 +100,14 @@ def main(): args = arg_parser(sys.argv[1:]) mol_supply_json, io_params = generate_input(args.input) params = generate_parameter_set(args, io_params) + # print(args) + # exit() + # print(mol_supply_json) + # print(params.__dict__) + # exit() dict_out = run_peptide_master(mol_supply_json, params) + # print(dict_out) + # exit() generate_output(mol_supply_json, dict_out, params) diff --git a/peptide_tools_master/peptools/io/_io.py b/peptide_tools_master/peptools/io/_io.py index 3da832b..38f3d09 100644 --- a/peptide_tools_master/peptools/io/_io.py +++ b/peptide_tools_master/peptools/io/_io.py @@ -106,24 +106,23 @@ def configure_runtime_parameters(args, input_file_extension): params = RuntimeParameters() params.generate_plot = False params.print_fragment_pkas = bool(args.print_fragment_pkas) + # TODO: Merge logic since pIfasta has been removed if input_file_extension in [ InputFileExtension.SMI, InputFileExtension.SDF, ]: params.calc_extn_coeff = True params.calc_pIChemiSt = True - params.calc_pI_fasta = False elif input_file_extension == InputFileExtension.FASTA: params.calc_extn_coeff = True - params.calc_pI_fasta = True - params.calc_pIChemiSt = False + params.calc_pIChemiSt = True return params def configure_chemical_parameters(args): return ChemicalParameters( - args.ionized_Cterm, - args.ionized_Nterm, + args.ionizable_cterm, + args.ionizable_nterm, args.NPhosphateGroups, args.NAlkylLysGroups, args.NDiAlkylLysGroups, @@ -138,9 +137,8 @@ def generate_parameter_set(args, io_params): def generate_output(mol_supply_json, dict_out, params): - dict_out_pIChemiSt = dict_out["output_pIChemiSt"] + pichemist_dict = dict_out["output_pIChemiSt"] ext_coeff_dict = dict_out["output_extn_coeff"] - pifasta_dict = dict_out["output_pI_fasta"] if not params.io.output_filename: _print_to_console_and_exit(dict_out) @@ -150,17 +148,15 @@ def generate_output(mol_supply_json, dict_out, params): mol = mol_supply_json[mi]["mol_obj"] if params.run.calc_pIChemiSt: - mol.SetProp("pI mean", "%.2f" % dict_out_pIChemiSt[mi]["pI"]["pI mean"]) - mol.SetProp("pI std", "%.2f" % dict_out_pIChemiSt[mi]["pI"]["std"]) + mol.SetProp("pI mean", "%.2f" % pichemist_dict[mi]["pI"]["pI mean"]) + mol.SetProp("pI std", "%.2f" % pichemist_dict[mi]["pI"]["std"]) mol.SetProp( "pI interval", - " - ".join( - ["%.2f" % x for x in dict_out_pIChemiSt[mi]["pI_interval"]] - ), + " - ".join(["%.2f" % x for x in pichemist_dict[mi]["pI_interval"]]), ) mol.SetProp( "pI interval threshold", - "%.2f" % dict_out_pIChemiSt[mi]["pI_interval_threshold"], + "%.2f" % pichemist_dict[mi]["pI_interval_threshold"], ) if params.run.calc_extn_coeff: @@ -215,16 +211,16 @@ def _print_to_console_and_exit(dict_out): def _generate_fasta_output(mol_supply_json, dict_out, params): ext_coeff_dict = dict_out["output_extn_coeff"] - pifasta_dict = dict_out["output_pI_fasta"] + pichemist_dict = dict_out["output_pIChemiSt"] dict_list = list() for mi in mol_supply_json.keys(): res = dict() fasta = mol_supply_json[mi]["fasta"] - if params.run.calc_pI_fasta: - res["pI mean"] = "%.2f" % pifasta_dict[mi]["pI"]["pI mean"] - res["pI std"] = "%.2f" % pifasta_dict[mi]["pI"]["std"] + if params.run.calc_pIChemiSt: + res["pI mean"] = "%.2f" % pichemist_dict[mi]["pI"]["pI mean"] + res["pI std"] = "%.2f" % pichemist_dict[mi]["pI"]["std"] if params.run.calc_extn_coeff: res["mol_name"] = ext_coeff_dict[mi]["mol_name"] diff --git a/peptide_tools_master/peptools/io/params.py b/peptide_tools_master/peptools/io/params.py index a1a074d..0e9acb3 100644 --- a/peptide_tools_master/peptools/io/params.py +++ b/peptide_tools_master/peptools/io/params.py @@ -24,20 +24,20 @@ def __init__(self): self.print_fragment_pkas = False self.calc_extn_coeff = False self.calc_pIChemiSt = False - self.calc_pI_fasta = False +# TODO: Remove sic params class ChemicalParameters: def __init__( self, - ionized_Cterm, - ionized_Nterm, + ionizable_cterm, + ionizable_nterm, NPhosphateGroups, # sic NAlkylLysGroups, # sic NDiAlkylLysGroups, # sic ): - self.ionized_Cterm = ionized_Cterm - self.ionized_Nterm = ionized_Nterm + self.ionizable_cterm = ionizable_cterm + self.ionizable_nterm = ionizable_nterm self.NPhosphateGroups = NPhosphateGroups # sic self.NAlkylLysGroups = NAlkylLysGroups # sic self.NDiAlkylLysGroups = NDiAlkylLysGroups # sic diff --git a/peptide_tools_master/peptools/utils.py b/peptide_tools_master/peptools/utils.py new file mode 100644 index 0000000..099ee18 --- /dev/null +++ b/peptide_tools_master/peptools/utils.py @@ -0,0 +1,31 @@ +import argparse +import logging +import os + + +def get_logger(name): + """ + Creates a logger where level is + determined by the env LOGGING_LEVEL. + + """ + log = logging.getLogger(name) + if os.environ.get("LOGGING_LEVEL") == "DEBUG": + logging.basicConfig(level=logging.DEBUG) + else: + logging.basicConfig(level=logging.INFO) + return log + + +def str2bool(v): + """ + Converts a string to a boolean. + """ + if isinstance(v, bool): + return v + if v.lower() in ("yes", "true", "t", "y", "1"): + return True + elif v.lower() in ("no", "false", "f", "n", "0"): + return False + else: + raise argparse.ArgumentTypeError("Boolean value expected.") diff --git a/peptide_tools_master/peptools/wrapper/__init__.py b/peptide_tools_master/peptools/wrapper/__init__.py index 9665ab3..3cf91f3 100644 --- a/peptide_tools_master/peptools/wrapper/__init__.py +++ b/peptide_tools_master/peptools/wrapper/__init__.py @@ -1,15 +1,12 @@ from peptools.wrapper.ec import calculate_extinction_coefficient from peptools.wrapper.pi import calculate_pichemist -from peptools.wrapper.pi import calculate_pifasta def run_peptide_master(mol_supply_json, params): ext_coeff_dict = calculate_extinction_coefficient(mol_supply_json, params.run) - pifasta_dict = calculate_pifasta(mol_supply_json, params.run, params.chem) - pichemist_dict = calculate_pichemist(mol_supply_json, params.run, params.io) + pichemist_dict = calculate_pichemist(mol_supply_json, params) dict_out = { "output_extn_coeff": ext_coeff_dict, - "output_pI_fasta": pifasta_dict, "output_pIChemiSt": pichemist_dict, } return dict_out diff --git a/peptide_tools_master/peptools/wrapper/pi.py b/peptide_tools_master/peptools/wrapper/pi.py index 5ca2cdb..2016682 100644 --- a/peptide_tools_master/peptools/wrapper/pi.py +++ b/peptide_tools_master/peptools/wrapper/pi.py @@ -1,63 +1,22 @@ from pichemist.api import pichemist_from_dict -from pI_fasta import calc_pI_fasta - -def calculate_pifasta(mol_supply_json, runtime_params, chem_params): - dict_out_pI_fasta = dict() - if runtime_params.calc_pI_fasta: - pI_fasta_options = _configure_options( - mol_supply_json, runtime_params, chem_params - ) - dict_out_pI_fasta = calc_pI_fasta(pI_fasta_options) - return dict_out_pI_fasta - - -def _configure_options(mol_supply_json, runtime_params, chem_params): - pI_fasta_options = { - "seq": "", - "inputDict": mol_supply_json, - "inputJSON": "", - "inputFile": "", - "outputFile": "", - "tol": 0.001, - "CTermRes": "_", - "NTermRes": "_", - "IonizableTerminiOfCTermRes": _get_ionized_residue(chem_params.ionized_Cterm), - "IonizableTerminiOfNTermRes": _get_ionized_residue(chem_params.ionized_Nterm), - "lCyclic": False, - "NPhosphateGroups": chem_params.NPhosphateGroups, - "NAlkylLysGroups": chem_params.NAlkylLysGroups, - "NDiAlkylLysGroups": chem_params.NDiAlkylLysGroups, - "lPrintpKa": False, - "lPlot": runtime_params.generate_plots, - "lIgnoreC": False, - "plot_filename": "OUT_titration_curve.png", - "l_json": True, - "pka_set_list": "", - } - return pI_fasta_options - - -def _get_ionized_residue(is_residue_ionized): - if is_residue_ionized: - return "_" - else: - return "" - - -def calculate_pichemist(mol_supply_json, run_params, io_params): +def calculate_pichemist(mol_supply_json, params): dict_out_pIChemiSt = dict() - if run_params.calc_pIChemiSt: + if params.run.calc_pIChemiSt: plot_filename_prefix = "temp" - if io_params.filepath_prefix: - plot_filename_prefix = io_params.filepath_prefix + if params.io.filepath_prefix: + plot_filename_prefix = params.io.filepath_prefix + # print(params.chem.__dict__) + # exit() dict_out_pIChemiSt = pichemist_from_dict( mol_supply_json, method="pkamatcher", ph_q_curve_file_prefix=plot_filename_prefix, - plot_ph_q_curve=run_params.generate_plots, - print_fragments=run_params.print_fragment_pkas, + plot_ph_q_curve=params.run.generate_plots, + print_fragments=params.run.print_fragment_pkas, + ionizable_nterm=params.chem.ionizable_nterm, + ionizable_cterm=params.chem.ionizable_cterm, ) return dict_out_pIChemiSt diff --git a/peptide_tools_master/test/examples/payload_1_out.json.stdout b/peptide_tools_master/test/examples/payload_1_out.json.stdout index 57b1a92..43c0aab 100644 --- a/peptide_tools_master/test/examples/payload_1_out.json.stdout +++ b/peptide_tools_master/test/examples/payload_1_out.json.stdout @@ -8,7 +8,6 @@ "mol_name": "none" } }, - "output_pI_fasta": {}, "output_pIChemiSt": { "1": { "mol_name": "none", diff --git a/peptide_tools_master/test/examples/payload_1_out_fragments.json.stdout b/peptide_tools_master/test/examples/payload_1_out_fragments.json.stdout index 328b2d6..ce59916 100644 --- a/peptide_tools_master/test/examples/payload_1_out_fragments.json.stdout +++ b/peptide_tools_master/test/examples/payload_1_out_fragments.json.stdout @@ -8,7 +8,6 @@ "mol_name": "none" } }, - "output_pI_fasta": {}, "output_pIChemiSt": { "1": { "mol_name": "none", @@ -45,173 +44,6 @@ "pI_interval_threshold": 0.2, "plot_filename": "temp_1.png", "pKa_set": "IPC2_peptide", - "base_pkas_fasta": { - "IPC2_peptide": [ - [ - 7.947, - "F_N-term" - ] - ], - "IPC_peptide": [ - [ - 9.564, - "F_N-term" - ] - ], - "ProMoST": [ - [ - 6.96, - "F_N-term" - ] - ], - "Gauci": [ - [ - 7.5, - "F_N-term" - ] - ], - "Grimsley": [ - [ - 7.7, - "F_N-term" - ] - ], - "Thurlkill": [ - [ - 8, - "F_N-term" - ] - ], - "Lehninger": [ - [ - 9.69, - "F_N-term" - ] - ], - "Toseland": [ - [ - 8.71, - "F_N-term" - ] - ] - }, - "acid_pkas_fasta": { - "IPC2_peptide": [ - [ - 4.507, - "E" - ], - [ - 2.977, - "E_C-term" - ], - [ - 9.153, - "Y" - ] - ], - "IPC_peptide": [ - [ - 4.317, - "E" - ], - [ - 2.383, - "E_C-term" - ], - [ - 10.071, - "Y" - ] - ], - "ProMoST": [ - [ - 4.75, - "E" - ], - [ - 3.5, - "E_C-term" - ], - [ - 9.84, - "Y" - ] - ], - "Gauci": [ - [ - 4.45, - "E" - ], - [ - 4.75, - "E_C-term" - ], - [ - 10, - "Y" - ] - ], - "Grimsley": [ - [ - 4.2, - "E" - ], - [ - 3.3, - "E_C-term" - ], - [ - 10.3, - "Y" - ] - ], - "Thurlkill": [ - [ - 4.25, - "E" - ], - [ - 3.67, - "E_C-term" - ], - [ - 9.84, - "Y" - ] - ], - "Lehninger": [ - [ - 4.25, - "E" - ], - [ - 2.34, - "E_C-term" - ], - [ - 10, - "Y" - ] - ], - "Toseland": [ - [ - 4.29, - "E" - ], - [ - 3.19, - "E_C-term" - ], - [ - 9.61, - "Y" - ] - ] - }, - "base_pkas_calc": [], - "acid_pkas_calc": [], - "constant_Qs_calc": [], "frag_base_pkas_fasta": { "1": { "type": "base", diff --git a/peptide_tools_master/test/examples/payload_2_out.csv b/peptide_tools_master/test/examples/payload_2_out.csv index 75d3e1a..601cf1f 100644 --- a/peptide_tools_master/test/examples/payload_2_out.csv +++ b/peptide_tools_master/test/examples/payload_2_out.csv @@ -1,2 +1,2 @@ pI mean,pI std,mol_name,Sequence(FASTA),e205(nm),e214(nm),e280(nm) -3.78,1.06,PEPTIDE_1,FPYVAE,28580,18018,1490 +3.82,1.10,PEPTIDE_1,FPYVAE,28580,18018,1490 diff --git a/peptide_tools_master/test/examples/payload_3_out.json.stdout b/peptide_tools_master/test/examples/payload_3_out.json.stdout index 50b24af..11d68ea 100644 --- a/peptide_tools_master/test/examples/payload_3_out.json.stdout +++ b/peptide_tools_master/test/examples/payload_3_out.json.stdout @@ -8,7 +8,6 @@ "mol_name": "none" } }, - "output_pI_fasta": {}, "output_pIChemiSt": { "1": { "mol_name": "none", @@ -45,142 +44,6 @@ "pI_interval_threshold": 0.2, "plot_filename": "temp_1.png", "pKa_set": "IPC2_peptide", - "base_pkas_fasta": { - "IPC2_peptide": [], - "IPC_peptide": [], - "ProMoST": [], - "Gauci": [], - "Grimsley": [], - "Thurlkill": [], - "Lehninger": [], - "Toseland": [] - }, - "acid_pkas_fasta": { - "IPC2_peptide": [ - [ - 4.507, - "E" - ], - [ - 2.977, - "E_C-term" - ], - [ - 9.153, - "Y" - ] - ], - "IPC_peptide": [ - [ - 4.317, - "E" - ], - [ - 2.383, - "E_C-term" - ], - [ - 10.071, - "Y" - ] - ], - "ProMoST": [ - [ - 4.75, - "E" - ], - [ - 3.5, - "E_C-term" - ], - [ - 9.84, - "Y" - ] - ], - "Gauci": [ - [ - 4.45, - "E" - ], - [ - 4.75, - "E_C-term" - ], - [ - 10, - "Y" - ] - ], - "Grimsley": [ - [ - 4.2, - "E" - ], - [ - 3.3, - "E_C-term" - ], - [ - 10.3, - "Y" - ] - ], - "Thurlkill": [ - [ - 4.25, - "E" - ], - [ - 3.67, - "E_C-term" - ], - [ - 9.84, - "Y" - ] - ], - "Lehninger": [ - [ - 4.25, - "E" - ], - [ - 2.34, - "E_C-term" - ], - [ - 10, - "Y" - ] - ], - "Toseland": [ - [ - 4.29, - "E" - ], - [ - 3.19, - "E_C-term" - ], - [ - 9.61, - "Y" - ] - ] - }, - "base_pkas_calc": [ - [ - 7.9, - "CC(=O)[C@H](Cc1ccccc1)NCCCCN" - ], - [ - 10.4, - "CC(=O)[C@H](Cc1ccccc1)NCCCCN" - ] - ], - "acid_pkas_calc": [], - "constant_Qs_calc": [], "frag_base_pkas_fasta": {}, "frag_acid_pkas_fasta": { "1": { @@ -205,13 +68,13 @@ "frag_base_pkas_calc": { "1": { "type": "base", - "frag": "fragment_1.png", + "frag": "CC(=O)[C@H](Cc1ccccc1)NCCCCN", "count": 1, "pka": 7.9 }, "2": { "type": "base", - "frag": "fragment_2.png", + "frag": "CC(=O)[C@H](Cc1ccccc1)NCCCCN", "count": 1, "pka": 10.4 } diff --git a/peptide_tools_master/test/examples/payload_6_out.json.stdout b/peptide_tools_master/test/examples/payload_6_out.json.stdout index 44e8ac6..f367625 100644 --- a/peptide_tools_master/test/examples/payload_6_out.json.stdout +++ b/peptide_tools_master/test/examples/payload_6_out.json.stdout @@ -8,21 +8,21 @@ "mol_name": "none" } }, - "output_pI_fasta": { + "output_pIChemiSt": { "1": { - "sequence": "MAGAP", + "mol_name": "none", "pI": { - "IPC2_peptide": 5.5, - "IPC_peptide": 6, - "ProMoST": 5.1875, - "Gauci": 5.28125, + "IPC2_peptide": 5, + "IPC_peptide": 7, + "ProMoST": 5.25, + "Gauci": 5.25, "Grimsley": 5.5, - "Thurlkill": 5.8125, - "Lehninger": 6, + "Thurlkill": 6, + "Lehninger": 7, "Toseland": 6, - "pI mean": 5.66015625, - "std": 0.8876732885400461, - "err": 0.3138399009024147 + "pI mean": 5.875, + "std": 2.0615528128088303, + "err": 0.7288689868556625 }, "QpH7": { "IPC2_peptide": -0.22101980206722793, @@ -38,13 +38,12 @@ "err": 0.2748132736858734 }, "pI_interval": [ - 3.5999999999999988, - 7.299999999999999 + 3.737499999999999, + 7.537499999999998 ], - "plot_filename": "OUT_titration_curve.png", - "plot_title_info": "sequence: MAGAP", - "mol_name": "none" + "pI_interval_threshold": 0.2, + "plot_filename": "temp_1.png", + "pKa_set": "IPC2_peptide" } - }, - "output_pIChemiSt": {} + } } diff --git a/peptide_tools_master/test/examples/payload_7_out.json.stdout b/peptide_tools_master/test/examples/payload_7_out.json.stdout new file mode 100644 index 0000000..34f0999 --- /dev/null +++ b/peptide_tools_master/test/examples/payload_7_out.json.stdout @@ -0,0 +1,80 @@ +{ + "output_extn_coeff": { + "1": { + "fasta": "FPYVAE", + "e205": 28580, + "e214": 18018, + "e280": 1490, + "mol_name": "none" + } + }, + "output_pIChemiSt": { + "1": { + "mol_name": "none", + "pI": { + "IPC2_peptide": 3.75, + "IPC_peptide": 3.34375, + "ProMoST": 4.125, + "Gauci": 4.59375, + "Grimsley": 3.75, + "Thurlkill": 3.96875, + "Lehninger": 3.3125, + "Toseland": 3.75, + "pI mean": 3.82421875, + "std": 1.101257714927573, + "err": 0.38935339902964433 + }, + "QpH7": { + "IPC2_peptide": -1.2370959572269449, + "IPC_peptide": -1.0081017452801901, + "ProMoST": -1.7348917509283845, + "Gauci": -1.4418394775037948, + "Grimsley": -1.3344079319254933, + "Thurlkill": -1.2034840355851255, + "Lehninger": -1.0068918835235123, + "Toseland": -1.051981916395253, + "Q at pH7.4 mean": -1.2523368372960872, + "std": 0.6619374142499742, + "err": 0.23403021716862277 + }, + "pI_interval": [ + 3.5749999999999993, + 4.062499999999998 + ], + "pI_interval_threshold": 0.2, + "plot_filename": "temp_1.png", + "pKa_set": "IPC2_peptide", + "frag_base_pkas_fasta": { + "1": { + "type": "base", + "frag": "F_N-term", + "count": 1, + "pka": 8.303428571428572 + } + }, + "frag_acid_pkas_fasta": { + "1": { + "type": "acid", + "frag": "Y", + "count": 1, + "pka": 9.951571428571429 + }, + "2": { + "type": "acid", + "frag": "E", + "count": 1, + "pka": 4.358142857142857 + }, + "3": { + "type": "acid", + "frag": "E_C-term", + "count": 1, + "pka": 3.304714285714286 + } + }, + "frag_base_pkas_calc": {}, + "frag_acid_pkas_calc": {}, + "frag_Qs_calc": {} + } + } +} diff --git a/peptide_tools_master/test/examples/payload_8_out.json.stdout b/peptide_tools_master/test/examples/payload_8_out.json.stdout new file mode 100644 index 0000000..a73472b --- /dev/null +++ b/peptide_tools_master/test/examples/payload_8_out.json.stdout @@ -0,0 +1,67 @@ +{ + "output_extn_coeff": { + "1": { + "fasta": "FPYVAE", + "e205": 28580, + "e214": 18018, + "e280": 1490, + "mol_name": "none" + } + }, + "output_pIChemiSt": { + "1": { + "mol_name": "none", + "pI": { + "IPC2_peptide": 3.5625, + "IPC_peptide": 3.375, + "ProMoST": 3.75, + "Gauci": 3.5, + "Grimsley": 3.25, + "Thurlkill": 3.25, + "Lehninger": 3.25, + "Toseland": 3.375, + "pI mean": 3.4140625, + "std": 0.47547262670946683, + "err": 0.16810495930742198 + }, + "QpH7": { + "IPC2_peptide": -1.016076155159717, + "IPC_peptide": -1.0013031485429318, + "ProMoST": -1.0013839252088195, + "Gauci": -1.0013848317274412, + "Grimsley": -1.0006267830230153, + "Thurlkill": -1.0029102007184603, + "Lehninger": -1.0017981477155729, + "Toseland": -1.0053525190408676, + "Q at pH7.4 mean": -1.0038544638921034, + "std": 0.013633185762927715, + "err": 0.004820059051071041 + }, + "pI_interval": [ + -1, + 3.7249999999999983 + ], + "pI_interval_threshold": 0.2, + "plot_filename": "temp_1.png", + "pKa_set": "IPC2_peptide", + "frag_base_pkas_fasta": {}, + "frag_acid_pkas_fasta": { + "1": { + "type": "acid", + "frag": "Y", + "count": 1, + "pka": 9.951571428571429 + }, + "2": { + "type": "acid", + "frag": "E", + "count": 1, + "pka": 4.358142857142857 + } + }, + "frag_base_pkas_calc": {}, + "frag_acid_pkas_calc": {}, + "frag_Qs_calc": {} + } + } +} diff --git a/peptide_tools_master/test/test_cli.py b/peptide_tools_master/test/test_cli.py index 31c2902..a6c321f 100644 --- a/peptide_tools_master/test/test_cli.py +++ b/peptide_tools_master/test/test_cli.py @@ -98,19 +98,7 @@ def test_fasta_file_input_1(): def test_smiles_stdin_input_3(): """Validity of console text output.""" smiles = "C[C@@H](C(=O)N[C@@H](CCC(=O)O)C(=O)O)NC(=O)[C@H](C(C)C)NC(=O)[C@H](Cc1ccc(cc1)O)NC(=O)[C@@H]2CCCN2C(=O)[C@H](Cc3ccccc3)NCCCCN" # noqa: E501 - test_args = cli_base_args + [ - "--input", - smiles, - "--print_fragment_pkas", - "--ionized_Cterm", - "--ionized_Nterm", - "-p", - 0, - "-l", - 0, - "-l", - 0, - ] + test_args = cli_base_args + ["--input", smiles, "--print_fragment_pkas"] subprocess_output = subprocess.run( stringify_list(test_args), capture_output=True, text=True ) @@ -217,6 +205,40 @@ def test_fasta_stdin_input_2(): assert result == expected +def test_fasta_stdin_input_3(): + """Validity of console JSON output for FASTA input.""" + test_args = cli_base_args + ["--input", "FPYVAE", "--print_fragment_pkas"] + subprocess_output = subprocess.run( + stringify_list(test_args), capture_output=True, text=True + ) + # print(" ".join(stringify_list(test_args))) + result = json.loads(subprocess_output.stdout) + with open(f"{examples_dir}/payload_7_out.json.stdout", "r") as file: + expected = json.load(file) + assert result == expected + + +def test_fasta_stdin_all_capped_input_3(): + """Validity of console JSON output for FASTA input.""" + test_args = cli_base_args + [ + "--input", + "FPYVAE", + "--print_fragment_pkas", + "--ionizable_nterm", + "false", + "--ionizable_cterm", + "false", + ] + subprocess_output = subprocess.run( + stringify_list(test_args), capture_output=True, text=True + ) + # print(" ".join(stringify_list(test_args))) + result = json.loads(subprocess_output.stdout) + with open(f"{examples_dir}/payload_8_out.json.stdout", "r") as file: + expected = json.load(file) + assert result == expected + + def test_empty_input(): test_args = cli_base_args + ["--input", " "] subprocess_output = subprocess.run(