diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 5ab5d197..6291f8ab 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.2.0 +current_version = 0.2.1 commit = True tag = False parse = (?P\d+)\.(?P\d+)\.(?P\d+)(\-(?P[a-z]+)(?P\d+))? @@ -15,6 +15,8 @@ serialize = [bumpversion:file:./settings.ini] +[bumpversion:file:./docs/conf.py] + [bumpversion:file:./release/one_click_linux_gui/control] [bumpversion:file:./release/one_click_linux_gui/create_installer_linux.sh] diff --git a/.github/workflows/pip_installation.yml b/.github/workflows/pip_installation.yml index 1d7a0ccd..7d938638 100644 --- a/.github/workflows/pip_installation.yml +++ b/.github/workflows/pip_installation.yml @@ -31,8 +31,9 @@ jobs: - name: Unittests shell: bash -l {0} run: | - cd tests - . ./run_tests.sh + conda activate alphabase + nbdev_test + conda deactivate loose_installation: name: Test loose pip installation on ${{ matrix.os }} runs-on: ${{ matrix.os }} @@ -56,5 +57,6 @@ jobs: - name: Unittests shell: bash -l {0} run: | - cd tests - . ./run_tests.sh + conda activate alphabase + nbdev_test + conda deactivate diff --git a/.gitignore b/.gitignore index 7211571e..c3eb9ef4 100644 --- a/.gitignore +++ b/.gitignore @@ -70,6 +70,7 @@ instance/ # Sphinx documentation docs/_build/ +docs/build/ # PyBuilder target/ @@ -138,7 +139,7 @@ alphabase/logs # nbdev2 *.gitattributes -*_docs* +_docs* # *_quarto.yml # *sidebar.yml *_proc* diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 00000000..e9674e62 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,27 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: docs/conf.py + +# Optionally build your docs in additional formats such as PDF +formats: all + +conda: + environment: misc/conda_dev_env.yaml + +# # Optionally set the version of Python and requirements required to build your docs +# python: +# version: 3.8 +# install: +# - requirements: requirements/requirements.txt +# - method: pip +# path: . +# extra_requirements: +# - plotting +# - development \ No newline at end of file diff --git a/README.md b/README.md index 439d8fc3..9879aada 100644 --- a/README.md +++ b/README.md @@ -36,19 +36,13 @@ please see [GitHub Pages](https://mannlabs.github.io/alphabase/) ## About -An open-source Python package of the AlphaPept ecosystem from the [Mann -Labs at the Max Planck Institute of -Biochemistry](https://www.biochem.mpg.de/mann) and the [University of -Copenhagen](https://www.cpr.ku.dk/research/proteomics/mann/). It -provides basic functionalities for AlphaPept ecosystem. +The infrastructure package of AlphaX ecosystem for MS proteomics. ------------------------------------------------------------------------ ## License -AlphaBase was developed by the [Mann Labs at the Max Planck Institute of -Biochemistry](https://www.biochem.mpg.de/mann) and the [University of -Copenhagen](https://www.cpr.ku.dk/research/proteomics/mann/) and is +AlphaBase was developed by the [Mann Labs at the Max Planck Institute of Biochemistry](https://www.biochem.mpg.de/mann) and the [University of Copenhagen](https://www.cpr.ku.dk/research/proteomics/mann/) and is freely available with an [Apache License](LICENSE.txt). External Python packages (available in the [requirements](requirements) folder) have their own licenses, which can be consulted on their respective websites. diff --git a/alphabase/__init__.py b/alphabase/__init__.py index 5c02d80b..312c40f0 100644 --- a/alphabase/__init__.py +++ b/alphabase/__init__.py @@ -2,7 +2,7 @@ __project__ = "alphabase" -__version__ = "0.2.0" +__version__ = "0.2.1" __license__ = "Apache" __description__ = "An open-source Python package of the AlphaPept ecosystem" __author__ = "Mann Labs" diff --git a/alphabase/_modidx.py b/alphabase/_modidx.py index c62ba678..51b773f8 100644 --- a/alphabase/_modidx.py +++ b/alphabase/_modidx.py @@ -1,482 +1,4 @@ -# Autogenerated by nbdev +# keep _modidx.py to enable nbdev_test -d = { 'settings': { 'branch': 'main', - 'doc_baseurl': '/alphabase', - 'doc_host': 'https://MannLabs.github.io', - 'git_url': 'https://github.com/MannLabs/alphabase', - 'lib_path': 'alphabase'}, - 'syms': { 'alphabase.cli': {}, - 'alphabase.constants.aa': { 'alphabase.constants.aa.calc_AA_masses_for_same_len_seqs': ( 'constants/aa.html#calc_aa_masses_for_same_len_seqs', - 'alphabase/constants/aa.py'), - 'alphabase.constants.aa.calc_AA_masses_for_var_len_seqs': ( 'constants/aa.html#calc_aa_masses_for_var_len_seqs', - 'alphabase/constants/aa.py'), - 'alphabase.constants.aa.calc_sequence_mass': ( 'constants/aa.html#calc_sequence_mass', - 'alphabase/constants/aa.py'), - 'alphabase.constants.aa.calc_sequence_masses_for_same_len_seqs': ( 'constants/aa.html#calc_sequence_masses_for_same_len_seqs', - 'alphabase/constants/aa.py'), - 'alphabase.constants.aa.reset_AA_df': ( 'constants/aa.html#reset_aa_df', - 'alphabase/constants/aa.py'), - 'alphabase.constants.aa.reset_AA_mass': ( 'constants/aa.html#reset_aa_mass', - 'alphabase/constants/aa.py')}, - 'alphabase.constants.atom': {}, - 'alphabase.constants.element': { 'alphabase.constants.element.calc_mass_from_formula': ( 'constants/element.html#calc_mass_from_formula', - 'alphabase/constants/element.py'), - 'alphabase.constants.element.load_elem_yaml': ( 'constants/element.html#load_elem_yaml', - 'alphabase/constants/element.py'), - 'alphabase.constants.element.parse_formula': ( 'constants/element.html#parse_formula', - 'alphabase/constants/element.py'), - 'alphabase.constants.element.reset_elements': ( 'constants/element.html#reset_elements', - 'alphabase/constants/element.py'), - 'alphabase.constants.element.truncate_isotope': ( 'constants/element.html#truncate_isotope', - 'alphabase/constants/element.py')}, - 'alphabase.constants.isotope': { 'alphabase.constants.isotope.IsotopeDistribution': ( 'constants/isotope.html#isotopedistribution', - 'alphabase/constants/isotope.py'), - 'alphabase.constants.isotope.IsotopeDistribution.__init__': ( 'constants/isotope.html#isotopedistribution.__init__', - 'alphabase/constants/isotope.py'), - 'alphabase.constants.isotope.IsotopeDistribution.calc_formula_distribution': ( 'constants/isotope.html#isotopedistribution.calc_formula_distribution', - 'alphabase/constants/isotope.py'), - 'alphabase.constants.isotope._calc_one_elem_cum_dist': ( 'constants/isotope.html#_calc_one_elem_cum_dist', - 'alphabase/constants/isotope.py'), - 'alphabase.constants.isotope.abundance_convolution': ( 'constants/isotope.html#abundance_convolution', - 'alphabase/constants/isotope.py'), - 'alphabase.constants.isotope.formula_dist': ( 'constants/isotope.html#formula_dist', - 'alphabase/constants/isotope.py'), - 'alphabase.constants.isotope.one_element_dist': ( 'constants/isotope.html#one_element_dist', - 'alphabase/constants/isotope.py')}, - 'alphabase.constants.modification': { 'alphabase.constants.modification._calc_modloss': ( 'constants/modification.html#_calc_modloss', - 'alphabase/constants/modification.py'), - 'alphabase.constants.modification._calc_modloss_with_importance': ( 'constants/modification.html#_calc_modloss_with_importance', - 'alphabase/constants/modification.py'), - 'alphabase.constants.modification.add_modifications_for_lower_case_AA': ( 'constants/modification.html#add_modifications_for_lower_case_aa', - 'alphabase/constants/modification.py'), - 'alphabase.constants.modification.add_new_modifications': ( 'constants/modification.html#add_new_modifications', - 'alphabase/constants/modification.py'), - 'alphabase.constants.modification.calc_mod_masses_for_same_len_seqs': ( 'constants/modification.html#calc_mod_masses_for_same_len_seqs', - 'alphabase/constants/modification.py'), - 'alphabase.constants.modification.calc_modification_mass': ( 'constants/modification.html#calc_modification_mass', - 'alphabase/constants/modification.py'), - 'alphabase.constants.modification.calc_modification_mass_sum': ( 'constants/modification.html#calc_modification_mass_sum', - 'alphabase/constants/modification.py'), - 'alphabase.constants.modification.calc_modloss_mass': ( 'constants/modification.html#calc_modloss_mass', - 'alphabase/constants/modification.py'), - 'alphabase.constants.modification.calc_modloss_mass_with_importance': ( 'constants/modification.html#calc_modloss_mass_with_importance', - 'alphabase/constants/modification.py'), - 'alphabase.constants.modification.keep_modloss_by_importance': ( 'constants/modification.html#keep_modloss_by_importance', - 'alphabase/constants/modification.py'), - 'alphabase.constants.modification.load_mod_df': ( 'constants/modification.html#load_mod_df', - 'alphabase/constants/modification.py'), - 'alphabase.constants.modification.update_all_by_MOD_DF': ( 'constants/modification.html#update_all_by_mod_df', - 'alphabase/constants/modification.py')}, - 'alphabase.gui': {}, - 'alphabase.io.hdf': {}, - 'alphabase.io.psm_reader.alphapept_reader': {}, - 'alphabase.io.psm_reader.dia_psm_reader': {}, - 'alphabase.io.psm_reader.dia_search_reader': {}, - 'alphabase.io.psm_reader.maxquant_reader': {}, - 'alphabase.io.psm_reader.msfragger_reader': {}, - 'alphabase.io.psm_reader.pfind_reader': {}, - 'alphabase.io.psm_reader.psm_reader': {}, - 'alphabase.io.tempmmap': {}, - 'alphabase.peptide.fragment': { 'alphabase.peptide.fragment.calc_fragment_mz_values_for_same_nAA': ( 'peptide/fragment.html#calc_fragment_mz_values_for_same_naa', - 'alphabase/peptide/fragment.py'), - 'alphabase.peptide.fragment.concat_precursor_fragment_dataframes': ( 'peptide/fragment.html#concat_precursor_fragment_dataframes', - 'alphabase/peptide/fragment.py'), - 'alphabase.peptide.fragment.create_fragment_mz_dataframe': ( 'peptide/fragment.html#create_fragment_mz_dataframe', - 'alphabase/peptide/fragment.py'), - 'alphabase.peptide.fragment.create_fragment_mz_dataframe_by_sort_precursor': ( 'peptide/fragment.html#create_fragment_mz_dataframe_by_sort_precursor', - 'alphabase/peptide/fragment.py'), - 'alphabase.peptide.fragment.get_charged_frag_types': ( 'peptide/fragment.html#get_charged_frag_types', - 'alphabase/peptide/fragment.py'), - 'alphabase.peptide.fragment.get_sliced_fragment_dataframe': ( 'peptide/fragment.html#get_sliced_fragment_dataframe', - 'alphabase/peptide/fragment.py'), - 'alphabase.peptide.fragment.init_fragment_by_precursor_dataframe': ( 'peptide/fragment.html#init_fragment_by_precursor_dataframe', - 'alphabase/peptide/fragment.py'), - 'alphabase.peptide.fragment.init_fragment_dataframe_from_other': ( 'peptide/fragment.html#init_fragment_dataframe_from_other', - 'alphabase/peptide/fragment.py'), - 'alphabase.peptide.fragment.init_zero_fragment_dataframe': ( 'peptide/fragment.html#init_zero_fragment_dataframe', - 'alphabase/peptide/fragment.py'), - 'alphabase.peptide.fragment.mask_fragments_for_charge_greater_than_precursor_charge': ( 'peptide/fragment.html#mask_fragments_for_charge_greater_than_precursor_charge', - 'alphabase/peptide/fragment.py'), - 'alphabase.peptide.fragment.parse_charged_frag_type': ( 'peptide/fragment.html#parse_charged_frag_type', - 'alphabase/peptide/fragment.py'), - 'alphabase.peptide.fragment.update_sliced_fragment_dataframe': ( 'peptide/fragment.html#update_sliced_fragment_dataframe', - 'alphabase/peptide/fragment.py')}, - 'alphabase.peptide.mass_calc': { 'alphabase.peptide.mass_calc.calc_b_y_and_peptide_mass': ( 'peptide/mass_calc.html#calc_b_y_and_peptide_mass', - 'alphabase/peptide/mass_calc.py'), - 'alphabase.peptide.mass_calc.calc_b_y_and_peptide_masses_for_same_len_seqs': ( 'peptide/mass_calc.html#calc_b_y_and_peptide_masses_for_same_len_seqs', - 'alphabase/peptide/mass_calc.py'), - 'alphabase.peptide.mass_calc.calc_delta_modification_mass': ( 'peptide/mass_calc.html#calc_delta_modification_mass', - 'alphabase/peptide/mass_calc.py'), - 'alphabase.peptide.mass_calc.calc_mod_delta_masses_for_same_len_seqs': ( 'peptide/mass_calc.html#calc_mod_delta_masses_for_same_len_seqs', - 'alphabase/peptide/mass_calc.py'), - 'alphabase.peptide.mass_calc.calc_peptide_masses_for_same_len_seqs': ( 'peptide/mass_calc.html#calc_peptide_masses_for_same_len_seqs', - 'alphabase/peptide/mass_calc.py')}, - 'alphabase.peptide.mobility': { 'alphabase.peptide.mobility.ccs_to_mobility_bruker': ( 'peptide/mobility.html#ccs_to_mobility_bruker', - 'alphabase/peptide/mobility.py'), - 'alphabase.peptide.mobility.ccs_to_mobility_for_df': ( 'peptide/mobility.html#ccs_to_mobility_for_df', - 'alphabase/peptide/mobility.py'), - 'alphabase.peptide.mobility.get_reduced_mass': ( 'peptide/mobility.html#get_reduced_mass', - 'alphabase/peptide/mobility.py'), - 'alphabase.peptide.mobility.mobility_to_ccs_bruker': ( 'peptide/mobility.html#mobility_to_ccs_bruker', - 'alphabase/peptide/mobility.py'), - 'alphabase.peptide.mobility.mobility_to_ccs_for_df': ( 'peptide/mobility.html#mobility_to_ccs_for_df', - 'alphabase/peptide/mobility.py')}, - 'alphabase.peptide.precursor': { 'alphabase.peptide.precursor._batchify_df': ( 'peptide/precursor.html#_batchify_df', - 'alphabase/peptide/precursor.py'), - 'alphabase.peptide.precursor._count_batchify_df': ( 'peptide/precursor.html#_count_batchify_df', - 'alphabase/peptide/precursor.py'), - 'alphabase.peptide.precursor.calc_precursor_isotope': ( 'peptide/precursor.html#calc_precursor_isotope', - 'alphabase/peptide/precursor.py'), - 'alphabase.peptide.precursor.calc_precursor_isotope_mp': ( 'peptide/precursor.html#calc_precursor_isotope_mp', - 'alphabase/peptide/precursor.py'), - 'alphabase.peptide.precursor.get_mod_seq_charge_hash': ( 'peptide/precursor.html#get_mod_seq_charge_hash', - 'alphabase/peptide/precursor.py'), - 'alphabase.peptide.precursor.get_mod_seq_formula': ( 'peptide/precursor.html#get_mod_seq_formula', - 'alphabase/peptide/precursor.py'), - 'alphabase.peptide.precursor.get_mod_seq_hash': ( 'peptide/precursor.html#get_mod_seq_hash', - 'alphabase/peptide/precursor.py'), - 'alphabase.peptide.precursor.get_mod_seq_isotope_distribution': ( 'peptide/precursor.html#get_mod_seq_isotope_distribution', - 'alphabase/peptide/precursor.py'), - 'alphabase.peptide.precursor.get_right_most_isotope_index': ( 'peptide/precursor.html#get_right_most_isotope_index', - 'alphabase/peptide/precursor.py'), - 'alphabase.peptide.precursor.hash_mod_seq_charge_df': ( 'peptide/precursor.html#hash_mod_seq_charge_df', - 'alphabase/peptide/precursor.py'), - 'alphabase.peptide.precursor.hash_mod_seq_df': ( 'peptide/precursor.html#hash_mod_seq_df', - 'alphabase/peptide/precursor.py'), - 'alphabase.peptide.precursor.hash_precursor_df': ( 'peptide/precursor.html#hash_precursor_df', - 'alphabase/peptide/precursor.py'), - 'alphabase.peptide.precursor.is_precursor_refined': ( 'peptide/precursor.html#is_precursor_refined', - 'alphabase/peptide/precursor.py'), - 'alphabase.peptide.precursor.refine_precursor_df': ( 'peptide/precursor.html#refine_precursor_df', - 'alphabase/peptide/precursor.py'), - 'alphabase.peptide.precursor.update_precursor_mz': ( 'peptide/precursor.html#update_precursor_mz', - 'alphabase/peptide/precursor.py')}, - 'alphabase.protein.fasta': { 'alphabase.protein.fasta.Digest': ('protein/fasta.html#digest', 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.Digest.__init__': ( 'protein/fasta.html#digest.__init__', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.Digest.cleave_sequence': ( 'protein/fasta.html#digest.cleave_sequence', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.FastaLib': ('protein/fasta.html#fastalib', 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.FastaLib.__init__': ( 'protein/fasta.html#fastalib.__init__', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.FastaLib._check_if_multi_mods_on_aa': ( 'protein/fasta.html#fastalib._check_if_multi_mods_on_aa', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.FastaLib._cleave_to_peptides': ( 'protein/fasta.html#fastalib._cleave_to_peptides', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.FastaLib._process_after_load_pep_seqs': ( 'protein/fasta.html#fastalib._process_after_load_pep_seqs', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.FastaLib.add_additional_modifications': ( 'protein/fasta.html#fastalib.add_additional_modifications', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.FastaLib.add_charge': ( 'protein/fasta.html#fastalib.add_charge', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.FastaLib.add_modifications': ( 'protein/fasta.html#fastalib.add_modifications', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.FastaLib.add_mods_for_one_seq': ( 'protein/fasta.html#fastalib.add_mods_for_one_seq', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.FastaLib.add_peptide_labeling': ( 'protein/fasta.html#fastalib.add_peptide_labeling', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.FastaLib.append_protein_name': ( 'protein/fasta.html#fastalib.append_protein_name', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.FastaLib.get_peptides_from_fasta': ( 'protein/fasta.html#fastalib.get_peptides_from_fasta', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.FastaLib.get_peptides_from_fasta_list': ( 'protein/fasta.html#fastalib.get_peptides_from_fasta_list', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.FastaLib.get_peptides_from_peptide_sequence_list': ( 'protein/fasta.html#fastalib.get_peptides_from_peptide_sequence_list', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.FastaLib.get_peptides_from_protein_dict': ( 'protein/fasta.html#fastalib.get_peptides_from_protein_dict', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.FastaLib.import_and_process_fasta': ( 'protein/fasta.html#fastalib.import_and_process_fasta', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.FastaLib.import_and_process_peptide_sequences': ( 'protein/fasta.html#fastalib.import_and_process_peptide_sequences', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.FastaLib.import_and_process_protein_dict': ( 'protein/fasta.html#fastalib.import_and_process_protein_dict', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.FastaLib.load_hdf': ( 'protein/fasta.html#fastalib.load_hdf', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.FastaLib.save_hdf': ( 'protein/fasta.html#fastalib.save_hdf', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.add_single_peptide_labeling': ( 'protein/fasta.html#add_single_peptide_labeling', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.append_regular_modifications': ( 'protein/fasta.html#append_regular_modifications', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.cleave_sequence_with_cut_pos': ( 'protein/fasta.html#cleave_sequence_with_cut_pos', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.concat_proteins': ( 'protein/fasta.html#concat_proteins', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.create_labeling_peptide_df': ( 'protein/fasta.html#create_labeling_peptide_df', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.get_candidate_sites': ( 'protein/fasta.html#get_candidate_sites', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.get_fix_mods': ( 'protein/fasta.html#get_fix_mods', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.get_uniprot_gene_name': ( 'protein/fasta.html#get_uniprot_gene_name', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.get_var_mod_sites': ( 'protein/fasta.html#get_var_mod_sites', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.get_var_mods': ( 'protein/fasta.html#get_var_mods', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.get_var_mods_per_sites_multi_mods_on_aa': ( 'protein/fasta.html#get_var_mods_per_sites_multi_mods_on_aa', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.get_var_mods_per_sites_single_mod_on_aa': ( 'protein/fasta.html#get_var_mods_per_sites_single_mod_on_aa', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.load_all_proteins': ( 'protein/fasta.html#load_all_proteins', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.parse_labels': ( 'protein/fasta.html#parse_labels', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.parse_term_mod': ( 'protein/fasta.html#parse_term_mod', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.protein_idxes_to_names': ( 'protein/fasta.html#protein_idxes_to_names', - 'alphabase/protein/fasta.py'), - 'alphabase.protein.fasta.read_fasta_file': ( 'protein/fasta.html#read_fasta_file', - 'alphabase/protein/fasta.py')}, - 'alphabase.protein.inference': {}, - 'alphabase.protein.lcp_digest': {}, - 'alphabase.psm_reader.alphapept_reader': { 'alphabase.psm_reader.alphapept_reader.AlphaPeptReader': ( 'psm_reader/alphapept_reader.html#alphapeptreader', - 'alphabase/psm_reader/alphapept_reader.py'), - 'alphabase.psm_reader.alphapept_reader.AlphaPeptReader.__init__': ( 'psm_reader/alphapept_reader.html#alphapeptreader.__init__', - 'alphabase/psm_reader/alphapept_reader.py'), - 'alphabase.psm_reader.alphapept_reader.AlphaPeptReader._init_column_mapping': ( 'psm_reader/alphapept_reader.html#alphapeptreader._init_column_mapping', - 'alphabase/psm_reader/alphapept_reader.py'), - 'alphabase.psm_reader.alphapept_reader.AlphaPeptReader._init_modification_mapping': ( 'psm_reader/alphapept_reader.html#alphapeptreader._init_modification_mapping', - 'alphabase/psm_reader/alphapept_reader.py'), - 'alphabase.psm_reader.alphapept_reader.AlphaPeptReader._load_file': ( 'psm_reader/alphapept_reader.html#alphapeptreader._load_file', - 'alphabase/psm_reader/alphapept_reader.py'), - 'alphabase.psm_reader.alphapept_reader.AlphaPeptReader._load_modifications': ( 'psm_reader/alphapept_reader.html#alphapeptreader._load_modifications', - 'alphabase/psm_reader/alphapept_reader.py'), - 'alphabase.psm_reader.alphapept_reader.get_x_tandem_score': ( 'psm_reader/alphapept_reader.html#get_x_tandem_score', - 'alphabase/psm_reader/alphapept_reader.py'), - 'alphabase.psm_reader.alphapept_reader.parse_ap': ( 'psm_reader/alphapept_reader.html#parse_ap', - 'alphabase/psm_reader/alphapept_reader.py')}, - 'alphabase.psm_reader.dia_psm_reader': { 'alphabase.psm_reader.dia_psm_reader.DiannReader': ( 'psm_reader/dia_psm_reader.html#diannreader', - 'alphabase/psm_reader/dia_psm_reader.py'), - 'alphabase.psm_reader.dia_psm_reader.DiannReader.__init__': ( 'psm_reader/dia_psm_reader.html#diannreader.__init__', - 'alphabase/psm_reader/dia_psm_reader.py'), - 'alphabase.psm_reader.dia_psm_reader.DiannReader._init_column_mapping': ( 'psm_reader/dia_psm_reader.html#diannreader._init_column_mapping', - 'alphabase/psm_reader/dia_psm_reader.py'), - 'alphabase.psm_reader.dia_psm_reader.DiannReader._load_file': ( 'psm_reader/dia_psm_reader.html#diannreader._load_file', - 'alphabase/psm_reader/dia_psm_reader.py'), - 'alphabase.psm_reader.dia_psm_reader.SpectronautReader': ( 'psm_reader/dia_psm_reader.html#spectronautreader', - 'alphabase/psm_reader/dia_psm_reader.py'), - 'alphabase.psm_reader.dia_psm_reader.SpectronautReader.__init__': ( 'psm_reader/dia_psm_reader.html#spectronautreader.__init__', - 'alphabase/psm_reader/dia_psm_reader.py'), - 'alphabase.psm_reader.dia_psm_reader.SpectronautReader._init_column_mapping': ( 'psm_reader/dia_psm_reader.html#spectronautreader._init_column_mapping', - 'alphabase/psm_reader/dia_psm_reader.py'), - 'alphabase.psm_reader.dia_psm_reader.SpectronautReader._load_file': ( 'psm_reader/dia_psm_reader.html#spectronautreader._load_file', - 'alphabase/psm_reader/dia_psm_reader.py'), - 'alphabase.psm_reader.dia_psm_reader.SpectronautReportReader': ( 'psm_reader/dia_psm_reader.html#spectronautreportreader', - 'alphabase/psm_reader/dia_psm_reader.py'), - 'alphabase.psm_reader.dia_psm_reader.SpectronautReportReader.__init__': ( 'psm_reader/dia_psm_reader.html#spectronautreportreader.__init__', - 'alphabase/psm_reader/dia_psm_reader.py'), - 'alphabase.psm_reader.dia_psm_reader.SpectronautReportReader._init_column_mapping': ( 'psm_reader/dia_psm_reader.html#spectronautreportreader._init_column_mapping', - 'alphabase/psm_reader/dia_psm_reader.py'), - 'alphabase.psm_reader.dia_psm_reader.SpectronautReportReader._load_file': ( 'psm_reader/dia_psm_reader.html#spectronautreportreader._load_file', - 'alphabase/psm_reader/dia_psm_reader.py'), - 'alphabase.psm_reader.dia_psm_reader.SwathReader': ( 'psm_reader/dia_psm_reader.html#swathreader', - 'alphabase/psm_reader/dia_psm_reader.py'), - 'alphabase.psm_reader.dia_psm_reader.SwathReader.__init__': ( 'psm_reader/dia_psm_reader.html#swathreader.__init__', - 'alphabase/psm_reader/dia_psm_reader.py')}, - 'alphabase.psm_reader.maxquant_reader': { 'alphabase.psm_reader.maxquant_reader.MaxQuantReader': ( 'psm_reader/maxquant_reader.html#maxquantreader', - 'alphabase/psm_reader/maxquant_reader.py'), - 'alphabase.psm_reader.maxquant_reader.MaxQuantReader.__init__': ( 'psm_reader/maxquant_reader.html#maxquantreader.__init__', - 'alphabase/psm_reader/maxquant_reader.py'), - 'alphabase.psm_reader.maxquant_reader.MaxQuantReader._extend_mod_brackets': ( 'psm_reader/maxquant_reader.html#maxquantreader._extend_mod_brackets', - 'alphabase/psm_reader/maxquant_reader.py'), - 'alphabase.psm_reader.maxquant_reader.MaxQuantReader._find_mod_seq_column': ( 'psm_reader/maxquant_reader.html#maxquantreader._find_mod_seq_column', - 'alphabase/psm_reader/maxquant_reader.py'), - 'alphabase.psm_reader.maxquant_reader.MaxQuantReader._init_column_mapping': ( 'psm_reader/maxquant_reader.html#maxquantreader._init_column_mapping', - 'alphabase/psm_reader/maxquant_reader.py'), - 'alphabase.psm_reader.maxquant_reader.MaxQuantReader._init_modification_mapping': ( 'psm_reader/maxquant_reader.html#maxquantreader._init_modification_mapping', - 'alphabase/psm_reader/maxquant_reader.py'), - 'alphabase.psm_reader.maxquant_reader.MaxQuantReader._load_file': ( 'psm_reader/maxquant_reader.html#maxquantreader._load_file', - 'alphabase/psm_reader/maxquant_reader.py'), - 'alphabase.psm_reader.maxquant_reader.MaxQuantReader._load_modifications': ( 'psm_reader/maxquant_reader.html#maxquantreader._load_modifications', - 'alphabase/psm_reader/maxquant_reader.py'), - 'alphabase.psm_reader.maxquant_reader.MaxQuantReader._translate_decoy': ( 'psm_reader/maxquant_reader.html#maxquantreader._translate_decoy', - 'alphabase/psm_reader/maxquant_reader.py'), - 'alphabase.psm_reader.maxquant_reader.MaxQuantReader.set_modification_mapping': ( 'psm_reader/maxquant_reader.html#maxquantreader.set_modification_mapping', - 'alphabase/psm_reader/maxquant_reader.py'), - 'alphabase.psm_reader.maxquant_reader.parse_mod_seq': ( 'psm_reader/maxquant_reader.html#parse_mod_seq', - 'alphabase/psm_reader/maxquant_reader.py')}, - 'alphabase.psm_reader.msfragger_reader': { 'alphabase.psm_reader.msfragger_reader.MSFragger_PSM_TSV_Reader': ( 'psm_reader/msfragger_reader.html#msfragger_psm_tsv_reader', - 'alphabase/psm_reader/msfragger_reader.py'), - 'alphabase.psm_reader.msfragger_reader.MSFragger_PSM_TSV_Reader.__init__': ( 'psm_reader/msfragger_reader.html#msfragger_psm_tsv_reader.__init__', - 'alphabase/psm_reader/msfragger_reader.py'), - 'alphabase.psm_reader.msfragger_reader._get_msf_mods': ( 'psm_reader/msfragger_reader.html#_get_msf_mods', - 'alphabase/psm_reader/msfragger_reader.py'), - 'alphabase.psm_reader.msfragger_reader._is_fragger_decoy': ( 'psm_reader/msfragger_reader.html#_is_fragger_decoy', - 'alphabase/psm_reader/msfragger_reader.py')}, - 'alphabase.psm_reader.pfind_reader': { 'alphabase.psm_reader.pfind_reader.convert_one_pFind_mod': ( 'psm_reader/pfind_reader.html#convert_one_pfind_mod', - 'alphabase/psm_reader/pfind_reader.py'), - 'alphabase.psm_reader.pfind_reader.get_pFind_mods': ( 'psm_reader/pfind_reader.html#get_pfind_mods', - 'alphabase/psm_reader/pfind_reader.py'), - 'alphabase.psm_reader.pfind_reader.pFindReader': ( 'psm_reader/pfind_reader.html#pfindreader', - 'alphabase/psm_reader/pfind_reader.py'), - 'alphabase.psm_reader.pfind_reader.pFindReader.__init__': ( 'psm_reader/pfind_reader.html#pfindreader.__init__', - 'alphabase/psm_reader/pfind_reader.py'), - 'alphabase.psm_reader.pfind_reader.pFindReader._init_column_mapping': ( 'psm_reader/pfind_reader.html#pfindreader._init_column_mapping', - 'alphabase/psm_reader/pfind_reader.py'), - 'alphabase.psm_reader.pfind_reader.pFindReader._init_modification_mapping': ( 'psm_reader/pfind_reader.html#pfindreader._init_modification_mapping', - 'alphabase/psm_reader/pfind_reader.py'), - 'alphabase.psm_reader.pfind_reader.pFindReader._load_file': ( 'psm_reader/pfind_reader.html#pfindreader._load_file', - 'alphabase/psm_reader/pfind_reader.py'), - 'alphabase.psm_reader.pfind_reader.pFindReader._load_modifications': ( 'psm_reader/pfind_reader.html#pfindreader._load_modifications', - 'alphabase/psm_reader/pfind_reader.py'), - 'alphabase.psm_reader.pfind_reader.pFindReader._translate_decoy': ( 'psm_reader/pfind_reader.html#pfindreader._translate_decoy', - 'alphabase/psm_reader/pfind_reader.py'), - 'alphabase.psm_reader.pfind_reader.pFindReader._translate_modifications': ( 'psm_reader/pfind_reader.html#pfindreader._translate_modifications', - 'alphabase/psm_reader/pfind_reader.py'), - 'alphabase.psm_reader.pfind_reader.pFindReader._translate_score': ( 'psm_reader/pfind_reader.html#pfindreader._translate_score', - 'alphabase/psm_reader/pfind_reader.py'), - 'alphabase.psm_reader.pfind_reader.parse_pfind_protein': ( 'psm_reader/pfind_reader.html#parse_pfind_protein', - 'alphabase/psm_reader/pfind_reader.py'), - 'alphabase.psm_reader.pfind_reader.translate_pFind_mod': ( 'psm_reader/pfind_reader.html#translate_pfind_mod', - 'alphabase/psm_reader/pfind_reader.py')}, - 'alphabase.psm_reader.psm_reader': { 'alphabase.psm_reader.psm_reader.PSMReaderBase': ( 'psm_reader/psm_reader.html#psmreaderbase', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderBase.__init__': ( 'psm_reader/psm_reader.html#psmreaderbase.__init__', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderBase._init_column_mapping': ( 'psm_reader/psm_reader.html#psmreaderbase._init_column_mapping', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderBase._init_modification_mapping': ( 'psm_reader/psm_reader.html#psmreaderbase._init_modification_mapping', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderBase._load_file': ( 'psm_reader/psm_reader.html#psmreaderbase._load_file', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderBase._load_modifications': ( 'psm_reader/psm_reader.html#psmreaderbase._load_modifications', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderBase._post_process': ( 'psm_reader/psm_reader.html#psmreaderbase._post_process', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderBase._reverse_mod_mapping': ( 'psm_reader/psm_reader.html#psmreaderbase._reverse_mod_mapping', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderBase._translate_columns': ( 'psm_reader/psm_reader.html#psmreaderbase._translate_columns', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderBase._translate_decoy': ( 'psm_reader/psm_reader.html#psmreaderbase._translate_decoy', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderBase._translate_modifications': ( 'psm_reader/psm_reader.html#psmreaderbase._translate_modifications', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderBase._translate_score': ( 'psm_reader/psm_reader.html#psmreaderbase._translate_score', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderBase.add_modification_mapping': ( 'psm_reader/psm_reader.html#psmreaderbase.add_modification_mapping', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderBase.filter_psm_by_modifications': ( 'psm_reader/psm_reader.html#psmreaderbase.filter_psm_by_modifications', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderBase.import_file': ( 'psm_reader/psm_reader.html#psmreaderbase.import_file', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderBase.load': ( 'psm_reader/psm_reader.html#psmreaderbase.load', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderBase.norm_rt': ( 'psm_reader/psm_reader.html#psmreaderbase.norm_rt', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderBase.normalize_rt': ( 'psm_reader/psm_reader.html#psmreaderbase.normalize_rt', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderBase.normalize_rt_by_raw_name': ( 'psm_reader/psm_reader.html#psmreaderbase.normalize_rt_by_raw_name', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderBase.psm_df': ( 'psm_reader/psm_reader.html#psmreaderbase.psm_df', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderBase.set_modification_mapping': ( 'psm_reader/psm_reader.html#psmreaderbase.set_modification_mapping', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderProvider': ( 'psm_reader/psm_reader.html#psmreaderprovider', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderProvider.__init__': ( 'psm_reader/psm_reader.html#psmreaderprovider.__init__', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderProvider.get_reader': ( 'psm_reader/psm_reader.html#psmreaderprovider.get_reader', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderProvider.get_reader_by_yaml': ( 'psm_reader/psm_reader.html#psmreaderprovider.get_reader_by_yaml', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.PSMReaderProvider.register_reader': ( 'psm_reader/psm_reader.html#psmreaderprovider.register_reader', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.keep_modifications': ( 'psm_reader/psm_reader.html#keep_modifications', - 'alphabase/psm_reader/psm_reader.py'), - 'alphabase.psm_reader.psm_reader.translate_other_modification': ( 'psm_reader/psm_reader.html#translate_other_modification', - 'alphabase/psm_reader/psm_reader.py')}, - 'alphabase.spectral_library.decoy_library': { 'alphabase.spectral_library.decoy_library.DecoyLib': ( 'spectral_library/decoy_library.html#decoylib', - 'alphabase/spectral_library/decoy_library.py'), - 'alphabase.spectral_library.decoy_library.DecoyLib.__init__': ( 'spectral_library/decoy_library.html#decoylib.__init__', - 'alphabase/spectral_library/decoy_library.py'), - 'alphabase.spectral_library.decoy_library.DecoyLib._decoy_fragment_intensity': ( 'spectral_library/decoy_library.html#decoylib._decoy_fragment_intensity', - 'alphabase/spectral_library/decoy_library.py'), - 'alphabase.spectral_library.decoy_library.DecoyLib._decoy_fragment_mz': ( 'spectral_library/decoy_library.html#decoylib._decoy_fragment_mz', - 'alphabase/spectral_library/decoy_library.py'), - 'alphabase.spectral_library.decoy_library.DecoyLib._decoy_frags': ( 'spectral_library/decoy_library.html#decoylib._decoy_frags', - 'alphabase/spectral_library/decoy_library.py'), - 'alphabase.spectral_library.decoy_library.DecoyLib._decoy_meta': ( 'spectral_library/decoy_library.html#decoylib._decoy_meta', - 'alphabase/spectral_library/decoy_library.py'), - 'alphabase.spectral_library.decoy_library.DecoyLib._decoy_mods': ( 'spectral_library/decoy_library.html#decoylib._decoy_mods', - 'alphabase/spectral_library/decoy_library.py'), - 'alphabase.spectral_library.decoy_library.DecoyLib._decoy_seq': ( 'spectral_library/decoy_library.html#decoylib._decoy_seq', - 'alphabase/spectral_library/decoy_library.py'), - 'alphabase.spectral_library.decoy_library.DecoyLib._get_hdf_to_load': ( 'spectral_library/decoy_library.html#decoylib._get_hdf_to_load', - 'alphabase/spectral_library/decoy_library.py'), - 'alphabase.spectral_library.decoy_library.DecoyLib._get_hdf_to_save': ( 'spectral_library/decoy_library.html#decoylib._get_hdf_to_save', - 'alphabase/spectral_library/decoy_library.py'), - 'alphabase.spectral_library.decoy_library.DecoyLib._remove_target_seqs': ( 'spectral_library/decoy_library.html#decoylib._remove_target_seqs', - 'alphabase/spectral_library/decoy_library.py'), - 'alphabase.spectral_library.decoy_library.DecoyLib.append_decoy_sequence': ( 'spectral_library/decoy_library.html#decoylib.append_decoy_sequence', - 'alphabase/spectral_library/decoy_library.py'), - 'alphabase.spectral_library.decoy_library.DecoyLib.decoy_sequence': ( 'spectral_library/decoy_library.html#decoylib.decoy_sequence', - 'alphabase/spectral_library/decoy_library.py'), - 'alphabase.spectral_library.decoy_library.DecoyLib.load_hdf': ( 'spectral_library/decoy_library.html#decoylib.load_hdf', - 'alphabase/spectral_library/decoy_library.py'), - 'alphabase.spectral_library.decoy_library.DecoyLib.save_hdf': ( 'spectral_library/decoy_library.html#decoylib.save_hdf', - 'alphabase/spectral_library/decoy_library.py'), - 'alphabase.spectral_library.decoy_library.DecoyLib.translate_to_decoy': ( 'spectral_library/decoy_library.html#decoylib.translate_to_decoy', - 'alphabase/spectral_library/decoy_library.py'), - 'alphabase.spectral_library.decoy_library.DecoyLibProvider': ( 'spectral_library/decoy_library.html#decoylibprovider', - 'alphabase/spectral_library/decoy_library.py'), - 'alphabase.spectral_library.decoy_library.DecoyLibProvider.__init__': ( 'spectral_library/decoy_library.html#decoylibprovider.__init__', - 'alphabase/spectral_library/decoy_library.py'), - 'alphabase.spectral_library.decoy_library.DecoyLibProvider.get_decoy_lib': ( 'spectral_library/decoy_library.html#decoylibprovider.get_decoy_lib', - 'alphabase/spectral_library/decoy_library.py'), - 'alphabase.spectral_library.decoy_library.DecoyLibProvider.register': ( 'spectral_library/decoy_library.html#decoylibprovider.register', - 'alphabase/spectral_library/decoy_library.py'), - 'alphabase.spectral_library.decoy_library.DiaNNDecoyLib': ( 'spectral_library/decoy_library.html#dianndecoylib', - 'alphabase/spectral_library/decoy_library.py'), - 'alphabase.spectral_library.decoy_library.DiaNNDecoyLib.__init__': ( 'spectral_library/decoy_library.html#dianndecoylib.__init__', - 'alphabase/spectral_library/decoy_library.py'), - 'alphabase.spectral_library.decoy_library.DiaNNDecoyLib._decoy_seq': ( 'spectral_library/decoy_library.html#dianndecoylib._decoy_seq', - 'alphabase/spectral_library/decoy_library.py')}, - 'alphabase.spectral_library.library_base': { 'alphabase.spectral_library.library_base.SpecLibBase': ( 'spectral_library/library_base.html#speclibbase', - 'alphabase/spectral_library/library_base.py'), - 'alphabase.spectral_library.library_base.SpecLibBase.__init__': ( 'spectral_library/library_base.html#speclibbase.__init__', - 'alphabase/spectral_library/library_base.py'), - 'alphabase.spectral_library.library_base.SpecLibBase._get_hdf_to_load': ( 'spectral_library/library_base.html#speclibbase._get_hdf_to_load', - 'alphabase/spectral_library/library_base.py'), - 'alphabase.spectral_library.library_base.SpecLibBase._get_hdf_to_save': ( 'spectral_library/library_base.html#speclibbase._get_hdf_to_save', - 'alphabase/spectral_library/library_base.py'), - 'alphabase.spectral_library.library_base.SpecLibBase.append_decoy_sequence': ( 'spectral_library/library_base.html#speclibbase.append_decoy_sequence', - 'alphabase/spectral_library/library_base.py'), - 'alphabase.spectral_library.library_base.SpecLibBase.calc_fragment_mz_df': ( 'spectral_library/library_base.html#speclibbase.calc_fragment_mz_df', - 'alphabase/spectral_library/library_base.py'), - 'alphabase.spectral_library.library_base.SpecLibBase.calc_precursor_isotope': ( 'spectral_library/library_base.html#speclibbase.calc_precursor_isotope', - 'alphabase/spectral_library/library_base.py'), - 'alphabase.spectral_library.library_base.SpecLibBase.calc_precursor_mz': ( 'spectral_library/library_base.html#speclibbase.calc_precursor_mz', - 'alphabase/spectral_library/library_base.py'), - 'alphabase.spectral_library.library_base.SpecLibBase.clip_by_precursor_mz_': ( 'spectral_library/library_base.html#speclibbase.clip_by_precursor_mz_', - 'alphabase/spectral_library/library_base.py'), - 'alphabase.spectral_library.library_base.SpecLibBase.flatten_fragment_data': ( 'spectral_library/library_base.html#speclibbase.flatten_fragment_data', - 'alphabase/spectral_library/library_base.py'), - 'alphabase.spectral_library.library_base.SpecLibBase.fragment_intensity_df': ( 'spectral_library/library_base.html#speclibbase.fragment_intensity_df', - 'alphabase/spectral_library/library_base.py'), - 'alphabase.spectral_library.library_base.SpecLibBase.fragment_mz_df': ( 'spectral_library/library_base.html#speclibbase.fragment_mz_df', - 'alphabase/spectral_library/library_base.py'), - 'alphabase.spectral_library.library_base.SpecLibBase.hash_precursor_df': ( 'spectral_library/library_base.html#speclibbase.hash_precursor_df', - 'alphabase/spectral_library/library_base.py'), - 'alphabase.spectral_library.library_base.SpecLibBase.load_df_from_hdf': ( 'spectral_library/library_base.html#speclibbase.load_df_from_hdf', - 'alphabase/spectral_library/library_base.py'), - 'alphabase.spectral_library.library_base.SpecLibBase.load_hdf': ( 'spectral_library/library_base.html#speclibbase.load_hdf', - 'alphabase/spectral_library/library_base.py'), - 'alphabase.spectral_library.library_base.SpecLibBase.peptide_df': ( 'spectral_library/library_base.html#speclibbase.peptide_df', - 'alphabase/spectral_library/library_base.py'), - 'alphabase.spectral_library.library_base.SpecLibBase.precursor_df': ( 'spectral_library/library_base.html#speclibbase.precursor_df', - 'alphabase/spectral_library/library_base.py'), - 'alphabase.spectral_library.library_base.SpecLibBase.refine_df': ( 'spectral_library/library_base.html#speclibbase.refine_df', - 'alphabase/spectral_library/library_base.py'), - 'alphabase.spectral_library.library_base.SpecLibBase.save_df_to_hdf': ( 'spectral_library/library_base.html#speclibbase.save_df_to_hdf', - 'alphabase/spectral_library/library_base.py'), - 'alphabase.spectral_library.library_base.SpecLibBase.save_hdf': ( 'spectral_library/library_base.html#speclibbase.save_hdf', - 'alphabase/spectral_library/library_base.py'), - 'alphabase.spectral_library.library_base.SpecLibBase.update_precursor_mz': ( 'spectral_library/library_base.html#speclibbase.update_precursor_mz', - 'alphabase/spectral_library/library_base.py')}, - 'alphabase.utils': { 'alphabase.utils._flatten': ('utils.html#_flatten', 'alphabase/utils.py'), - 'alphabase.utils.explode_multiple_columns': ('utils.html#explode_multiple_columns', 'alphabase/utils.py'), - 'alphabase.utils.process_bar': ('utils.html#process_bar', 'alphabase/utils.py')}, - 'alphabase.yaml_utils': { 'alphabase.yaml_utils.load_yaml': ('yaml_utils.html#load_yaml', 'alphabase/yaml_utils.py'), - 'alphabase.yaml_utils.save_yaml': ('yaml_utils.html#save_yaml', 'alphabase/yaml_utils.py')}}} \ No newline at end of file +d = { 'settings': {}, + 'syms': {}} diff --git a/alphabase/constants/aa.py b/alphabase/constants/aa.py index 2996d3d8..8eeaa918 100644 --- a/alphabase/constants/aa.py +++ b/alphabase/constants/aa.py @@ -1,32 +1,25 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbdev_nbs/constants/aa.ipynb. - -# %% auto 0 -__all__ = ['AA_CHEM', 'AA_ASCII_MASS', 'AA_DF', 'AA_formula', 'reset_AA_mass', 'reset_AA_df', 'calc_sequence_mass', - 'calc_AA_masses_for_same_len_seqs', 'calc_sequence_masses_for_same_len_seqs', - 'calc_AA_masses_for_var_len_seqs'] - -# %% ../../nbdev_nbs/constants/aa.ipynb 2 import os import pandas as pd import numpy as np from typing import Union, Tuple -from ..yaml_utils import load_yaml +from alphabase.yaml_utils import load_yaml from alphabase.constants.element import ( calc_mass_from_formula, MASS_H2O, parse_formula, ) -from ._const import CONST_FILE_FOLDER +from alphabase.constants._const import CONST_FILE_FOLDER -# %% ../../nbdev_nbs/constants/aa.ipynb 3 +# We use all 128 ASCII code to represent amino acids for flexible extensions in the future. +# The amino acid masses are stored in 128-lengh array :py:data:`AA_ASCII_MASS`. +# If an ASCII code is not in `AA_CHEM`, the mass will be set as a large value to disable MS search. AA_CHEM:dict = load_yaml( os.path.join(CONST_FILE_FOLDER, 'amino_acid.yaml') ) -# %% ../../nbdev_nbs/constants/aa.ipynb 5 def reset_AA_mass()->np.ndarray: """AA mass in np.array with shape (128,)""" AA_ASCII_MASS = np.ones(128)*1e8 @@ -53,14 +46,13 @@ def reset_AA_df(): #: 128-len AA dataframe AA_DF:pd.DataFrame = reset_AA_df() -#: AA to formula dict of dict. For example: {'K': {'C': n, 'O': m, ...}} +# AA to formula dict of dict. For example: {'K': {'C': n, 'O': m, ...}} AA_formula:dict = {} for aa, formula, mass in AA_DF.values: AA_formula[aa] = dict( parse_formula(formula) ) -# %% ../../nbdev_nbs/constants/aa.ipynb 8 def calc_sequence_mass( sequence: str )->np.ndarray: @@ -77,7 +69,6 @@ def calc_sequence_mass( ''' return AA_ASCII_MASS[np.array(sequence,'c').view(np.int8)] -# %% ../../nbdev_nbs/constants/aa.ipynb 10 def calc_AA_masses_for_same_len_seqs( sequence_array: np.ndarray )->np.ndarray: @@ -132,7 +123,6 @@ def calc_sequence_masses_for_same_len_seqs( )+MASS_H2O -# %% ../../nbdev_nbs/constants/aa.ipynb 19 def calc_AA_masses_for_var_len_seqs( sequence_array: np.ndarray )->np.ndarray: diff --git a/alphabase/constants/atom.py b/alphabase/constants/atom.py index 90bfe319..0f87b92e 100644 --- a/alphabase/constants/atom.py +++ b/alphabase/constants/atom.py @@ -1 +1 @@ -from .element import * \ No newline at end of file +from alphabase.constants.element import * \ No newline at end of file diff --git a/alphabase/constants/const_files/protease.yaml b/alphabase/constants/const_files/protease.yaml index 0b6cc7ca..ec3885cf 100644 --- a/alphabase/constants/const_files/protease.yaml +++ b/alphabase/constants/const_files/protease.yaml @@ -36,7 +36,8 @@ thermolysin: '[^DE](?=[AFILMV])' thrombin: '((?<=G)R(?=G))|((?<=[AFGILTVM][AFGILTVWA]P)R(?=[^DE][^DE]))' trypsin_full: '([KR](?=[^P]))|((?<=W)K(?=P))|((?<=M)R(?=P))' trypsin_exception: '((?<=[CD])K(?=D))|((?<=C)K(?=[HY]))|((?<=C)R(?=K))|((?<=R)R(?=[HR]))' -trypsin: '([KR](?=[^P]))' +trypsin_not_p: '([KR](?=[^P]))' +trypsin: '([KR])' trypsin/p: '([KR])' non-specific: '()' no-cleave: '_' \ No newline at end of file diff --git a/alphabase/constants/const_files/psm_reader.yaml b/alphabase/constants/const_files/psm_reader.yaml index 460b7817..0cacd736 100644 --- a/alphabase/constants/const_files/psm_reader.yaml +++ b/alphabase/constants/const_files/psm_reader.yaml @@ -23,8 +23,6 @@ alphapept: maxquant: reader_type: maxquant rt_unit: minute - mod_sep: '()' - underscore_for_ncterm: True fixed_C57: True column_mapping: 'sequence': 'Sequence' @@ -46,37 +44,32 @@ maxquant: 'proteins': 'Proteins' 'genes': ['Gene Names','Gene names'] 'decoy': 'Reverse' + 'intensity': 'Intensity' modification_mapping: 'Acetyl@Protein N-term': - '_(Acetyl (Protein N-term))' - '_(ac)' - - '_(UniMod:1)' 'Carbamidomethyl@C': - 'C(Carbamidomethyl (C))' - - 'C(UniMod:4)' 'Oxidation@M': - 'M(Oxidation (M))' - 'M(ox)' - - 'M(UniMod:35)' 'Phospho@S': - 'S(Phospho (S))' - 'S(Phospho (ST))' - 'S(Phospho (STY))' - 'S(ph)' - - 'S(UniMod:21)' - 'pS' 'Phospho@T': - 'T(Phospho (T))' - 'T(Phospho (ST))' - 'T(Phospho (STY))' - 'T(ph)' - - 'T(UniMod:21)' - 'pT' 'Phospho@Y': - 'Y(Phospho (Y))' - 'Y(Phospho (STY))' - 'Y(ph)' - - 'Y(UniMod:21)' - 'pY' 'Deamidated@N': ['N(Deamidation (NQ))','N(de)'] 'Deamidated@Q': ['Q(Deamidation (NQ))','Q(de)'] @@ -144,8 +137,6 @@ msfragger_pepxml: diann: reader_type: diann rt_unit: minute - mod_sep: '()' - underscore_for_ncterm: False fixed_C57: False csv_sep: "\t" column_mapping: @@ -160,12 +151,11 @@ diann: 'genes': 'Genes' 'scan_num': 'MS2.Scan' 'score': 'CScore' + 'fdr': 'Q.Value' modification_mapping: 'maxquant' spectronaut_report: reader_type: spectronaut_report rt_unit: minute - mod_sep: '[]' - underscore_for_ncterm: True fixed_C57: False csv_sep: ',' column_mapping: @@ -175,11 +165,10 @@ spectronaut_report: 'genes': 'PG.Genes' 'uniprot_ids': 'PG.UniProtIds' 'charge': 'charge' + modification_mapping: 'maxquant' spectronaut: reader_type: spectronaut rt_unit: irt - mod_sep: '[]' - underscore_for_ncterm: True fixed_C57: False csv_sep: "\t" mod_seq_columns: diff --git a/alphabase/constants/element.py b/alphabase/constants/element.py index cf8dec39..ef295403 100644 --- a/alphabase/constants/element.py +++ b/alphabase/constants/element.py @@ -1,20 +1,11 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbdev_nbs/constants/element.ipynb. - -# %% auto 0 -__all__ = ['common_const_dict', 'MASS_PROTON', 'MASS_ISOTOPE', 'MAX_ISOTOPE_LEN', 'EMPTY_DIST', 'CHEM_INFO_DICT', - 'CHEM_MONO_MASS', 'CHEM_ISOTOPE_DIST', 'CHEM_MONO_IDX', 'MASS_H2O', 'MASS_NH3', 'truncate_isotope', - 'reset_elements', 'load_elem_yaml', 'parse_formula', 'calc_mass_from_formula'] - -# %% ../../nbdev_nbs/constants/element.ipynb 2 import os import numpy as np import numba -from ..yaml_utils import load_yaml +from alphabase.yaml_utils import load_yaml -from ._const import CONST_FILE_FOLDER +from alphabase.constants._const import CONST_FILE_FOLDER -# %% ../../nbdev_nbs/constants/element.ipynb 3 common_const_dict:dict = load_yaml( os.path.join(CONST_FILE_FOLDER, 'common_constants.yaml') ) @@ -22,7 +13,6 @@ MASS_PROTON:float = common_const_dict['MASS_PROTON'] MASS_ISOTOPE:float = common_const_dict['MASS_ISOTOPE'] -# %% ../../nbdev_nbs/constants/element.ipynb 5 MAX_ISOTOPE_LEN = common_const_dict['MAX_ISOTOPE_LEN'] EMPTY_DIST = np.zeros(MAX_ISOTOPE_LEN) EMPTY_DIST[0] = 1 @@ -75,7 +65,6 @@ def truncate_isotope( trunc_start = len(isotopes)-MAX_ISOTOPE_LEN-1 return mono_idx-trunc_start-1, trunc_start+1, trunc_end -# %% ../../nbdev_nbs/constants/element.ipynb 7 #: chemical element information in dict defined by `nist_element.yaml` CHEM_INFO_DICT = {} @@ -164,7 +153,6 @@ def load_elem_yaml(yaml_file:str): ) ) -# %% ../../nbdev_nbs/constants/element.ipynb 9 def parse_formula( formula:str )->list: diff --git a/alphabase/constants/isotope.py b/alphabase/constants/isotope.py index ae43bd3a..69e92f8c 100644 --- a/alphabase/constants/isotope.py +++ b/alphabase/constants/isotope.py @@ -1,9 +1,3 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbdev_nbs/constants/isotope.ipynb. - -# %% auto 0 -__all__ = ['abundance_convolution', 'one_element_dist', 'formula_dist', 'IsotopeDistribution'] - -# %% ../../nbdev_nbs/constants/isotope.ipynb 3 import numba import numpy as np import typing @@ -14,7 +8,6 @@ truncate_isotope, parse_formula ) -# %% ../../nbdev_nbs/constants/isotope.ipynb 4 @numba.njit def abundance_convolution( d1:np.ndarray, @@ -55,7 +48,6 @@ def abundance_convolution( mono_idx, start, end = truncate_isotope(ret, mono_idx) return ret[start:end], mono_idx -# %% ../../nbdev_nbs/constants/isotope.ipynb 6 @numba.njit def one_element_dist( elem: str, @@ -125,7 +117,6 @@ def formula_dist( calc_dist, mono_idx = abundance_convolution(calc_dist, mono_idx, _dist, _mono) return calc_dist, mono_idx -# %% ../../nbdev_nbs/constants/isotope.ipynb 23 def _calc_one_elem_cum_dist( element_cum_dist:np.ndarray, element_cum_mono:np.ndarray @@ -154,7 +145,6 @@ def _calc_one_elem_cum_dist( element_cum_mono[1] ) -# %% ../../nbdev_nbs/constants/isotope.ipynb 24 class IsotopeDistribution: def __init__(self, max_elem_num_dict:dict = { diff --git a/alphabase/constants/modification.py b/alphabase/constants/modification.py index 265d154b..329a85d6 100644 --- a/alphabase/constants/modification.py +++ b/alphabase/constants/modification.py @@ -1,12 +1,3 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbdev_nbs/constants/modification.ipynb. - -# %% auto 0 -__all__ = ['MOD_DF', 'MOD_INFO_DICT', 'MOD_CHEM', 'MOD_MASS', 'MOD_LOSS_MASS', 'MOD_formula', 'MOD_LOSS_IMPORTANCE', - 'update_all_by_MOD_DF', 'add_modifications_for_lower_case_AA', 'keep_modloss_by_importance', 'load_mod_df', - 'calc_modification_mass', 'calc_mod_masses_for_same_len_seqs', 'calc_modification_mass_sum', - 'calc_modloss_mass_with_importance', 'calc_modloss_mass', 'add_new_modifications'] - -# %% ../../nbdev_nbs/constants/modification.ipynb 3 import os import numba import numpy as np @@ -17,9 +8,8 @@ calc_mass_from_formula, parse_formula, ) -from ._const import CONST_FILE_FOLDER +from alphabase.constants._const import CONST_FILE_FOLDER -# %% ../../nbdev_nbs/constants/modification.ipynb 4 MOD_DF:pd.DataFrame = pd.DataFrame() MOD_INFO_DICT:dict = {} @@ -78,7 +68,6 @@ def _mod_lower_case(modname): MOD_DF = pd.concat([MOD_DF, lower_case_df]) update_all_by_MOD_DF() -# %% ../../nbdev_nbs/constants/modification.ipynb 5 def keep_modloss_by_importance(modloss_importance_level:float=1.0): MOD_DF['modloss'] = MOD_DF['modloss_original'] MOD_DF.loc[MOD_DF.modloss_importancenp.ndarray: + excluded = np.zeros_like(fragment_intensities, dtype=np.bool_) + for frag_start, frag_end in zip(frag_start_idxes, frag_end_idxes): + if top_k >= frag_end-frag_start: continue + idxes = np.argsort(fragment_intensities[frag_start:frag_end]) + _excl = np.ones_like(idxes, dtype=np.bool_) + _excl[idxes[-top_k:]] = False + excluded[frag_start:frag_end] = _excl + return excluded + + +def flatten_fragments(precursor_df: pd.DataFrame, + fragment_mz_df: pd.DataFrame, + fragment_intensity_df: pd.DataFrame, + min_fragment_intensity: float = -1., + keep_top_k_fragments: int = 1000, + custom_columns:list = [ + 'type','number','position','charge','loss_type' + ], +)->Tuple[pd.DataFrame, pd.DataFrame]: + """ + Converts the tabular fragment format consisting of + the `fragment_mz_df` and the `fragment_intensity_df` + into a linear fragment format. + The linear fragment format will only retain fragments + above a given intensity treshold with `mz > 0`. + It consists of columns: `mz`, `intensity`, + `type`, `number`, `charge` and `loss_type`, + where each column refers to: + + - mz: float64, fragment mz value + - intensity: float32, fragment intensity value + - type: int8, ASCII code of the ion type (97=a, 98=b, 99=c, 120=x, 121=y, 122=z), or more ion types in the future. See https://en.wikipedia.org/wiki/ASCII for more ASCII information + - number: uint32, fragment series number + - position: uint32, fragment position in sequence (from left to right, starts with 0) + - charge: int8, fragment charge + - loss_type: int16, fragment loss type, 0=noloss, 17=NH3, 18=H2O, 98=H3PO4 (phos), ... + + The fragment pointers `frag_start_idx` and `frag_end_idx` + will be reannotated to the new fragment format. + + For ASCII code `type`, we can convert it into byte-str by using `frag_df.type.values.view('S1')`. + + Parameters + ---------- + precursor_df : pd.DataFrame + input precursor dataframe which contains the frag_start_idx and frag_end_idx columns + + fragment_mz_df : pd.DataFrame + input fragment mz dataframe of shape (N, T) which contains N * T fragment mzs + + fragment_intensity_df : pd.DataFrame + input fragment mz dataframe of shape (N, T) which contains N * T fragment mzs + + min_fragment_intensity : float, optional + minimum intensity which should be retained. Defaults to -1.0 + + custom_columns : list, optional + 'mz' and 'intensity' columns are required. Others could be customized. + Defaults to ['type','number','position','charge','loss_type'] + + Returns + ------- + pd.DataFrame + precursor dataframe whith reindexed `frag_start_idx` and `frag_end_idx` columns + pd.DataFrame + fragment dataframe with columns: `mz`, `intensity`, `type`, `number`, + `charge` and `loss_type`, where each column refers to: + + - mz: float, fragment mz value + - intensity: float32, fragment intensity value + - type: int8, ASCII code of the ion type (97=a, 98=b, 99=c, 120=x, 121=y, 122=z), or more ion types in the future. See https://en.wikipedia.org/wiki/ASCII for more ASCII information + - number: uint32, fragment series number + - position: uint32, fragment position in sequence (from left to right, starts with 0) + - charge: int8, fragment charge + - loss_type: int16, fragment loss type, 0=noloss, 17=NH3, 18=H2O, 98=H3PO4 (phos), ... + """ + + # new dataframes for fragments and precursors are created + frag_df = pd.DataFrame() + frag_df['mz'] = fragment_mz_df.values.reshape(-1) + frag_df['intensity'] = fragment_intensity_df.values.astype(np.float32).reshape(-1) + + frag_types = [] + frag_loss_types = [] + frag_charges = [] + frag_directions = [] # 'abc': direction=1, 'xyz': direction=-1, otherwise 0 + + for col in fragment_mz_df.columns.values: + _types = col.split('_') + frag_types.append(ord(_types[0])) # using ASCII code + frag_charges.append(int(_types[-1][1:])) + if len(_types) == 2: + frag_loss_types.append(0) + else: + if _types[1] == 'NH3': + frag_loss_types.append(17) + elif _types[1] == 'H2O': + frag_loss_types.append(18) + else: + frag_loss_types.append(98) + + if _types[0] in 'abc': + frag_directions.append(1) + elif _types[0] in 'xyz': + frag_directions.append(-1) + else: + frag_directions.append(0) + + if 'type' in custom_columns: + frag_df['type'] = np.array(frag_types*len(fragment_mz_df), dtype=np.int8) + if 'loss_type' in custom_columns: + frag_df['loss_type'] = np.array(frag_loss_types*len(fragment_mz_df), dtype=np.int16) + if 'charge' in custom_columns: + frag_df['charge'] = np.array(frag_charges*len(fragment_mz_df), dtype=np.int8) + + frag_directions = np.array([frag_directions]*len(fragment_mz_df), dtype=np.int8) + if 'number' in custom_columns: + frag_df['number'] = parse_fragment_numbers( + frag_directions, + precursor_df.frag_start_idx.values, + precursor_df.frag_end_idx.values + ).reshape(-1) + if 'position' in custom_columns: + frag_df['position'] = parse_fragment_positions( + frag_directions, + precursor_df.frag_start_idx.values, + precursor_df.frag_end_idx.values + ).reshape(-1) + + precursor_new_df = precursor_df.copy() + precursor_new_df[['frag_start_idx','frag_end_idx']] *= len(fragment_mz_df.columns) + + + frag_df.intensity.mask(frag_df.mz == 0.0, 0.0, inplace=True) + excluded = ( + frag_df.intensity.values < min_fragment_intensity + ) | ( + frag_df.mz.values == 0 + ) | ( + exclude_not_top_k( + frag_df.intensity.values, keep_top_k_fragments, + precursor_new_df.frag_start_idx.values, + precursor_new_df.frag_end_idx.values, + ) + ) + frag_df = frag_df[~excluded] + frag_df = frag_df.reset_index(drop=True) + + + # cumulative sum counts the number of fragments before the given fragment which were removed. + # This sum does not include the fragment at the index position and has therefore len N +1 + cum_sum_tresh = np.zeros(shape=len(excluded)+1, dtype=np.int64) + cum_sum_tresh[1:] = np.cumsum(excluded) + + precursor_new_df['frag_start_idx'] -= cum_sum_tresh[precursor_new_df.frag_start_idx.values] + precursor_new_df['frag_end_idx'] -= cum_sum_tresh[precursor_new_df.frag_end_idx.values] + + return precursor_new_df, frag_df + +@nb.njit() +def compress_fragment_indices(frag_idx): + """ + recalculates fragment indices to remove unused fragments. Can be used to compress a fragment library. + Expects fragment indices to be ordered by increasing values (!!!). + It should be O(N) runtime with N being the number of fragment rows. + + >>> frag_idx = [[6, 10], + [12, 14], + [20, 22]] + + >>> frag_idx = [[0, 4], + [4, 6], + [6, 8]] + >>> fragment_pointer = [6,7,8,9,12,13,20,21] + """ + frag_idx_len = frag_idx[:,1]-frag_idx[:,0] + + + # This sum does not include the fragment at the index position and has therefore len N +1 + frag_idx_cumsum = np.zeros(shape=len(frag_idx_len)+1, dtype='int64') + frag_idx_cumsum[1:] = np.cumsum(frag_idx_len) + + fragment_pointer = np.zeros(np.sum(frag_idx_len), dtype='int64') + + for i in range(len(frag_idx)): + + start_index = frag_idx_cumsum[i] + + for j,k in enumerate(range(frag_idx[i,0],frag_idx[i,1])): + fragment_pointer[start_index+j]=k + + + new_frag_idx = np.column_stack((frag_idx_cumsum[:-1],frag_idx_cumsum[1:])) + return new_frag_idx, fragment_pointer + +def remove_unused_fragments( + precursor_df: pd.DataFrame, + fragment_df_list: Tuple[pd.DataFrame, ...] + ) -> Tuple[pd.DataFrame, Tuple[pd.DataFrame, ...]]: + """Removes unused fragments of removed precursors, + reannotates the frag_start_idx and frag_end_idx + + Parameters + ---------- + precursor_df : pd.DataFrame + Precursor dataframe which contains frag_start_idx and frag_end_idx columns + + fragment_df_list : List[pd.DataFrame] + A list of fragment dataframes which should be compressed by removing unused fragments. + Multiple fragment dataframes can be provided which will all be sliced in the same way. + This allows to slice both the fragment_mz_df and fragment_intensity_df. + At least one fragment dataframe needs to be provided. + + Returns + ------- + pd.DataFrame, List[pd.DataFrame] + returns the reindexed precursor DataFrame and the sliced fragment DataFrames + """ + + precursor_df = precursor_df.sort_values(['frag_start_idx'], ascending=True) + frag_idx = precursor_df[['frag_start_idx','frag_end_idx']].values + + new_frag_idx, fragment_pointer = compress_fragment_indices(frag_idx) + + precursor_df[['frag_start_idx','frag_end_idx']] = new_frag_idx + precursor_df = precursor_df.sort_index() + + output_tuple = [] + + for i in range(len(fragment_df_list)): + output_tuple.append(fragment_df_list[i].iloc[fragment_pointer].copy().reset_index(drop=True)) + + return precursor_df, tuple(output_tuple) + def create_fragment_mz_dataframe_by_sort_precursor( precursor_df: pd.DataFrame, charged_frag_types:List, batch_size:int=500000, )->pd.DataFrame: """Sort nAA in precursor_df for faster fragment mz dataframe creation. - + Because the fragment mz values are continous in memory, so it is faster when setting values in pandas. - + Note that this function will change the order and index of precursor_df - + Parameters ---------- precursor_df : pd.DataFrame precursor dataframe - + charged_frag_types : List fragment types list - + batch_size : int, optional Calculate fragment mz values in batch. Defaults to 500000. @@ -539,31 +783,25 @@ def create_fragment_mz_dataframe( `reference_fragment_df` must be provided charged_frag_types : List `['b_z1','b_z2','y_z1','y_z2','b_modloss_1','y_H2O_z1'...]` - + reference_fragment_df : pd.DataFrame kwargs only. Generate fragment_mz_df based on this reference, as `precursor_df.frag_start_idx` and `precursor.frag_end_idx` point to the indices in `reference_fragment_df`. Defaults to None - + inplace_in_reference : bool kwargs only. Change values in place in the `reference_fragment_df`. Defaults to False - + batch_size: int Number of peptides for each batch, to save RAM. - + Returns ------- pd.DataFrame `fragment_mz_df` with given `charged_frag_types` - - # Raises - # ------ - # ValueError - # when `precursor_df` contains 'frag_start_idx' but - # `reference_fragment_df` is not None ''' if reference_fragment_df is None: if 'frag_start_idx' in precursor_df.columns: @@ -638,3 +876,60 @@ def create_fragment_mz_dataframe( precursor_df.nAA.values, ) + +# %% ../../nbdev_nbs/peptide/fragment.ipynb 38 +@nb.njit(nogil=True) +def join_left( + left: np.ndarray, + right: np.ndarray + ): + """joins all values in the left array to the values in the right array. + The index to the element in the right array is returned. + If the value wasn't found, -1 is returned. If the element appears more than once, the last appearance is used. + + Parameters + ---------- + + left: numpy.ndarray + left array which should be matched + + right: numpy.ndarray + right array which should be matched to + + Returns + ------- + numpy.ndarray, dtype = int64 + array with length of the left array which indices pointing to the right array + -1 is returned if values could not be found in the right array + """ + left_indices = np.argsort(left) + left_sorted = left[left_indices] + + right_indices = np.argsort(right) + right_sorted = right[right_indices] + + joined_index = -np.ones(len(left), dtype='int64') + + # from hereon sorted arrays are expected + lower_right = 0 + + for i in range(len(joined_index)): + + for k in range(lower_right, len(right)): + + if left_sorted[i] >= right_sorted[k]: + if left_sorted[i] == right_sorted[k]: + joined_index[i] = k + lower_right = k + else: + break + + # the joined_index_sorted connects indices from the sorted left array with the sorted right array + # to get the original indices, the order of both sides needs to be restored + # First, the indices pointing to the right side are restored by masking the array for hits and looking up the right side + joined_index[joined_index >= 0] = right_indices[joined_index[joined_index >= 0]] + + # Next, the left side is restored by arranging the items + joined_index[left_indices] = joined_index + + return joined_index diff --git a/alphabase/peptide/mass_calc.py b/alphabase/peptide/mass_calc.py index 6a3c732b..5713222d 100644 --- a/alphabase/peptide/mass_calc.py +++ b/alphabase/peptide/mass_calc.py @@ -1,10 +1,3 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbdev_nbs/peptide/mass_calc.ipynb. - -# %% auto 0 -__all__ = ['calc_delta_modification_mass', 'calc_mod_delta_masses_for_same_len_seqs', 'calc_b_y_and_peptide_mass', - 'calc_peptide_masses_for_same_len_seqs', 'calc_b_y_and_peptide_masses_for_same_len_seqs'] - -# %% ../../nbdev_nbs/peptide/mass_calc.ipynb 4 import numpy as np from typing import List, Tuple @@ -18,9 +11,8 @@ calc_modification_mass_sum, calc_mod_masses_for_same_len_seqs ) -from ..constants.element import MASS_H2O +from alphabase.constants.element import MASS_H2O -# %% ../../nbdev_nbs/peptide/mass_calc.ipynb 5 def calc_delta_modification_mass( pep_len:int, mass_deltas:List[float], @@ -135,7 +127,6 @@ def calc_b_y_and_peptide_mass( y_masses = pepmass - b_masses return b_masses, y_masses, pepmass -# %% ../../nbdev_nbs/peptide/mass_calc.ipynb 7 def calc_peptide_masses_for_same_len_seqs( sequences: np.ndarray, mod_list: List[str], diff --git a/alphabase/peptide/mobility.py b/alphabase/peptide/mobility.py index 87a47e8f..9dd6020e 100644 --- a/alphabase/peptide/mobility.py +++ b/alphabase/peptide/mobility.py @@ -1,17 +1,9 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbdev_nbs/peptide/mobility.ipynb. - -# %% auto 0 -__all__ = ['CCS_IM_COEF', 'IM_GAS_MASS', 'get_reduced_mass', 'ccs_to_mobility_bruker', 'mobility_to_ccs_bruker', - 'ccs_to_mobility_for_df', 'mobility_to_ccs_for_df'] - -# %% ../../nbdev_nbs/peptide/mobility.ipynb 2 import numpy as np import pandas as pd -from .fragment import update_precursor_mz -from ..constants.element import common_const_dict +from alphabase.peptide.fragment import update_precursor_mz +from alphabase.constants.element import common_const_dict -# %% ../../nbdev_nbs/peptide/mobility.ipynb 3 CCS_IM_COEF = common_const_dict['MOBILITY']['CCS_IM_COEF'] IM_GAS_MASS = common_const_dict['MOBILITY']['IM_GAS_MASS'] diff --git a/alphabase/peptide/precursor.py b/alphabase/peptide/precursor.py index 15d20a6e..8e9ed724 100644 --- a/alphabase/peptide/precursor.py +++ b/alphabase/peptide/precursor.py @@ -1,12 +1,3 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbdev_nbs/peptide/precursor.ipynb. - -# %% auto 0 -__all__ = ['reset_precursor_df', 'is_precursor_sorted', 'calc_precursor_mz', 'refine_precursor_df', 'is_precursor_refined', - 'update_precursor_mz', 'get_mod_seq_hash', 'get_mod_seq_charge_hash', 'hash_mod_seq_df', - 'hash_mod_seq_charge_df', 'hash_precursor_df', 'get_mod_seq_formula', 'get_right_most_isotope_index', - 'get_mod_seq_isotope_distribution', 'calc_precursor_isotope', 'calc_precursor_isotope_mp'] - -# %% ../../nbdev_nbs/peptide/precursor.ipynb 2 import pandas as pd import numpy as np import numba @@ -18,8 +9,8 @@ from alphabase.constants.element import ( MASS_PROTON, MASS_ISOTOPE ) -from ..constants.aa import AA_formula -from ..constants.modification import MOD_formula +from alphabase.constants.aa import AA_formula +from alphabase.constants.modification import MOD_formula from alphabase.constants.isotope import ( IsotopeDistribution ) @@ -27,7 +18,6 @@ calc_peptide_masses_for_same_len_seqs ) -# %% ../../nbdev_nbs/peptide/precursor.ipynb 3 def refine_precursor_df( df:pd.DataFrame, drop_frag_idx = True, @@ -68,7 +58,7 @@ def is_precursor_refined(precursor_df: pd.DataFrame): return ( (len(precursor_df) == 0) or ( (precursor_df.index.values[0] == 0) and - precursor_df.nAA.is_monotonic and + precursor_df.nAA.is_monotonic_increasing and np.all( np.diff(precursor_df.index.values)==1 ) @@ -134,7 +124,6 @@ def update_precursor_mz( calc_precursor_mz = update_precursor_mz -# %% ../../nbdev_nbs/peptide/precursor.ipynb 4 def get_mod_seq_hash( sequence:str, mods:str, mod_sites:str, @@ -288,7 +277,6 @@ def hash_precursor_df( hash_mod_seq_charge_df(precursor_df, seed=seed) return precursor_df -# %% ../../nbdev_nbs/peptide/precursor.ipynb 5 def get_mod_seq_formula(seq:str, mods:str)->list: """ 'PEPTIDE','Acetyl@Any N-term' --> [('C',n), ('H',m), ...] @@ -310,7 +298,7 @@ def get_mod_seq_formula(seq:str, mods:str)->list: return list(formula.items()) @numba.njit -def get_right_most_isotope_index( +def get_right_most_isotope_offset( intensities:np.ndarray, apex_idx:int, min_right_most_intensity:float, @@ -369,13 +357,9 @@ def get_mod_seq_isotope_distribution( tuple float - Abundance of mono+1 / mono float - Abundance of apex / mono - int - Apex isotope position relative to mono, - i.e. apex index - mono index and - 0 refers to the position of mono itself - float - Abundance of right-most peak which has at least `min_right_most_intensity` - intensity relative to the apex peak - int - Right-most position relative to mono, - i.e. right-most index - mono index + int - Apex isotope position relative to mono, i.e. apex index - mono index and 0 refers to the position of mono itself + float - Abundance of right-most peak which has at least `min_right_most_intensity` intensity relative to the apex peak + int - Right-most position relative to mono, i.e. right-most index - mono index """ dist, mono = isotope_dist.calc_formula_distribution( get_mod_seq_formula(*seq_mods) @@ -384,7 +368,7 @@ def get_mod_seq_isotope_distribution( apex_idx = np.argmax(dist) # find right-most peak - right_most_idx = get_right_most_isotope_index( + right_most_idx = get_right_most_isotope_offset( dist, apex_idx, min_right_most_intensity ) @@ -419,10 +403,10 @@ def calc_precursor_isotope( - isotope_m1_mz - isotope_apex_intensity - isotope_apex_mz - - isotope_apex_index + - isotope_apex_offset - isotope_right_most_intensity - isotope_right_most_mz - - isotope_right_most_index + - isotope_right_most_offset """ if "precursor_mz" not in precursor_df.columns: @@ -433,9 +417,9 @@ def calc_precursor_isotope( ( precursor_df['isotope_m1_intensity'], precursor_df['isotope_apex_intensity'], - precursor_df['isotope_apex_index'], + precursor_df['isotope_apex_offset'], precursor_df['isotope_right_most_intensity'], - precursor_df['isotope_right_most_index'], + precursor_df['isotope_right_most_offset'], ) = zip( *precursor_df[['sequence','mods']].apply( get_mod_seq_isotope_distribution, @@ -443,6 +427,21 @@ def calc_precursor_isotope( min_right_most_intensity=min_right_most_intensity, ) ) + precursor_df['isotope_m1_intensity'] = precursor_df[ + 'isotope_m1_intensity' + ].astype(np.float32) + precursor_df['isotope_apex_intensity'] = precursor_df[ + 'isotope_apex_intensity' + ].astype(np.float32) + precursor_df['isotope_apex_offset'] = precursor_df[ + 'isotope_apex_offset' + ].astype(np.int8) + precursor_df['isotope_right_most_intensity'] = precursor_df[ + 'isotope_right_most_intensity' + ].astype(np.float32) + precursor_df['isotope_right_most_offset'] = precursor_df[ + 'isotope_right_most_offset' + ].astype(np.int8) precursor_df['isotope_m1_mz'] = ( precursor_df.precursor_mz + @@ -453,7 +452,7 @@ def calc_precursor_isotope( precursor_df.precursor_mz + ( MASS_ISOTOPE - *precursor_df.isotope_apex_index + *precursor_df.isotope_apex_offset /precursor_df.charge ) ) @@ -461,7 +460,7 @@ def calc_precursor_isotope( precursor_df.precursor_mz + ( MASS_ISOTOPE - *precursor_df.isotope_right_most_index + *precursor_df.isotope_right_most_offset /precursor_df.charge ) ) @@ -490,6 +489,7 @@ def calc_precursor_isotope_mp( mp_batch_size:int=100000, process_bar=None, min_right_most_intensity:float=0.2, + min_precursor_num_to_run_mp:int=1000, )->pd.DataFrame: """`calc_precursor_isotope` is not that fast for large dataframes, so here we use multiprocessing for faster isotope pattern calculation. @@ -522,11 +522,16 @@ def calc_precursor_isotope_mp( - isotope_m1_mz - isotope_apex_intensity - isotope_apex_mz - - isotope_apex_index + - isotope_apex_offset - isotope_right_most_intensity - isotope_right_most_mz - - isotope_right_most_index + - isotope_right_most_offset """ + if len(precursor_df) < min_precursor_num_to_run_mp: + return calc_precursor_isotope( + precursor_df=precursor_df, + min_right_most_intensity=min_right_most_intensity, + ) df_list = [] df_group = precursor_df.groupby('nAA') with mp.Pool(processes) as p: diff --git a/alphabase/protein/fasta.py b/alphabase/protein/fasta.py index f35aed7c..5c96edc9 100644 --- a/alphabase/protein/fasta.py +++ b/alphabase/protein/fasta.py @@ -1,13 +1,3 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbdev_nbs/protein/fasta.ipynb. - -# %% auto 0 -__all__ = ['protease_dict', 'get_var_mods_per_sites', 'get_uniprot_gene_name', 'read_fasta_file', 'load_all_proteins', - 'concat_proteins', 'cleave_sequence_with_cut_pos', 'Digest', 'get_fix_mods', 'get_candidate_sites', - 'get_var_mod_sites', 'get_var_mods_per_sites_multi_mods_on_aa', 'get_var_mods_per_sites_single_mod_on_aa', - 'get_var_mods', 'parse_term_mod', 'add_single_peptide_labeling', 'parse_labels', - 'create_labeling_peptide_df', 'protein_idxes_to_names', 'append_regular_modifications', 'FastaLib'] - -# %% ../../nbdev_nbs/protein/fasta.ipynb 2 import regex as re import numpy as np import pandas as pd @@ -19,15 +9,14 @@ from Bio import SeqIO from typing import Union -from ..yaml_utils import load_yaml -from ..io.hdf import HDF_File -from ..utils import explode_multiple_columns +from alphabase.yaml_utils import load_yaml +from alphabase.io.hdf import HDF_File +from alphabase.utils import explode_multiple_columns -from ..constants._const import CONST_FILE_FOLDER +from alphabase.constants._const import CONST_FILE_FOLDER -from ..spectral_library.library_base import SpecLibBase +from alphabase.spectral_library.base import SpecLibBase -# %% ../../nbdev_nbs/protein/fasta.ipynb 3 def get_uniprot_gene_name(description:str): idx = description.find(' GN=') if idx == -1: return '' @@ -102,13 +91,15 @@ def concat_proteins(protein_dict:dict, sep='$')->str: seq_list.append('') return '$'.join(seq_list) -# %% ../../nbdev_nbs/protein/fasta.ipynb 5 protease_dict = load_yaml( os.path.join( CONST_FILE_FOLDER, 'protease.yaml' ) ) +""" +Pre-built protease dict with regular expression. +""" @numba.njit def cleave_sequence_with_cut_pos( @@ -264,7 +255,6 @@ def cleave_sequence(self, cterm_list.append(cterm) return seq_list, miss_list, nterm_list, cterm_list -# %% ../../nbdev_nbs/protein/fasta.ipynb 10 def get_fix_mods( sequence:str, fix_mod_aas:str, @@ -281,7 +271,6 @@ def get_fix_mods( mods.append(fix_mod_dict[aa]) return ';'.join(mods), ';'.join(str(i) for i in mod_sites) -# %% ../../nbdev_nbs/protein/fasta.ipynb 12 def get_candidate_sites( sequence:str, target_mod_aas:str )->list: @@ -349,7 +338,6 @@ def get_var_mod_sites( ) return mod_sites -# %% ../../nbdev_nbs/protein/fasta.ipynb 14 def get_var_mods_per_sites_multi_mods_on_aa( sequence:str, mod_sites:tuple, @@ -422,7 +410,6 @@ def get_var_mods( ret_sites_list.append('') return ret_mods, ret_sites_list -# %% ../../nbdev_nbs/protein/fasta.ipynb 17 def parse_term_mod(term_mod_name:str): _mod, term = term_mod_name.split('@') if '^' in term: @@ -430,7 +417,6 @@ def parse_term_mod(term_mod_name:str): else: return '', term -# %% ../../nbdev_nbs/protein/fasta.ipynb 19 def add_single_peptide_labeling( seq:str, mods:str, @@ -500,17 +486,15 @@ def create_labeling_peptide_df(peptide_df:pd.DataFrame, labels:list): return df -# %% ../../nbdev_nbs/protein/fasta.ipynb 21 def protein_idxes_to_names(protein_idxes:str, protein_names:list): if len(protein_idxes) == 0: return '' proteins = [protein_names[int(i)] for i in protein_idxes.split(';')] proteins = [protein for protein in proteins if protein] return ';'.join(proteins) -# %% ../../nbdev_nbs/protein/fasta.ipynb 23 def append_regular_modifications(df:pd.DataFrame, var_mods = ['Phospho@S','Phospho@T','Phospho@Y'], - max_mod_num=1, max_combs=100, + max_mod_num=1, max_peptidoform_num=100, keep_unmodified=True, cannot_modify_pep_nterm_aa:bool=False, cannot_modify_pep_cterm_aa:bool=False, @@ -532,9 +516,9 @@ def append_regular_modifications(df:pd.DataFrame, Maximal modification number for each sequence of the `var_mods`. Defaults to 1. - max_combs : int, optional + max_peptidoform_num : int, optional One sequence is only allowed to explode - to `max_combs` number of modified peptides. Defaults to 100. + to `max_peptidoform_num` number of modified peptides. Defaults to 100. keep_unmodified : bool, optional If unmodified (only refered to `var_mods`) @@ -573,7 +557,7 @@ def append_regular_modifications(df:pd.DataFrame, df['mod_sites_app'] ) = zip(*df.sequence.apply(get_var_mods, var_mod_aas=var_mod_aas, mod_dict=mod_dict, - max_var_mod=max_mod_num, max_combs=max_combs, + max_var_mod=max_mod_num, max_combs=max_peptidoform_num, keep_unmodified=keep_unmodified ) ) @@ -604,19 +588,39 @@ def append_regular_modifications(df:pd.DataFrame, df.reset_index(drop=True, inplace=True) return df -# %% ../../nbdev_nbs/protein/fasta.ipynb 24 class FastaLib(SpecLibBase): + """ + This is the main entry of AlphaBase when generating spectral libraries from fasta files + It includes functionalities to: + - Digest protein sequences + - Add fixed, variable or labeling modifications to the peptide sequences + - Add charge states + - Append decoy peptides + - Save libraries into hdf file + + Attributes + ---------- + max_peptidoform_num : int, 100 by default + For some modifications such as Phospho, there may be + thousands of peptidoforms generated for some peptides, + so we use this attribute to control the overall number of + peptidoforms of a peptide. + + protein_df : pd.DataFrame + Protein dataframe with columns 'protein_id', + 'sequence', 'description', 'gene_name', etc. + """ def __init__(self, charged_frag_types:list = [ 'b_z1','b_z2','y_z1', 'y_z2' ], - protease:str = 'trypsin/P', + protease:str = 'trypsin', max_missed_cleavages:int = 2, peptide_length_min:int = 7, peptide_length_max:int = 35, precursor_charge_min:int = 2, precursor_charge_max:int = 4, - precursor_mz_min:float = 200.0, + precursor_mz_min:float = 400.0, precursor_mz_max:float = 2000.0, var_mods:list = ['Acetyl@Protein N-term','Oxidation@M'], max_var_mod_num:int = 2, @@ -624,13 +628,7 @@ def __init__(self, decoy: str = None, # or pseudo_reverse or diann I_to_L=False, ): - """Class to process fasta files and generate libraries, including: - - Digest protein sequences - - Add fixed, variable or labeling modifications to the peptide sequences - - Add charge states - - Append decoy peptides - - Save libraries into hdf file - + """ Parameters ---------- charged_frag_types : list, optional @@ -638,9 +636,9 @@ def __init__(self, by default [ 'b_z1','b_z2','y_z1', 'y_z2' ] protease : str, optional - Could be pre-defined protease name defined in `protease_dict`, + Could be pre-defined protease name defined in :data:`protease_dict`, or a regular expression. - By default 'trypsin/P' + By default 'trypsin' max_missed_cleavages : int, optional Maximal missed cleavages, by default 2 @@ -677,20 +675,6 @@ def __init__(self, decoy : str, optional Decoy type, see `alphabase.spectral_library.decoy_library`, by default None - - Attributes - ---------- - precursor_df : pd.DataFrame - The main peptide/precursor DataFrame containing peptide sequences, modifications, ... - - protein_df : pd.DataFrame - It contains protein sequences, gene names, protein ids ... - - fragment_mz_df : pd.DataFrame - Fragment mz DataFrame - - fragment_intensity_df : pd.DataFrame - Fragment intensity DataFrame """ super().__init__( charged_frag_types=charged_frag_types, @@ -700,7 +684,7 @@ def __init__(self, ) self.protein_df:pd.DataFrame() = pd.DataFrame() self.I_to_L = I_to_L - self.max_mod_combinations = 100 + self.max_peptidoform_num = 100 self._digest = Digest( protease, max_missed_cleavages, peptide_length_min, peptide_length_max @@ -837,13 +821,9 @@ def import_and_process_protein_dict(self, protein_dict:dict): protein_dict : dict Format: { - 'prot_id1': - 'protein_id': 'prot_id1' - 'sequence': string - 'gene_name': string - 'description': string - 'prot_id2': - ... + 'prot_id1': {'protein_id': 'prot_id1', 'sequence': string, 'gene_name': string, 'description': string + 'prot_id2': {...} + ... } """ self.get_peptides_from_protein_dict(protein_dict) @@ -908,13 +888,9 @@ def get_peptides_from_protein_dict(self, protein_dict:dict): protein_dict : dict Format: { - 'prot_id1': - 'protein_id': 'prot_id1' - 'sequence': string - 'gene_name': string - 'description': string - 'prot_id2': - ... + 'prot_id1': {'protein_id': 'prot_id1', 'sequence': string, 'gene_name': string, 'description': string + 'prot_id2': {...} + ... } """ self.protein_df = pd.DataFrame.from_dict( @@ -1046,7 +1022,7 @@ def add_mods_for_one_seq(self, sequence:str, var_mods_list, var_mod_sites_list = get_var_mods( sequence, self.var_mod_aas, self.var_mod_dict, - self.max_var_mod_num, self.max_mod_combinations-1, # 1 for unmodified + self.max_var_mod_num, self.max_peptidoform_num-1, # 1 for unmodified keep_unmodified=True ) @@ -1103,19 +1079,19 @@ def add_modifications(self): def add_additional_modifications(self, var_mods = ['Phospho@S','Phospho@T','Phospho@Y'], - max_mod_num:int=1, max_combs:int=100, + max_mod_num:int=1, max_peptidoform_num:int=100, keep_unmodified:bool=True, cannot_modify_pep_nterm_aa:bool=False, cannot_modify_pep_cterm_aa:bool=False, ): """Add external defined variable modifications to all peptide sequences in `self.precursor_df`. - See `append_regular_modifications` for details + See :meth:`append_regular_modifications()` for details """ self._precursor_df = append_regular_modifications( self.precursor_df, var_mods=var_mods, max_mod_num=max_mod_num, - max_combs=max_combs, + max_peptidoform_num=max_peptidoform_num, keep_unmodified=keep_unmodified, cannot_modify_pep_nterm_aa=cannot_modify_pep_nterm_aa, cannot_modify_pep_cterm_aa=cannot_modify_pep_cterm_aa, @@ -1130,10 +1106,10 @@ def add_peptide_labeling(self, labeling_channel_dict:dict): labeling_channel_dict : dict of list For example: { - 'reference': [], # not labelled for reference - '0': ['Dimethyl@Any N-term','Dimethyl@K'], - '4': ['Dimethyl:2H(4)@Any N-term','Dimethyl:2H(4)@K'], - '8': ['Dimethyl:2H(6)13C(2)@Any N-term','Dimethyl:2H(6)13C(2)@K'], + '': [], # not labelled for reference + '0': ['Dimethyl@Any N-term','Dimethyl@K'], + '4': ['Dimethyl:2H(4)@Any N-term','Dimethyl:2H(4)@K'], + '8': ['Dimethyl:2H(6)13C(2)@Any N-term','Dimethyl:2H(6)13C(2)@K'], }. The key name could be arbitrary distinguished strings for channel name, and value must be a list of modification names (str) in alphabase format. diff --git a/alphabase/protein/inference.py b/alphabase/protein/inference.py index 4580c587..f84f7466 100644 --- a/alphabase/protein/inference.py +++ b/alphabase/protein/inference.py @@ -1,5 +1,3 @@ -__all__ = ['build_AC', 'match_AC'] - import ahocorasick def build_AC(peptides:list): diff --git a/alphabase/protein/lcp_digest.py b/alphabase/protein/lcp_digest.py index ce9c936e..75b68612 100644 --- a/alphabase/protein/lcp_digest.py +++ b/alphabase/protein/lcp_digest.py @@ -1,5 +1,3 @@ -__all__ = ['get_lcp_array', 'get_next_stop_char', 'get_all_substring_indices_from_lcp', 'get_substring_indices'] - import numba import numpy as np from pydivsufsort import divsufsort, kasai diff --git a/alphabase/psm_reader/__init__.py b/alphabase/psm_reader/__init__.py index bc3011da..2578af22 100644 --- a/alphabase/psm_reader/__init__.py +++ b/alphabase/psm_reader/__init__.py @@ -5,7 +5,7 @@ ) from alphabase.psm_reader.alphapept_reader import AlphaPeptReader from alphabase.psm_reader.dia_psm_reader import ( - DiannReader, SpectronautReader, SwathReader, + DiannReader, SpectronautReader, SwathReader, SpectronautReportReader ) from alphabase.psm_reader.maxquant_reader import MaxQuantReader from alphabase.psm_reader.pfind_reader import pFindReader diff --git a/alphabase/psm_reader/alphapept_reader.py b/alphabase/psm_reader/alphapept_reader.py index a5c1131f..f3ad8ce0 100644 --- a/alphabase/psm_reader/alphapept_reader.py +++ b/alphabase/psm_reader/alphapept_reader.py @@ -1,9 +1,3 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbdev_nbs/psm_reader/alphapept_reader.ipynb. - -# %% auto 0 -__all__ = ['parse_ap', 'get_x_tandem_score', 'AlphaPeptReader'] - -# %% ../../nbdev_nbs/psm_reader/alphapept_reader.ipynb 2 import numba import os import pandas as pd @@ -15,7 +9,6 @@ psm_reader_yaml ) -# %% ../../nbdev_nbs/psm_reader/alphapept_reader.ipynb 3 @numba.njit def parse_ap(precursor): """ diff --git a/alphabase/psm_reader/dia_psm_reader.py b/alphabase/psm_reader/dia_psm_reader.py index ec5ecacb..ac41c1b2 100644 --- a/alphabase/psm_reader/dia_psm_reader.py +++ b/alphabase/psm_reader/dia_psm_reader.py @@ -1,9 +1,3 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbdev_nbs/psm_reader/dia_psm_reader.ipynb. - -# %% auto 0 -__all__ = ['SpectronautReader', 'SwathReader', 'DiannReader', 'SpectronautReportReader'] - -# %% ../../nbdev_nbs/psm_reader/dia_psm_reader.ipynb 3 import pandas as pd import numpy as np @@ -15,7 +9,6 @@ MaxQuantReader ) -# %% ../../nbdev_nbs/psm_reader/dia_psm_reader.ipynb 4 class SpectronautReader(MaxQuantReader): """Reader for Spectronaut's output library TSV/CSV. @@ -33,8 +26,6 @@ def __init__(self, modification_mapping:dict = None, fdr = 0.01, keep_decoy = False, - mod_sep = '[]', - underscore_for_ncterm=True, fixed_C57 = False, mod_seq_columns=psm_reader_yaml[ 'spectronaut' @@ -47,8 +38,6 @@ def __init__(self, column_mapping=column_mapping, modification_mapping=modification_mapping, fdr=fdr, keep_decoy=keep_decoy, - mod_sep=mod_sep, - underscore_for_ncterm=underscore_for_ncterm, mod_seq_columns = mod_seq_columns, fixed_C57=fixed_C57, rt_unit=rt_unit, @@ -87,8 +76,6 @@ def __init__(self, modification_mapping:dict = None, fdr = 0.01, keep_decoy = False, - mod_sep = '()', - underscore_for_ncterm=False, fixed_C57 = False, mod_seq_columns=psm_reader_yaml[ 'spectronaut' @@ -103,15 +90,12 @@ def __init__(self, column_mapping=column_mapping, modification_mapping=modification_mapping, fdr=fdr, keep_decoy=keep_decoy, - mod_sep=mod_sep, - underscore_for_ncterm=underscore_for_ncterm, fixed_C57=fixed_C57, mod_seq_columns=mod_seq_columns, csv_sep=csv_sep, **kwargs, ) -# %% ../../nbdev_nbs/psm_reader/dia_psm_reader.ipynb 10 class DiannReader(SpectronautReader): def __init__(self, *, @@ -119,8 +103,6 @@ def __init__(self, modification_mapping:dict = None, fdr = 0.01, keep_decoy = False, - mod_sep = '()', - underscore_for_ncterm=False, fixed_C57 = False, csv_sep = '\t', rt_unit = 'minute', @@ -134,8 +116,6 @@ def __init__(self, column_mapping=column_mapping, modification_mapping=modification_mapping, fdr=fdr, keep_decoy=keep_decoy, - mod_sep=mod_sep, - underscore_for_ncterm=underscore_for_ncterm, fixed_C57=fixed_C57, csv_sep=csv_sep, rt_unit=rt_unit, @@ -167,7 +147,6 @@ def _load_file(self, filename): 'diann', DiannReader ) -# %% ../../nbdev_nbs/psm_reader/dia_psm_reader.ipynb 11 class SpectronautReportReader(MaxQuantReader): """Reader for Spectronaut's report TSV/CSV. @@ -185,8 +164,6 @@ def __init__(self, modification_mapping:dict = None, fdr = 0.01, keep_decoy = False, - mod_sep = '[]', - underscore_for_ncterm=True, fixed_C57 = False, csv_sep = ',', rt_unit = 'minute', @@ -196,8 +173,6 @@ def __init__(self, column_mapping=column_mapping, modification_mapping=modification_mapping, fdr=fdr, keep_decoy=keep_decoy, - mod_sep=mod_sep, - underscore_for_ncterm=underscore_for_ncterm, fixed_C57=fixed_C57, rt_unit=rt_unit, **kwargs, diff --git a/alphabase/psm_reader/maxquant_reader.py b/alphabase/psm_reader/maxquant_reader.py index 6fb37354..2cc5ee1a 100644 --- a/alphabase/psm_reader/maxquant_reader.py +++ b/alphabase/psm_reader/maxquant_reader.py @@ -1,9 +1,3 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbdev_nbs/psm_reader/maxquant_reader.ipynb. - -# %% auto 0 -__all__ = ['parse_mod_seq', 'MaxQuantReader'] - -# %% ../../nbdev_nbs/psm_reader/maxquant_reader.ipynb 2 import pandas as pd import numpy as np import numba @@ -14,13 +8,22 @@ psm_reader_yaml ) -# %% ../../nbdev_nbs/psm_reader/maxquant_reader.ipynb 3 +from alphabase.constants.modification import MOD_DF + +mod_to_unimod_dict = {} +for mod_name,unimod_id in MOD_DF[['mod_name','unimod_id']].values: + unimod_id = int(unimod_id) + if unimod_id==-1 or unimod_id=='-1': continue + if mod_name[-2]=='@': + mod_to_unimod_dict[mod_name] = f"{mod_name[-1]}(UniMod:{unimod_id})" + else: + mod_to_unimod_dict[mod_name] = f"_(UniMod:{unimod_id})" + @numba.njit def parse_mod_seq( modseq:str, mod_sep:str='()', fixed_C57:bool=True, - underscore_for_ncterm:bool=True, )->tuple: """Extract modifications and sites from the modified sequence (modseq) @@ -37,10 +40,6 @@ def parse_mod_seq( If Carbamidomethyl@C is a fixed modification and not displayed in the sequence. Defaults to True for MaxQuant. - underscore_for_ncterm : bool - If modseq starts and ends with underscores. - Defaults to True. - Returns ------- tuple @@ -50,6 +49,10 @@ def parse_mod_seq( 0 for N-term; -1 for C-term; 1 to N for normal modifications. """ PeptideModSeq = modseq + if modseq[0] == '_': + underscore_for_ncterm = True + else: + underscore_for_ncterm = False mod_list = [] site_list = [] site = PeptideModSeq.find(mod_sep[0]) @@ -94,8 +97,6 @@ def __init__(self, modification_mapping:dict = None, fdr = 0.01, keep_decoy = False, - mod_sep = '()', - underscore_for_ncterm=True, fixed_C57 = True, mod_seq_columns = ['Modified sequence'], **kwargs, @@ -120,16 +121,6 @@ def __init__(self, keep_decoy : bool, optional If keep decoy PSMs, by default False - mod_sep : str, optional - Symbols to separate modified sequences, - e.g. `AM(Oxidation)PIC(+57)QMK`. - By default '()' - - underscore_for_ncterm : bool, optional - If search engine uses an under score in N- and C-term, - `_(Acetyl)AM(Oxidation)PIC(+57)QMK_`. - by default True - fixed_C57 : bool, optional If true, the search engine will not show `Carbamidomethyl` in the modified sequences. @@ -147,8 +138,6 @@ def __init__(self, **kwargs, ) - self.mod_sep = mod_sep - self.underscore_for_ncterm = underscore_for_ncterm self.fixed_C57 = fixed_C57 self._mod_seq_columns = mod_seq_columns self.mod_seq_column = 'Modified sequence' @@ -169,9 +158,17 @@ def _init_modification_mapping(self): def set_modification_mapping(self, modification_mapping: dict): super().set_modification_mapping(modification_mapping) + self._add_all_unimod() self._extend_mod_brackets() self._reverse_mod_mapping() + def _add_all_unimod(self): + for mod_name, unimod in mod_to_unimod_dict.items(): + if mod_name in self.modification_mapping: + self.modification_mapping[mod_name].append(unimod) + else: + self.modification_mapping[mod_name] = [unimod] + def _extend_mod_brackets(self): for key, mod_list in list(self.modification_mapping.items()): extend_mods = [] @@ -209,15 +206,19 @@ def _load_file(self, filename): return df def _load_modifications(self, origin_df: pd.DataFrame): + if origin_df[self.mod_seq_column].str.contains('[',regex=False).any(): + mod_sep = '[]' + else: + mod_sep = '()' + ( seqs, self._psm_df['mods'], self._psm_df['mod_sites'] ) = zip( *origin_df[self.mod_seq_column].apply( - parse_mod_seq, mod_sep=self.mod_sep, + parse_mod_seq, mod_sep=mod_sep, fixed_C57=self.fixed_C57, - underscore_for_ncterm=self.underscore_for_ncterm ) ) if 'sequence' not in self._psm_df.columns: diff --git a/alphabase/psm_reader/msfragger_reader.py b/alphabase/psm_reader/msfragger_reader.py index f4f71e71..50c0a7f6 100644 --- a/alphabase/psm_reader/msfragger_reader.py +++ b/alphabase/psm_reader/msfragger_reader.py @@ -1,9 +1,3 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbdev_nbs/psm_reader/msfragger_reader.ipynb. - -# %% auto 0 -__all__ = ['mass_mapped_mods', 'mod_mass_tol', 'MSFragger_PSM_TSV_Reader'] - -# %% ../../nbdev_nbs/psm_reader/msfragger_reader.ipynb 2 import numpy as np import pandas as pd @@ -11,9 +5,9 @@ PSMReaderBase, psm_reader_yaml, psm_reader_provider ) -from .maxquant_reader import MaxQuantReader -from ..constants.aa import AA_ASCII_MASS -from ..constants.modification import MOD_INFO_DICT as mod_info +from alphabase.psm_reader.maxquant_reader import MaxQuantReader +from alphabase.constants.aa import AA_ASCII_MASS +from alphabase.constants.modification import MOD_INFO_DICT as mod_info #| export try: @@ -22,7 +16,6 @@ pepxml = None -# %% ../../nbdev_nbs/psm_reader/msfragger_reader.ipynb 3 def _is_fragger_decoy(proteins): for prot in proteins: if not prot.startswith('rev_'): @@ -63,7 +56,6 @@ def _get_msf_mods(sequence, msf_aa_mods): return ';'.join(mods), ';'.join(mod_sites), ';'.join(mod_deltas), ';'.join(mod_delta_sites) -# %% ../../nbdev_nbs/psm_reader/msfragger_reader.ipynb 4 class MSFragger_PSM_TSV_Reader(PSMReaderBase): def __init__(self, *, column_mapping: dict = None, @@ -78,7 +70,6 @@ def __init__(self, *, psm_reader_provider.register_reader('msfragger_psm_tsv', MSFragger_PSM_TSV_Reader) psm_reader_provider.register_reader('msfragger', MSFragger_PSM_TSV_Reader) -# %% ../../nbdev_nbs/psm_reader/msfragger_reader.ipynb 5 if pepxml is None: class MSFraggerPepXML: def __init__(self): raise NotImplementedError("") diff --git a/alphabase/psm_reader/pfind_reader.py b/alphabase/psm_reader/pfind_reader.py index 5deaf7f6..5b19b38b 100644 --- a/alphabase/psm_reader/pfind_reader.py +++ b/alphabase/psm_reader/pfind_reader.py @@ -1,9 +1,3 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbdev_nbs/psm_reader/pfind_reader.ipynb. - -# %% auto 0 -__all__ = ['convert_one_pFind_mod', 'translate_pFind_mod', 'get_pFind_mods', 'parse_pfind_protein', 'pFindReader'] - -# %% ../../nbdev_nbs/psm_reader/pfind_reader.ipynb 3 import pandas as pd import numpy as np @@ -14,7 +8,6 @@ psm_reader_yaml ) -# %% ../../nbdev_nbs/psm_reader/pfind_reader.ipynb 4 def convert_one_pFind_mod(mod): if mod[-1] == ')': mod = mod[:(mod.find('(')-1)] @@ -87,7 +80,6 @@ def parse_pfind_protein(protein, keep_reverse=True): ) -# %% ../../nbdev_nbs/psm_reader/pfind_reader.ipynb 6 class pFindReader(PSMReaderBase): def __init__(self, *, diff --git a/alphabase/psm_reader/psm_reader.py b/alphabase/psm_reader/psm_reader.py index ceeeeb01..51d08f31 100644 --- a/alphabase/psm_reader/psm_reader.py +++ b/alphabase/psm_reader/psm_reader.py @@ -1,19 +1,11 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbdev_nbs/psm_reader/psm_reader.ipynb. - -# %% auto 0 -__all__ = ['psm_reader_yaml', 'psm_reader_provider', 'translate_other_modification', 'keep_modifications', 'PSMReaderBase', - 'PSMReaderProvider'] - -# %% ../../nbdev_nbs/psm_reader/psm_reader.ipynb 3 import pandas as pd import numpy as np import alphabase.peptide.mobility as mobility from alphabase.peptide.precursor import ( update_precursor_mz, reset_precursor_df ) -from ..constants._const import CONST_FILE_FOLDER +from alphabase.constants._const import CONST_FILE_FOLDER -# %% ../../nbdev_nbs/psm_reader/psm_reader.ipynb 4 def translate_other_modification( mod_str: str, mod_dict: dict @@ -73,8 +65,7 @@ def keep_modifications( return mod_str -# %% ../../nbdev_nbs/psm_reader/psm_reader.ipynb 6 -from ..yaml_utils import load_yaml +from alphabase.yaml_utils import load_yaml import os import copy @@ -85,7 +76,6 @@ def keep_modifications( ) ) -# %% ../../nbdev_nbs/psm_reader/psm_reader.ipynb 8 class PSMReaderBase(object): def __init__(self, *, @@ -110,9 +100,9 @@ def __init__(self, `self._init_column_mapping`. The dict values could be either str or list, for exaplme: columns_mapping = { - 'sequence': 'NakedSequence', #str - 'charge': 'Charge', #str - 'proteins':['Proteins','UniprotIDs'], # list, this reader will automatically detect all of them. + 'sequence': 'NakedSequence', #str + 'charge': 'Charge', #str + 'proteins':['Proteins','UniprotIDs'], # list, this reader will automatically detect all of them. } Defaults to None. modification_mapping : dict, optional @@ -121,8 +111,8 @@ def __init__(self, `self._init_modification_mapping`. The dict values could be either str or list, for exaplme: modification_mapping = { - 'Oxidation@M': 'Oxidation (M)', # str - 'Phospho@S': ['S(Phospho (STY))','S(ph)','pS'], # list, this reader will automatically detect all of them. + 'Oxidation@M': 'Oxidation (M)', # str + 'Phospho@S': ['S(Phospho (STY))','S(ph)','pS'], # list, this reader will automatically detect all of them. } Defaults to None. fdr : float, optional @@ -172,13 +162,39 @@ def psm_df(self)->pd.DataFrame: return self._psm_df def add_modification_mapping(self, modification_mapping:dict): + """ + Append additional modifications from other search engines + + Parameters + ---------- + modification_mapping : dict + The key of dict is a modification name in AlphaBase format; + the value could be a str or a list, see below + ``` + add_modification_mapping({ + 'Dimethyl@K': ['K(Dimethyl)'], # list + 'Dimethyl@Any N-term': '_(Dimethyl)', # str + }) + ``` + """ if ( modification_mapping is None or - len(modification_mapping) == 0 + len(modification_mapping) == 0 ): return - - self.modification_mapping.update(modification_mapping) + + for key, val in list(modification_mapping.items()): + if key in self.modification_mapping: + if isinstance(val, str): + self.modification_mapping[key].append(val) + else: + self.modification_mapping[key].extend(val) + else: + if isinstance(val, str): + self.modification_mapping[key] = [val] + else: + self.modification_mapping[key] = val + self.set_modification_mapping(self.modification_mapping) def set_modification_mapping(self, modification_mapping:dict): @@ -211,6 +227,9 @@ def _reverse_mod_mapping(self): ) in self.modification_mapping.items(): if isinstance(other_mod, (list, tuple)): for _mod in other_mod: + if _mod in self.rev_mod_mapping: + if this_mod.endswith('Protein N-term'): + continue self.rev_mod_mapping[_mod] = this_mod else: self.rev_mod_mapping[other_mod] = this_mod @@ -220,11 +239,21 @@ def _init_column_mapping(self): f'"{self.__class__}" must implement "_init_column_mapping()"' ) - def load(self, _file): + def load(self, _file)->pd.DataFrame: """ Wrapper for import_file() """ - return self.import_file(_file) + if isinstance(_file, list): + return self.import_files(_file) + else: + return self.import_file(_file) + + def import_files(self, file_list:list): + df_list = [] + for _file in file_list: + df_list.append(self.import_file(_file)) + self._psm_df = pd.concat(df_list, ignore_index=True) + return self._psm_df - def import_file(self, _file:str): + def import_file(self, _file:str)->pd.DataFrame: """ This is the main entry function of PSM readers, it imports the file with following steps: @@ -461,7 +490,6 @@ def filter_psm_by_modifications(self, include_mod_set = set([ self._psm_df.reset_index(drop=True, inplace=True) -# %% ../../nbdev_nbs/psm_reader/psm_reader.ipynb 18 class PSMReaderProvider: def __init__(self): self.reader_dict = {} @@ -491,3 +519,6 @@ def get_reader_by_yaml(self, ) psm_reader_provider = PSMReaderProvider() +""" +A factory :class:`PSMReaderProvider` object to register and get readers for different PSM types. +""" diff --git a/alphabase/scoring/__init__.py b/alphabase/scoring/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/alphabase/scoring/fdr.py b/alphabase/scoring/fdr.py new file mode 100644 index 00000000..5817e52a --- /dev/null +++ b/alphabase/scoring/fdr.py @@ -0,0 +1,161 @@ +import numba +import numpy as np +import pandas as pd + +@numba.njit +def fdr_to_q_values( + fdr_values:np.ndarray +)->np.ndarray: + """convert FDR values to q_values. + + Parameters + ---------- + fdr_values : np.ndarray + FDR values, they should be + sorted according to the descending order of the `score` + + Returns + ------- + np.ndarray + q_values + + """ + q_values = np.zeros_like(fdr_values) + min_q_value = np.max(fdr_values) + for i in range(len(fdr_values) - 1, -1, -1): + fdr = fdr_values[i] + if fdr < min_q_value: + min_q_value = fdr + q_values[i] = min_q_value + return q_values + +def calculate_fdr( + df:pd.DataFrame, + score_column:str, + decoy_column:str='decoy' +)->pd.DataFrame: + """Calculate FDR values (q_values in fact) for the given dataframe + + Parameters + ---------- + df : pd.DataFrame + PSM dataframe to calculate FDRs + + score_column : str + score column to sort in decending order + + decoy_column : str, optional + decoy column in the dataframe. + 1=target, 0=decoy. Defaults to 'decoy'. + + Returns + ------- + pd.DataFrame + PSM dataframe with 'fdr' column added + + """ + df = df.reset_index(drop=True).sort_values( + [score_column,decoy_column], ascending=False + ) + target_values = 1-df[decoy_column].values + decoy_cumsum = np.cumsum(df[decoy_column].values) + target_cumsum = np.cumsum(target_values) + fdr_values = decoy_cumsum/target_cumsum + df['fdr'] = fdr_to_q_values(fdr_values) + return df + +#wrapper +calc_fdr_for_df = calculate_fdr + +@numba.njit +def fdr_from_ref( + sorted_scores:np.ndarray, + ref_scores:np.ndarray, + ref_fdr_values:np.ndarray +)->np.ndarray: + """ Calculate FDR values from the given reference scores and fdr_values. + It is used to extend peptide-level or sequence-level FDR (reference) + to each PSM, as PSMs are more useful for quantification. + + Parameters + ---------- + sorted_scores : np.array + the scores to calculate FDRs, + they must be sorted in decending order. + + ref_scores : np.array + reference scores that used to + calculate ref_fdr_values, also sorted in decending order. + + ref_fdr_values : np.array + fdr values corresponding to ref_scores + + Returns + ------- + np.array + fdr values corresponding to sorted_scores. + + """ + q_values = np.zeros_like(sorted_scores) + i,j = 0,0 + while i < len(sorted_scores) and j < len(ref_scores): + if sorted_scores[i] >= ref_scores[j]: + q_values[i] = ref_fdr_values[j] + i += 1 + else: + j += 1 + while i < len(sorted_scores): + q_values[i] = ref_fdr_values[-1] + i += 1 + return q_values + +def calculate_fdr_from_ref( + df: pd.DataFrame, + ref_scores:np.ndarray, + ref_fdr_values:np.ndarray, + score_column:str, + decoy_column:str='decoy' +)->pd.DataFrame: + """ Calculate FDR values for a PSM dataframe from the given reference + scores and fdr_values. It is used to extend peptide-level or + sequence-level FDR (reference) to each PSM, as PSMs are more useful + for quantification. + `` + + Parameters + ---------- + df : pd.DataFrame + PSM dataframe + + ref_scores : np.array + reference scores that used to + calculate ref_fdr_values, also sorted in decending order. + + ref_fdr_values : np.array + fdr values corresponding to ref_scores + + score_column : str + score column in the dataframe + + decoy_column : str, optional + decoy column in the dataframe. + 1=target, 0=decoy. Defaults to 'decoy'. + + Returns + ------- + pd.DataFrame + dataframe with 'fdr' column added + + """ + df = df.reset_index(drop=True).sort_values( + [score_column,decoy_column], ascending=False + ) + sorted_idxes = np.argsort(ref_fdr_values) + ref_scores = ref_scores[sorted_idxes] + ref_q_values = ref_fdr_values[sorted_idxes] + df['fdr'] = fdr_from_ref( + df.score.values, ref_scores, ref_q_values + ) + return df + +calc_fdr_from_ref_for_df = calculate_fdr_from_ref diff --git a/alphabase/scoring/feature_extraction_base.py b/alphabase/scoring/feature_extraction_base.py new file mode 100644 index 00000000..73c7d683 --- /dev/null +++ b/alphabase/scoring/feature_extraction_base.py @@ -0,0 +1,61 @@ +import pandas as pd + +class BaseFeatureExtractor: + def __init__(self): + self._feature_list = ['score','nAA','charge'] + + @property + def feature_list(self)->list: + """ + This is a property. It tells ML scoring modules + what features (columns) are extracted by + this FeatureExtractor for scoring. + + Returns + ------- + list + feature names (columns) in the PSM dataframe + """ + + self._feature_list = list(set(self._feature_list)) + return self._feature_list + + def extract_features(self, + psm_df:pd.DataFrame, + *args, **kwargs + )->pd.DataFrame: + """ + Extract the scoring features (self._feature_list) + and append them inplace into candidate PSMs (psm_df). + + **All sub-classes must re-implement this method.** + + Parameters + ---------- + psm_df : pd.DataFrame + PSMs to be rescored + + Returns + ------- + pd.DataFrame + psm_df with appended feature columns extracted by this extractor + """ + return psm_df + + def update_features(self,psm_df:pd.DataFrame)->pd.DataFrame: + """ + This method allow us to update adaptive features + during the iteration of Percolator algorithm + + Parameters + ---------- + psm_df : pd.DataFrame + psm_df + + Returns + ------- + pd.DataFrame + psm_df with updated feature values + """ + return psm_df + diff --git a/alphabase/scoring/ml_scoring_base.py b/alphabase/scoring/ml_scoring_base.py new file mode 100644 index 00000000..3491eeb4 --- /dev/null +++ b/alphabase/scoring/ml_scoring_base.py @@ -0,0 +1,361 @@ +import pandas as pd +import numpy as np + +from sklearn.linear_model import LogisticRegression +from sklearn.base import BaseEstimator + +from alphabase.scoring.feature_extraction_base import BaseFeatureExtractor +from alphabase.scoring.fdr import ( + calculate_fdr, + calculate_fdr_from_ref, + fdr_to_q_values, + fdr_from_ref, +) + +class Percolator: + def __init__(self): + self._feature_extractor:BaseFeatureExtractor = BaseFeatureExtractor() + self._ml_model = LogisticRegression() + + self.fdr_level = 'psm' # psm, precursor, peptide, or sequence + self.training_fdr = 0.01 + self.per_raw_fdr = False + + self.max_training_sample = 200000 + self.min_training_sample = 100 + self.cv_fold = 1 + self.iter_num = 1 + + self._base_features = ['score','nAA','charge'] + + @property + def feature_list(self)->list: + """ Get extracted feature_list. Property, read-only """ + return list(set( + self._base_features+ + self.feature_extractor.feature_list + )) + + @property + def ml_model(self): + """ + ML model in Percolator. + It can be sklearn models or other models but implement + the methods `fit()` and `decision_function()` (or `predict_proba()`) + which are the same as sklearn models. + """ + return self._ml_model + + @ml_model.setter + def ml_model(self, model): + self._ml_model = model + + @property + def feature_extractor(self)->BaseFeatureExtractor: + """ + The feature extractor inherited from `BaseFeatureExtractor` + """ + return self._feature_extractor + + @feature_extractor.setter + def feature_extractor(self, fe:BaseFeatureExtractor): + self._feature_extractor = fe + + def extract_features(self, + psm_df:pd.DataFrame, + *args, **kwargs + )->pd.DataFrame: + """ + Extract features for rescoring. + + *args and **kwargs are used for + `self.feature_extractor.extract_features`. + + Parameters + ---------- + psm_df : pd.DataFrame + PSM DataFrame + + Returns + ------- + pd.DataFrame + psm_df with feature columns appended inplace. + """ + psm_df['ml_score'] = psm_df.score + psm_df = self._estimate_psm_fdr(psm_df) + return self._feature_extractor.extract_features( + psm_df, *args, **kwargs + ) + + def rescore(self, + df:pd.DataFrame + )->pd.DataFrame: + """ + Estimate ML scores and then FDRs (q-values) + + Parameters + ---------- + df : pd.DataFrame + psm_df + + Returns + ------- + pd.DataFrame + psm_df with `ml_score` and `fdr` columns updated inplace + """ + for i in range(self.iter_num): + df = self._cv_score(df) + df = self._estimate_fdr(df, 'psm', False) + df = self.feature_extractor.update_features(df) + df = self._estimate_fdr(df) + return df + + def run_rerank_workflow(self, + top_k_psm_df:pd.DataFrame, + rerank_column:str='spec_idx', + *args, **kwargs + )->pd.DataFrame: + """ + Run percolator workflow with reranking + the peptides for each spectrum. + + - self.extract_features() + - self.rescore() + + *args and **kwargs are used for + `self.feature_extractor.extract_features`. + + Parameters + ---------- + top_k_psm_df : pd.DataFrame + PSM DataFrame + + rerank_column : str + The column use to rerank PSMs. + + For example, use the following code to select + the top-ranked peptide for each spectrum. + ``` + rerank_column = 'spec_idx' # scan_num + idx = top_k_psm_df.groupby(['raw_name',rerank_column])['ml_score'].idxmax() + psm_df = top_k_psm_df.loc[idx].copy() + ``` + Returns + ------- + pd.DataFrame + Only top-scored PSM is returned for + each group of the `rerank_column`. + """ + top_k_psm_df = self.extract_features( + top_k_psm_df, *args, **kwargs + ) + idxmax = top_k_psm_df.groupby( + ['raw_name',rerank_column] + )['ml_score'].idxmax() + + df = top_k_psm_df.loc[idxmax].copy() + self._train_and_score(df) + + top_k_psm_df = self._predict(top_k_psm_df) + idxmax = top_k_psm_df.groupby( + ['raw_name',rerank_column] + )['ml_score'].idxmax() + return top_k_psm_df.loc[idxmax].copy() + + def run_rescore_workflow(self, + psm_df:pd.DataFrame, + *args, **kwargs + )->pd.DataFrame: + """ + Run percolator workflow: + + - self.extract_features() + - self.rescore() + + *args and **kwargs are used for + `self.feature_extractor.extract_features`. + + Parameters + ---------- + psm_df : pd.DataFrame + PSM DataFrame + + Returns + ------- + pd.DataFrame + psm_df with feature columns appended inplace. + """ + df = self.extract_features( + psm_df, *args, **kwargs + ) + return self.rescore(df) + + def _estimate_fdr_per_raw(self, + df:pd.DataFrame, + fdr_level:str + )->pd.DataFrame: + df_list = [] + for raw_name, df_raw in df.groupby('raw_name'): + df_list.append(self._estimate_fdr(df_raw, + fdr_level = fdr_level, + per_raw_fdr = False + )) + return pd.concat(df_list, ignore_index=True) + + def _estimate_psm_fdr(self, + df:pd.DataFrame, + )->pd.DataFrame: + return calculate_fdr(df, 'ml_score', 'decoy') + + def _estimate_fdr(self, + df:pd.DataFrame, + fdr_level:str=None, + per_raw_fdr:bool=None, + )->pd.DataFrame: + if fdr_level is None: + fdr_level = self.fdr_level + if per_raw_fdr is None: + per_raw_fdr = self.per_raw_fdr + + if per_raw_fdr: + return self._estimate_fdr_per_raw( + df, fdr_level=fdr_level + ) + + if fdr_level == 'psm': + return self._estimate_psm_fdr(df) + else: + if fdr_level == 'precursor': + _df = df.groupby([ + 'sequence','mods','mod_sites','charge','decoy' + ])['ml_score'].max() + elif fdr_level == 'peptide': + _df = df.groupby([ + 'sequence','mods','mod_sites','decoy' + ])['ml_score'].max() + else: + _df = df.groupby(['sequence','decoy'])['ml_score'].max() + _df = self._estimate_psm_fdr(_df) + df['fdr'] = fdr_from_ref( + df['ml_score'].values, _df['ml_score'].values, + _df['fdr'].values + ) + return df + + def _train(self, + train_t_df:pd.DataFrame, + train_d_df:pd.DataFrame + ): + train_t_df = train_t_df[train_t_df.fdr<=self.training_fdr] + + if len(train_t_df) > self.max_training_sample: + train_t_df = train_t_df.sample( + n=self.max_training_sample, + random_state=1337 + ) + if len(train_d_df) > self.max_training_sample: + train_d_df = train_d_df.sample( + n=self.max_training_sample, + random_state=1337 + ) + + train_df = pd.concat((train_t_df, train_d_df)) + train_label = np.ones(len(train_df),dtype=np.int8) + train_label[len(train_t_df):] = 0 + + self._ml_model.fit( + train_df[self.feature_list].values, + train_label + ) + + def _predict(self, test_df): + try: + test_df['ml_score'] = self._ml_model.decision_function( + test_df[self.feature_list].values + ) + except AttributeError: + test_df['ml_score'] = self._ml_model.predict_proba( + test_df[self.feature_list].values + ) + return test_df + + def _train_and_score(self, + df:pd.DataFrame + )->pd.DataFrame: + + df_target = df[df.decoy == 0] + df_decoy = df[df.decoy != 0] + + if ( + np.sum(df_target.fdr<=self.training_fdr) < + self.min_training_sample or + len(df_decoy) < self.min_training_sample + ): + return df + + self._train(df_target, df_decoy) + test_df = pd.concat( + [df_target, df_decoy], + ignore_index=True + ) + + return self._predict(test_df) + + def _cv_score(self, df:pd.DataFrame)->pd.DataFrame: + """ + Apply cross-validation for rescoring. + + It will split `df` into K folds. For each fold, + its ML scores are predicted by a model which + is trained by other K-1 folds . + + Parameters + ---------- + df : pd.DataFrame + PSMs to be rescored + + Returns + ------- + pd.DataFrame + PSMs after rescoring + """ + + if self.cv_fold <= 1: + return self._train_and_score(df) + + df = df.sample( + frac=1, random_state=1337 + ).reset_index(drop=True) + + df_target = df[df.decoy == 0] + df_decoy = df[df.decoy != 0] + + if ( + np.sum(df_target.fdr<=self.training_fdr) < + self.min_training_sample*self.cv_fold + or len(df_decoy) < + self.min_training_sample*self.cv_fold + ): + return df + + test_df_list = [] + for i in range(self.cv_fold): + t_mask = np.ones(len(df_target), dtype=bool) + _slice = slice(i, len(df_target), self.cv_fold) + t_mask[_slice] = False + train_t_df = df_target[t_mask] + test_t_df = df_target[_slice] + + d_mask = np.ones(len(df_decoy), dtype=bool) + _slice = slice(i, len(df_decoy), self.cv_fold) + d_mask[_slice] = False + train_d_df = df_decoy[d_mask] + test_d_df = df_decoy[_slice] + + self._train(train_t_df, train_d_df) + + test_df = pd.concat((test_t_df, test_d_df)) + test_df_list.append(self._predict(test_df)) + + return pd.concat(test_df_list, ignore_index=True) + diff --git a/alphabase/spectral_library/library_base.py b/alphabase/spectral_library/base.py similarity index 58% rename from alphabase/spectral_library/library_base.py rename to alphabase/spectral_library/base.py index 5858bd87..af9ebb5e 100644 --- a/alphabase/spectral_library/library_base.py +++ b/alphabase/spectral_library/base.py @@ -1,19 +1,51 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbdev_nbs/spectral_library/library_base.ipynb. - -# %% auto 0 -__all__ = ['SpecLibBase'] - -# %% ../../nbdev_nbs/spectral_library/library_base.ipynb 2 import pandas as pd import numpy as np import typing +import logging import alphabase.peptide.fragment as fragment import alphabase.peptide.precursor as precursor -from ..io.hdf import HDF_File +from alphabase.io.hdf import HDF_File -# %% ../../nbdev_nbs/spectral_library/library_base.ipynb 3 class SpecLibBase(object): + """ + Base spectral library in alphabase and alphapeptdeep. + + Attributes + ---------- + charged_frag_types : list + same as `charged_frag_types` in Parameters in :meth:`__init__`. + + min_precursor_mz : float + same as `precursor_mz_min` in Parameters in :meth:`__init__`. + + max_precursor_mz : float + same as `precursor_mz_max` in Parameters in :meth:`__init__`. + + decoy : str + same as `decoy` in Parameters in :meth:`__init__`. + """ + + key_numeric_columns:list = [ + 'ccs_pred', 'charge', + 'decoy', + 'frag_end_idx', 'frag_start_idx', + 'isotope_m1_intensity', 'isotope_m1_mz', + 'isotope_apex_mz', 'isotope_apex_intensity', + 'isotope_apex_offset', + 'isotope_right_most_mz', 'isotope_right_most_intensity', + 'isotope_right_most_offset', + 'miss_cleavage', 'mobility_pred', + 'nAA', + 'precursor_mz', + 'rt_pred', 'rt_norm_pred' + ] + """ + list of str: Key numeric columns to be saved + into library/precursor_df in the hdf file for fast loading, + others will be saved into library/mod_seq_df instead. + """ + def __init__(self, # ['b_z1','b_z2','y_z1','y_modloss_z1', ...]; # 'b_z1': 'b' is the fragment type and @@ -24,8 +56,7 @@ def __init__(self, precursor_mz_min = 400, precursor_mz_max = 6000, decoy:str = None, ): - """Base spectral library in alphabase and alphapeptdeep. - + """ Parameters ---------- charged_frag_types : typing.List[str], optional @@ -43,35 +74,6 @@ def __init__(self, decoy : str, optional Decoy methods, could be "pseudo_reverse" or "diann". Defaults to None. - - Attributes - ---------- - precursor_df : pd.DataFrame - precursor dataframe. - - fragment_mz_df : pd.DataFrame - fragment m/z dataframe. - - fragment_intensity_df : pd.DataFrame - fragment intensity dataframe. - - charged_frag_types : list - same as `charged_frag_types` in Args. - - min_precursor_mz : float - same as `precursor_mz_min` in Args. - - max_precursor_mz : float - same as `precursor_mz_max` in Args. - - decoy : str - same as `decoy` in Args. - - key_numeric_columns : list of str - key numeric columns to be saved - into library/precursor_df in the hdf file. Others will be saved into - library/mod_seq_df instead. - """ self.charged_frag_types = charged_frag_types self._precursor_df = pd.DataFrame() @@ -80,27 +82,14 @@ def __init__(self, self.min_precursor_mz = precursor_mz_min self.max_precursor_mz = precursor_mz_max - self.key_numeric_columns = [ - 'ccs_pred', 'charge', - 'decoy', - 'frag_end_idx', 'frag_start_idx', - 'isotope_m1_intensity', 'isotope_m1_mz', - 'isotope_apex_mz', 'isotope_apex_intensity', - 'isotope_apex_index', - 'isotope_right_most_mz', 'isotope_right_most_intensity', - 'isotope_right_most_index', - 'miss_cleavage', 'mobility_pred', - 'nAA', - 'precursor_mz', - 'rt_pred', 'rt_norm_pred' - ] self.decoy = decoy @property def precursor_df(self)->pd.DataFrame: - """: pd.DataFrame : precursor dataframe with columns - 'sequence', 'mods', 'mod_sites', 'charge', ... - Identical to `self.peptide_df`. + """ + Precursor dataframe with columns + 'sequence', 'mods', 'mod_sites', 'charge', etc, + identical to :attr:`peptide_df`. """ return self._precursor_df @@ -115,9 +104,10 @@ def precursor_df(self, df:pd.DataFrame): @property def peptide_df(self)->pd.DataFrame: - """: pd.DataFrame : peptide dataframe with columns - 'sequence', 'mods', 'mod_sites', 'charge', ... - Identical to `self.precursor_df`. + """ + Peptide dataframe with columns + 'sequence', 'mods', 'mod_sites', 'charge', etc, + identical to :attr:`precursor_df`. """ return self._precursor_df @@ -127,39 +117,39 @@ def peptide_df(self, df:pd.DataFrame): @property def fragment_mz_df(self)->pd.DataFrame: - """: pd.DataFrame : The fragment mz dataframe with + """ + The fragment mz dataframe with fragment types as columns (['b_z1', 'y_z2', ...]) """ return self._fragment_mz_df @property def fragment_intensity_df(self)->pd.DataFrame: - """: pd.DataFrame : The fragment intensity dataframe with + """ + The fragment intensity dataframe with fragment types as columns (['b_z1', 'y_z2', ...]) """ return self._fragment_intensity_df def refine_df(self): - """Sort nAA and reset_index for faster calculation (or prediction) + """ + Sort nAA and reset_index for faster calculation (or prediction) """ precursor.refine_precursor_df( self._precursor_df ) def append_decoy_sequence(self): - """Append decoy sequence into precursor_df. + """ + Append decoy sequence into precursor_df. Decoy method is based on self.decoy(str). ``` - decoy_lib = ( - decoy_lib_provider.get_decoy_lib( - self.decoy, self - ) - ) - decoy_lib.decoy_sequence() + >>> decoy_lib = (decoy_lib_provider.get_decoy_lib( self.decoy, self)) + >>> decoy_lib.decoy_sequence() ... ``` """ - from alphabase.spectral_library.decoy_library import ( + from alphabase.spectral_library.decoy import ( decoy_lib_provider ) decoy_lib = ( @@ -189,32 +179,6 @@ def clip_by_precursor_mz_(self): ) self._precursor_df.reset_index(drop=True, inplace=True) - - def flatten_fragment_data( - self - )->typing.Tuple[np.ndarray, np.ndarray]: - ''' - Create flattened (1-D) np.ndarray for fragment mz and intensity - dataframes, respectively. The arrays are references to - original data, that means: - 1. This method is fast; - 2. Changing the array values will change the df values. - They can be unraveled back using: - `array.reshape(len(self._fragment_mz_df.columns), -1)` - - Returns - ------- - Tuple[np.ndarray, np.ndarray] - np.ndarray. 1-D flattened mz array (a reference to - original fragment mz df data) - np.ndarray. 1-D flattened intensity array (a reference to - original fragment intensity df data) - ''' - return ( - self._fragment_mz_df.values.reshape(-1), - self._fragment_intensity_df.values.reshape(-1) - ) - def calc_precursor_mz(self): """ Calculate precursor mz for self._precursor_df, @@ -234,7 +198,7 @@ def calc_precursor_isotope(self, multiprocessing:bool=True, mp_process_num:int=8, mp_process_bar=None, - min_num_for_mp:int=1000, + min_precursor_num_to_run_mp:int=1000, ): """ Append isotope columns into self.precursor_df. @@ -243,7 +207,7 @@ def calc_precursor_isotope(self, if 'precursor_mz' not in self._precursor_df.columns: self.calc_precursor_mz() self.clip_by_precursor_mz_() - if multiprocessing and len(self.precursor_df)>min_num_for_mp: + if multiprocessing and len(self.precursor_df)>min_precursor_num_to_run_mp: ( self._precursor_df ) = precursor.calc_precursor_isotope_mp( @@ -263,8 +227,6 @@ def calc_fragment_mz_df(self): TODO: use multiprocessing here or in the `create_fragment_mz_dataframe` function. """ - if 'frag_start_idx' in self.precursor_df.columns: - return if ( self.charged_frag_types is not None or len(self.charged_frag_types) @@ -275,13 +237,61 @@ def calc_fragment_mz_df(self): self.precursor_df, self.charged_frag_types, ) else: - print('Skip fragment calculation as fragment type is None') + print('Skip fragment calculation as self.charged_frag_types is None or empty') def hash_precursor_df(self): """Insert hash codes for peptides and precursors""" precursor.hash_precursor_df( self._precursor_df ) + + def annotate_fragments_from_speclib(self, + donor_speclib, + verbose = True + ): + """ + Annotate self.precursor_df with fragments from donor_speclib. + The donor_speclib must have a fragment_mz_df and can optionally have a fragment_intensity_df. + Fragment dataframes are updated inplace and overwritten. + + Parameters + ---------- + donor_speclib : SpecLibBase + The donor library to annotate fragments from. + + verbose : bool, optional + Print progress, by default True, for example:: + + 2022-12-16 00:52:08> Speclib with 4 precursors will be reannotated with speclib with 12 precursors and 504 fragments + 2022-12-16 00:52:08> A total of 4 precursors were succesfully annotated, 0 precursors were not matched + + + """ + self = annotate_fragments_from_speclib( + self, donor_speclib, verbose = verbose + ) + + def remove_unused_fragments(self): + """ + Remove unused fragments from self._fragment_mz_df and self._fragment_intensity_df. + Fragment dataframes are updated inplace and overwritten. + """ + + + if len(self._fragment_mz_df) > 0: + + # update both fragment mz and intensity df + if len(self.fragment_intensity_df > 0): + self._precursor_df,(self._fragment_mz_df, self._fragment_intensity_df) = fragment.remove_unused_fragments( + self._precursor_df,(self._fragment_mz_df, self._fragment_intensity_df) + ) + # only update fragment mz df + else: + (self._precursor_df, (self._fragment_mz_df,)) = fragment.remove_unused_fragments( + self._precursor_df, (self._fragment_mz_df,) + ) + + def _get_hdf_to_save(self, hdf_file, @@ -342,19 +352,20 @@ def load_df_from_hdf(self, def save_hdf(self, hdf_file:str): """Save library dataframes into hdf_file. - For `self.precursor_df`, this method will save it into two hdf groups: - hdf_file: `library/precursor_df` and `library/mod_seq_df`. + For `self.precursor_df`, this method will save it into two hdf groups in hdf_file: + `library/precursor_df` and `library/mod_seq_df`. `library/precursor_df` contains all essential numberic columns those can be loaded faster from hdf file into memory: - 'precursor_mz', 'charge', 'mod_seq_hash', 'mod_seq_charge_hash', - 'frag_start_idx', 'frag_end_idx', 'decoy', 'rt_pred', 'ccs_pred', - 'mobility_pred', 'miss_cleave', 'nAA', - ['isotope_mz_m1', 'isotope_intensity_m1'], ... + + 'precursor_mz', 'charge', 'mod_seq_hash', 'mod_seq_charge_hash', + 'frag_start_idx', 'frag_end_idx', 'decoy', 'rt_pred', 'ccs_pred', + 'mobility_pred', 'miss_cleave', 'nAA', + ['isotope_mz_m1', 'isotope_intensity_m1'], ... `library/mod_seq_df` contains all string columns and the other not essential columns: - 'sequence','mods','mod_sites', ['proteins', 'genes']... + 'sequence','mods','mod_sites', ['proteins', 'genes']... as well as 'mod_seq_hash', 'mod_seq_charge_hash' columns to map back to `precursor_df` @@ -438,3 +449,66 @@ def load_hdf(self, hdf_file:str, load_mod_seq:bool=False): ] ] +def annotate_fragments_from_speclib( + speclib: SpecLibBase, + fragment_speclib: SpecLibBase, + verbose = True, +)->SpecLibBase: + """Reannotate an SpecLibBase library with fragments from a different SpecLibBase. + + Parameters + ---------- + speclib: alphabase.spectral_library.library_base.SpecLibBase + Spectral library which contains the precursors to be annotated. All fragments mz and fragment intensities will be removed. + + fragment_speclib: alphabase.spectral_library.library_base.SpecLibBase + Spectral library which contains the donor precursors whose fragments should be used. + + Returns + ------- + + alphabase.spectral_library.library_base.SpecLibBase + newly annotated spectral library + + """ + if verbose: + num_precursor_left = len(speclib.precursor_df) + num_precursor_right = len(fragment_speclib.precursor_df) + num_fragments_right = len(fragment_speclib.fragment_mz_df) * len(fragment_speclib.fragment_mz_df.columns) + logging.info(f'Speclib with {num_precursor_left:,} precursors will be reannotated with speclib with {num_precursor_right:,} precursors and {num_fragments_right:,} fragments') + + # reannotation is based on mod_seq_hash column + hash_column_name = 'mod_seq_hash' + + # create hash columns if missing + if hash_column_name not in speclib.precursor_df.columns: + speclib.hash_precursor_df() + + if fragment_speclib not in fragment_speclib.precursor_df.columns: + fragment_speclib.hash_precursor_df() + + speclib_hash = speclib.precursor_df[hash_column_name].values + fragment_speclib_hash = fragment_speclib.precursor_df[hash_column_name].values + + speclib_indices = fragment.join_left(speclib_hash, fragment_speclib_hash) + + matched_mask = (speclib_indices >= 0) + + if verbose: + matched_count = np.sum(matched_mask) + not_matched_count = np.sum(~matched_mask) + + logging.info(f'A total of {matched_count:,} precursors were succesfully annotated, {not_matched_count:,} precursors were not matched') + + + frag_start_idx = fragment_speclib.precursor_df['frag_start_idx'].values[speclib_indices] + frag_end_idx = fragment_speclib.precursor_df['frag_end_idx'].values[speclib_indices] + + speclib._precursor_df = speclib._precursor_df[matched_mask].copy() + speclib._precursor_df['frag_start_idx'] = frag_start_idx[matched_mask] + speclib._precursor_df['frag_end_idx'] = frag_end_idx[matched_mask] + + speclib._fragment_mz_df = fragment_speclib._fragment_mz_df.copy() + speclib._fragment_intensity_df = fragment_speclib._fragment_intensity_df.copy() + + return speclib \ No newline at end of file diff --git a/alphabase/spectral_library/decoy_library.py b/alphabase/spectral_library/decoy.py similarity index 85% rename from alphabase/spectral_library/decoy_library.py rename to alphabase/spectral_library/decoy.py index 6402d5cb..dbd80733 100644 --- a/alphabase/spectral_library/decoy_library.py +++ b/alphabase/spectral_library/decoy.py @@ -1,21 +1,15 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbdev_nbs/spectral_library/decoy_library.ipynb. - -# %% auto 0 -__all__ = ['decoy_lib_provider', 'DecoyLib', 'DiaNNDecoyLib', 'DecoyLibProvider'] - -# %% ../../nbdev_nbs/spectral_library/decoy_library.ipynb 2 import copy -from .library_base import SpecLibBase -from ..io.hdf import HDF_File +from alphabase.spectral_library.base import SpecLibBase +from alphabase.io.hdf import HDF_File -# %% ../../nbdev_nbs/spectral_library/decoy_library.ipynb 3 class DecoyLib(SpecLibBase): def __init__(self, target_lib:SpecLibBase, fix_C_term = True, **kwargs, ): - """Pseudo-reverse peptide decoy generator + """ + Pseudo-reverse peptide decoy generator Currently, only sequence-level decoy is implemented, but AlphaPeptDeep will add modifications onto both target and decoy sequences, so it is enough for practical uses. @@ -39,11 +33,12 @@ def __init__(self, self.fix_C_term = fix_C_term def translate_to_decoy(self): - """Main entry of this class, it calls follows methods: - self.decoy_sequence() - self._decoy_mods() - self._decoy_meta() - self._decoy_frags() + """ + Main entry of this class, it calls follows methods: + - self.decoy_sequence() + - self._decoy_mods() + - self._decoy_meta() + - self._decoy_frags() """ self.decoy_sequence() self._decoy_mods() @@ -146,11 +141,12 @@ def load_hdf(self, hdf_file): class DiaNNDecoyLib(DecoyLib): def __init__(self, target_lib:SpecLibBase, - raw_AAs:str = 'GAVLIFMPWSCTYHKRQEND', - mutated_AAs:str = 'LLLVVLLLLTSSSSLLNDQE', #DiaNN + raw_AAs:str = 'GAVLIFMPWSCTYHKRQENDBJOUXZ', + mutated_AAs:str = 'LLLVVLLLLTSSSSLLNDQEVVVVVV', #DiaNN **kwargs, ): - """DiaNN-like decoy peptide generator + """ + DiaNN-like decoy peptide generator Parameters ---------- @@ -159,11 +155,11 @@ def __init__(self, raw_AAs : str, optional AAs those DiaNN decoy from. - Defaults to 'GAVLIFMPWSCTYHKRQEND'. + Defaults to 'GAVLIFMPWSCTYHKRQENDBJOUXZ'. mutated_AAs : str, optional AAs those DiaNN decoy to. - Defaults to 'LLLVVLLLLTSSSSLLNDQE'. + Defaults to 'LLLVVLLLLTSSSSLLNDQEVVVVVV'. """ super().__init__(target_lib) @@ -179,7 +175,6 @@ def _decoy_seq(self): x[2:-2]+self.mutated_AAs[self.raw_AAs.index(x[-2])]+x[-1] ) -# %% ../../nbdev_nbs/spectral_library/decoy_library.ipynb 6 class DecoyLibProvider(object): def __init__(self): self.decoy_dict = {} @@ -198,6 +193,7 @@ def get_decoy_lib(self, name:str, ---------- name : str Registered decoy class name + target_lib : SpecLibBase Target library for decoy generation diff --git a/alphabase/spectral_library/flat.py b/alphabase/spectral_library/flat.py new file mode 100644 index 00000000..aade30c7 --- /dev/null +++ b/alphabase/spectral_library/flat.py @@ -0,0 +1,198 @@ +import pandas as pd + +from alphabase.spectral_library.base import ( + SpecLibBase +) +from alphabase.peptide.fragment import ( + flatten_fragments +) + +from alphabase.io.hdf import HDF_File + +import alphabase.peptide.precursor as precursor + +class FlatSpecLib: + """ + Flatten the spectral library (SpecLibBase) by using :meth:`parse_base_library`. + + Attributes + ---------- + custom_fragment_df_columns : list of str + 'mz' and 'intensity' columns are required in :attr:`fragment_df`, + others could be customized. + It can include ['type','number','position','charge','loss_type']. + + min_fragment_intensity : float + minimal intensity to keep in :attr:`fragment_df`. + + keep_top_k_fragments : float + top k highest peaks to keep in :attr:`fragment_df`. + + """ + + key_numeric_columns = SpecLibBase.key_numeric_columns + """ Identical to :obj:`SpecLibBase.key_numeric_columns `. """ + + def __init__(self, + min_fragment_intensity:float = 0.001, + keep_top_k_fragments:int = 1000, + custom_fragment_df_columns:list = [ + 'type','number','position','charge','loss_type' + ], + **kwargs + ): + """ + Parameters + ---------- + min_fragment_intensity : float, optional + minimal intensity to keep, by default 0.001 + + keep_top_k_fragments : int, optional + top k highest peaks to keep, by default 1000 + + custom_fragment_df_columns : list, optional + See :attr:`custom_fragment_df_columns`, + defaults to ['type','number','position','charge','loss_type'] + """ + self.min_fragment_intensity = min_fragment_intensity + self.keep_top_k_fragments = keep_top_k_fragments + + self.custom_fragment_df_columns = custom_fragment_df_columns + + @property + def precursor_df(self)->pd.DataFrame: + """ + Similar to :obj:`SpecLibBase.precursor_df ` + """ + return self._precursor_df + + @precursor_df.setter + def precursor_df(self, df:pd.DataFrame): + self._precursor_df = df + precursor.refine_precursor_df( + self._precursor_df, + drop_frag_idx=False, + ensure_data_validity=True, + ) + + @property + def peptide_df(self)->pd.DataFrame: + """ + Similar to :obj:`SpecLibBase.precursor_df ` + """ + return self._precursor_df + + @peptide_df.setter + def peptide_df(self, df:pd.DataFrame): + self.precursor_df = df + + @property + def fragment_df(self)->pd.DataFrame: + """The fragment mz dataframe with + fragment types as columns (['mz', 'intensity'] + :attr:`custom_fragment_df_columns`.) + """ + return self._fragment_df + + def parse_base_library(self, library:SpecLibBase): + """ Flatten an library object of SpecLibBase or its inherited class. + This method will generate :attr:`precursor_df` and :attr:`fragment_df` + The fragments in fragment_df can be located by + `frag_start_idx` and `frag_end_idx` in precursor_df. + + Parameters + ---------- + library : SpecLibBase + A library object with attributes + `precursor_df`, `fragment_mz_df` and `fragment_intensity_df`. + """ + self._precursor_df, self._fragment_df = flatten_fragments( + library.precursor_df, + library.fragment_mz_df, + library.fragment_intensity_df, + min_fragment_intensity=self.min_fragment_intensity, + keep_top_k_fragments=self.keep_top_k_fragments, + custom_columns=self.custom_fragment_df_columns, + ) + + def save_hdf(self, hdf_file:str): + """Save library dataframes into hdf_file. + For `self.precursor_df`, this method will save it into two hdf groups: + hdf_file: `flat_library/precursor_df` and `flat_library/mod_seq_df`. + + `flat_library/precursor_df` contains all essential numberic columns those + can be loaded faster from hdf file into memory: + `['precursor_mz', 'charge', 'mod_seq_hash', 'mod_seq_charge_hash', + 'frag_start_idx', 'frag_end_idx', 'decoy', 'rt_pred', 'ccs_pred', + 'mobility_pred', 'miss_cleave', 'nAA', 'isotope_mz_m1', 'isotope_intensity_m1', ...]` + + `flat_library/mod_seq_df` contains all string columns and the other + not essential columns: + 'sequence','mods','mod_sites', ['proteins', 'genes']... + as well as 'mod_seq_hash', 'mod_seq_charge_hash' columns to map + back to `precursor_df` + + Parameters + ---------- + hdf_file : str + the hdf file path to save + + """ + _hdf = HDF_File( + hdf_file, + read_only=False, + truncate=True, + delete_existing=True + ) + if 'mod_seq_charge_hash' not in self._precursor_df.columns: + self.hash_precursor_df() + + key_columns = self.key_numeric_columns+[ + 'mod_seq_hash', 'mod_seq_charge_hash' + ] + + _hdf.flat_library = { + 'mod_seq_df': self._precursor_df[ + [ + col for col in self._precursor_df.columns + if col not in self.key_numeric_columns + ] + ], + 'precursor_df': self._precursor_df[ + [ + col for col in self._precursor_df.columns + if col in key_columns + ] + ], + 'fragment_df': self._fragment_df, + } + + def load_hdf(self, hdf_file:str, load_mod_seq:bool=False): + """Load the hdf library from hdf_file + + Parameters + ---------- + hdf_file : str + hdf library path to load + + load_mod_seq : bool, optional + if also load mod_seq_df. + Defaults to False. + + """ + _hdf = HDF_File( + hdf_file, + ) + self._precursor_df:pd.DataFrame = _hdf.flat_library.precursor_df.values + if load_mod_seq: + key_columns = self.key_numeric_columns+[ + 'mod_seq_hash', 'mod_seq_charge_hash' + ] + mod_seq_df = _hdf.flat_library.mod_seq_df.values + cols = [ + col for col in mod_seq_df.columns + if col not in key_columns + ] + self._precursor_df[cols] = mod_seq_df[cols] + + self._fragment_df = _hdf.flat_library.fragment_df.values + diff --git a/alphabase/spectral_library/reader.py b/alphabase/spectral_library/reader.py new file mode 100644 index 00000000..618b55af --- /dev/null +++ b/alphabase/spectral_library/reader.py @@ -0,0 +1,266 @@ +import typing +import numpy as np +import pandas as pd + +from alphabase.peptide.mobility import mobility_to_ccs_for_df +from alphabase.io.psm_reader.dia_search_reader import SpectronautReader +from alphabase.spectral_library.base import SpecLibBase +from alphabase.psm_reader.psm_reader import psm_reader_yaml +from alphabase.psm_reader import psm_reader_provider + +class SWATHLibraryReader(SpectronautReader, SpecLibBase): + def __init__(self, + charged_frag_types:typing.List[str] = [ + 'b_z1','b_z2','y_z1', 'y_z2', + 'b_modloss_z1','b_modloss_z2', + 'y_modloss_z1', 'y_modloss_z2' + ], + column_mapping:dict = None, + modification_mapping:dict = None, + fdr = 0.01, + fixed_C57 = False, + mod_seq_columns=psm_reader_yaml[ + 'spectronaut' + ]['mod_seq_columns'], + csv_sep = '\t', + rt_unit='irt', + precursor_mz_min:float = 400, + precursor_mz_max:float = 2000, + decoy:str = None, + **kwargs + ): + SpecLibBase.__init__(self, + charged_frag_types = charged_frag_types, + precursor_mz_min=precursor_mz_min, + precursor_mz_max=precursor_mz_max, + decoy=decoy + ) + + SpectronautReader.__init__(self, + column_mapping = column_mapping, + modification_mapping = modification_mapping, + fdr = fdr, + keep_decoy = False, + fixed_C57 = fixed_C57, + mod_seq_columns=mod_seq_columns, + csv_sep = csv_sep, + rt_unit=rt_unit, + ) + + self._frag_type_columns = "FragmentType FragmentIonType ProductType ProductIonType".split(' ') + self._frag_number_columns = "FragmentNumber FragmentSeriesNumber".split(' ') + self._frag_charge_columns = "FragmentCharge FragmentIonCharge ProductCharge ProductIonCharge".split(' ') + self._frag_loss_type_columns = "FragmentLossType FragmentIonLossType ProductLossType ProductIonLossType".split(' ') + self._frag_inten_columns = "RelativeIntensity RelativeFragmentIntensity RelativeFragmentIonIntensity LibraryIntensity".split(' ') + + def _find_key_columns(self, lib_df:pd.DataFrame): + def find_col(target_columns, df_columns): + for col in target_columns: + if col in df_columns: + return col + return None + self.mod_seq_col = find_col(self._mod_seq_columns, lib_df.columns) + self.seq_col = find_col(self.column_mapping['sequence'], lib_df.columns) + self.rt_col = find_col(self.column_mapping['rt'], lib_df.columns) + self.mob_col = find_col(self.column_mapping['mobility'], lib_df.columns) + self.raw_col = find_col( + [self.column_mapping['raw_name']] + if isinstance(self.column_mapping['raw_name'],str) + else self.column_mapping['raw_name'], + lib_df.columns + ) + self.frag_type_col = find_col(self._frag_type_columns, lib_df.columns) + self.frag_num_col = find_col(self._frag_number_columns, lib_df.columns) + self.frag_charge_col = find_col(self._frag_charge_columns, lib_df.columns) + self.frag_loss_type_col = find_col(self._frag_loss_type_columns, lib_df.columns) + self.frag_inten_col = find_col(self._frag_inten_columns, lib_df.columns) + + if self.frag_loss_type_col is None: + self.frag_loss_type_col = 'FragmentLossType' + lib_df[self.frag_loss_type_col] = '' + + def _get_fragment_intensity(self, lib_df:pd.DataFrame): + frag_col_dict = dict(zip( + self.charged_frag_types, + range(len(self.charged_frag_types)) + )) + + self._find_key_columns(lib_df) + lib_df[self.frag_loss_type_col].fillna('', inplace=True) + lib_df[self.frag_loss_type_col].replace('noloss','',inplace=True) + + mod_seq_list = [] + seq_list = [] + charge_list = [] + rt_list = [] + mob_list = [] + frag_intens_list = [] + nAA_list = [] + raw_list = [] + + group_cols = [self.mod_seq_col, self.seq_col, 'PrecursorCharge'] + + if self.raw_col is not None: + group_cols.append(self.raw_col) + + for keys, df_group in lib_df.groupby( + group_cols + ): + if self.raw_col is None: + mod_seq, seq, charge = keys + else: + mod_seq, seq, charge, raw = keys + nAA = len(seq) + intens = np.zeros( + (nAA-1, len(self.charged_frag_types)),dtype=np.float32 + ) + for frag_type, frag_num, loss_type, frag_charge, inten in df_group[ + [ + self.frag_type_col,self.frag_num_col,self.frag_loss_type_col, + self.frag_charge_col,self.frag_inten_col + ] + ].values: + if frag_type in 'abc': + frag_num -= 1 + elif frag_type in 'xyz': + frag_num = nAA-frag_num-1 + else: + continue + + if loss_type == '': + frag_type = f'{frag_type}_z{frag_charge}' + elif loss_type == 'H3PO4': + frag_type = f'{frag_type}_modloss_z{frag_charge}' + elif loss_type == 'H2O': + frag_type = f'{frag_type}_H2O_z{frag_charge}' + elif loss_type == 'NH3': + frag_type = f'{frag_type}_NH3_z{frag_charge}' + else: + continue + + if frag_type not in frag_col_dict: + continue + frag_col_idx = frag_col_dict[frag_type] + intens[frag_num, frag_col_idx] = inten + max_inten = np.max(intens) + if max_inten <= 0: continue + intens /= max_inten + + mod_seq_list.append(mod_seq) + seq_list.append(seq) + charge_list.append(charge) + rt_list.append(df_group[self.rt_col].values[0]) + if self.mob_col: + mob_list.append(df_group[self.mob_col].values[0]) + else: + mob_list.append(0) + frag_intens_list.append(intens) + nAA_list.append(nAA) + if self.raw_col is not None: + raw_list.append(raw) + + df = pd.DataFrame({ + self.mod_seq_column: mod_seq_list, + self.seq_col: seq_list, + 'PrecursorCharge': charge_list, + self.rt_col: rt_list, + self.mob_col: mob_list, + }) + + if self.raw_col is not None: + df[self.raw_col] = raw_list + + self._fragment_intensity_df = pd.DataFrame( + np.concatenate(frag_intens_list), + columns = self.charged_frag_types + ) + + indices = np.zeros(len(nAA_list)+1, dtype=np.int64) + indices[1:] = np.array(nAA_list)-1 + indices = np.cumsum(indices) + + df['frag_start_idx'] = indices[:-1] + df['frag_end_idx'] = indices[1:] + + return df + + def _load_file(self, filename): + df = pd.read_csv(filename, sep=self.csv_sep) + self._find_mod_seq_column(df) + + df = self._get_fragment_intensity(df) + + return df + + def _post_process(self, + lib_df + ): + self._psm_df['nAA'] = self._psm_df.sequence.str.len() + self._psm_df[ + ['frag_start_idx','frag_end_idx'] + ] = lib_df[['frag_start_idx','frag_end_idx']] + + self.normalize_rt_by_raw_name() + + if ( + 'mobility' in self._psm_df.columns + ): + self._psm_df['ccs'] = ( + mobility_to_ccs_for_df( + self._psm_df, + 'mobility' + ) + ) + + self._psm_df = self._psm_df[ + ~self._psm_df.mods.isna() + ].reset_index(drop=True) + + self._precursor_df = self._psm_df + + self.calc_fragment_mz_df() + + +class LibraryReaderFromRawData(SpecLibBase): + def __init__(self, + charged_frag_types:typing.List[str] = [ + 'b_z1','b_z2','y_z1', 'y_z2', + 'b_modloss_z1','b_modloss_z2', + 'y_modloss_z1', 'y_modloss_z2' + ], + precursor_mz_min:float = 400, + precursor_mz_max:float = 2000, + decoy:str = None, + **kwargs + ): + super().__init__( + charged_frag_types=charged_frag_types, + precursor_mz_min=precursor_mz_min, + precursor_mz_max=precursor_mz_max, + decoy=decoy, + ) + + def import_psms(self, psm_files:list, psm_type:str): + psm_reader = psm_reader_provider.get_reader(psm_type) + if isinstance(psm_files, str): + self._precursor_df = psm_reader.import_file(psm_files) + self._psm_df = self._precursor_df + else: + psm_df_list = [] + for psm_file in psm_files: + psm_df_list.append(psm_reader.import_file(psm_file)) + self._precursor_df = pd.concat(psm_df_list, ignore_index=True) + self._psm_df = self._precursor_df + + def extract_fragments(self, raw_files:list): + """ Include two steps: + 1. self.calc_fragment_mz_df() to generate self.fragment_mz_df + 2. Extract self.fragment_intensity_df from RAW files using AlphaRAW + + Parameters + ---------- + raw_files : list + RAW file paths + """ + self.calc_fragment_mz_df() + # TODO Use AlphaRAW to extract fragment intensities \ No newline at end of file diff --git a/alphabase/spectral_library/reader_from_raw.py b/alphabase/spectral_library/reader_from_raw.py new file mode 100644 index 00000000..0c7350b8 --- /dev/null +++ b/alphabase/spectral_library/reader_from_raw.py @@ -0,0 +1,6 @@ +import typing +import pandas as pd + +from alphabase.psm_reader import psm_reader_provider +from alphabase.spectral_library.base import SpecLibBase + diff --git a/alphabase/spectral_library/translate.py b/alphabase/spectral_library/translate.py new file mode 100644 index 00000000..d7d7029c --- /dev/null +++ b/alphabase/spectral_library/translate.py @@ -0,0 +1,430 @@ +import pandas as pd +import numpy as np +import tqdm +import typing +import numba +import multiprocessing as mp + +from alphabase.constants.modification import MOD_DF + +from alphabase.spectral_library.base import SpecLibBase + +from alphabase.utils import explode_multiple_columns + +#@numba.njit #(cannot use numba for pd.Series) +def create_modified_sequence( + df_items:typing.Tuple, # must be ('sequence','mods','mod_sites') + translate_mod_dict:dict=None, + mod_sep='()', + nterm = '_', + cterm = '_' +): + ''' + Translate `(sequence, mods, mod_sites)` into a modified sequence. Used by `df.apply()`. + For example, `('ABCDEFG','Mod1@A;Mod2@E','1;5')`->`_A[Mod1@A]BCDE[Mod2@E]FG_`. + + Parameters + ---------- + df_items : List + must be `(sequence, mods, mod_sites)` + + translate_mod_dict : dict + A dict to map alpha modification names to other software + + mod_sep : str + '[]' or '()', default '()' + + ''' + mod_seq = df_items[0] + if df_items[1]: + mods = df_items[1].split(';') + mod_sites = [int(i) for i in df_items[2].split(';')] + rev_order = np.argsort(mod_sites)[::-1] + mod_sites = [mod_sites[rev_order[i]] for i in range(len(mod_sites))] + mods = [mods[rev_order[i]] for i in range(len(mods))] + if translate_mod_dict is not None: + mods = [translate_mod_dict[mod] for mod in mods] + for _site, mod in zip(mod_sites, mods): + if _site > 0: + mod_seq = mod_seq[:_site] + mod_sep[0]+mod+mod_sep[1] + mod_seq[_site:] + elif _site == -1: + cterm += mod_sep[0]+mod+mod_sep[1] + elif _site == 0: + nterm += mod_sep[0]+mod+mod_sep[1] + else: + mod_seq = mod_seq[:_site] + mod_sep[0]+mod+mod_sep[1] + mod_seq[_site:] + return nterm + mod_seq + cterm + +@numba.njit +def _get_frag_info_from_column_name(column:str): + ''' + Only used when converting alphabase libraries into other libraries + ''' + idx = column.rfind('_') + frag_type = column[:idx] + charge = column[idx+2:] + if len(frag_type)==1: + loss_type = 'noloss' + else: + idx = frag_type.find('_') + loss_type = frag_type[idx+1:] + frag_type = frag_type[0] + return frag_type, loss_type, charge + +def _get_frag_num(columns, rows, frag_len): + frag_nums = [] + for r,c in zip(rows, columns): + if is_nterm_frag(c): + frag_nums.append(r+1) + else: + frag_nums.append(frag_len-r) + return frag_nums + +def merge_precursor_fragment_df( + precursor_df:pd.DataFrame, + fragment_mz_df:pd.DataFrame, + fragment_inten_df:pd.DataFrame, + top_n_inten:int, + frag_type_head:str='FragmentType', + frag_mass_head:str='FragmentMz', + frag_inten_head:str='RelativeIntensity', + frag_charge_head:str='FragmentCharge', + frag_loss_head:str='FragmentLossType', + frag_num_head:str='FragmentNumber', + verbose=True, +): + ''' + Convert alphabase library into a single dataframe. + This method is not important, as it will be only + used by DiaNN, or spectronaut, or others + ''' + df = precursor_df.copy() + frag_columns = fragment_mz_df.columns.values.astype('U') + frag_type_list = [] + frag_loss_list = [] + frag_charge_list = [] + frag_mass_list = [] + frag_inten_list = [] + frag_num_list = [] + iters = enumerate(df[['frag_start_idx','frag_end_idx']].values) + if verbose: + iters = tqdm.tqdm(iters) + for i,(start, end) in iters: + intens = fragment_inten_df.iloc[start:end,:].values # is loc[start:end-1,:] faster? + max_inten = np.amax(intens) + if max_inten > 0: + intens /= max_inten + masses = fragment_mz_df.iloc[start:end,:].values + sorted_idx = np.argsort(intens.reshape(-1))[-top_n_inten:][::-1] + idx_in_df = np.unravel_index(sorted_idx, masses.shape) + + frag_len = end-start + rows = np.arange(frag_len, dtype=np.int32)[idx_in_df[0]] + columns = frag_columns[idx_in_df[1]] + + frag_types, loss_types, charges = zip( + *[_get_frag_info_from_column_name(_) for _ in columns] + ) + + frag_nums = _get_frag_num(columns, rows, frag_len) + + frag_type_list.append(frag_types) + frag_loss_list.append(loss_types) + frag_charge_list.append(charges) + frag_mass_list.append(masses[idx_in_df]) + frag_inten_list.append(intens[idx_in_df]) + frag_num_list.append(frag_nums) + + df[frag_type_head] = frag_type_list + df[frag_mass_head] = frag_mass_list + df[frag_inten_head] = frag_inten_list + df[frag_charge_head] = frag_charge_list + df[frag_loss_head] = frag_loss_list + df[frag_num_head] = frag_num_list + + return explode_multiple_columns(df, + [ + frag_type_head, + frag_mass_head, + frag_inten_head, + frag_charge_head, + frag_loss_head, + frag_num_head + ] + ) + + # try: + # return df.explode([ + # frag_type_head, + # frag_mass_head, + # frag_inten_head, + # frag_charge_head, + # frag_loss_head, + # frag_num_head + # ]) + # except ValueError: + # # df.explode does not allow mulitple columns before pandas version 1.x.x. + # df = df.explode(frag_type_head) + + # df[frag_mass_head] = _flatten(frag_mass_list) + # df[frag_inten_head] = _flatten(frag_inten_list) + # df[frag_charge_head] = _flatten(frag_charge_list) + # df[frag_loss_head] = _flatten(frag_loss_list) + # df[frag_num_head] = _flatten(frag_num_list) + # return df + +mod_to_unimod_dict = {} +mod_to_modname_dict = {} +for mod_name,unimod_id in MOD_DF[['mod_name','unimod_id']].values: + if unimod_id==-1 or unimod_id=='-1': continue + mod_to_unimod_dict[mod_name] = f"UniMod:{unimod_id}" + mod_to_modname_dict[mod_name] = mod_name[:mod_name.find('@')] + +def is_nterm_frag(frag_type:str): + return frag_type[0] in 'abc' + +def mask_fragment_intensity_by_mz_( + fragment_mz_df:pd.DataFrame, + fragment_intensity_df:pd.DataFrame, + min_frag_mz, max_frag_mz +): + fragment_intensity_df.mask( + (fragment_mz_df>max_frag_mz)|(fragment_mz_dfpd.DataFrame: + ''' + Convert alphabase library to diann (or Spectronaut) library dataframe + This method is not important, as it will be only + used by DiaNN, or spectronaut, or others + + Parameters + ---------- + translate_mod_dict : dict + a dict map modifications from alphabase to other software. Default: build-in `alpha_to_other_mod_dict` + + keep_k_highest_peaks : int + only keep highest fragments for each precursor. Default: 12 + + Returns + ------- + pd.DataFrame + a single dataframe in the SWATH-like format + + ''' + df = pd.DataFrame() + df['ModifiedPeptide'] = speclib._precursor_df[ + ['sequence','mods','mod_sites'] + ].apply( + create_modified_sequence, + axis=1, + translate_mod_dict=translate_mod_dict, + mod_sep='()' + ) + + df['frag_start_idx'] = speclib._precursor_df['frag_start_idx'] + df['frag_end_idx'] = speclib._precursor_df['frag_end_idx'] + + df['PrecursorCharge'] = speclib._precursor_df['charge'] + if 'irt_pred' in speclib._precursor_df.columns: + df['Tr_recalibrated'] = speclib._precursor_df['irt_pred'] + elif 'rt_pred' in speclib._precursor_df.columns: + df['Tr_recalibrated'] = speclib._precursor_df['rt_pred'] + elif 'rt_norm' in speclib._precursor_df.columns: + df['Tr_recalibrated'] = speclib._precursor_df['rt_norm'] + else: + raise ValueError('precursor_df must contain the "rt_pred" or "rt_norm" column') + + if 'mobility_pred' in speclib._precursor_df.columns: + df['IonMobility'] = speclib._precursor_df.mobility_pred + elif 'mobility' in speclib._precursor_df.columns: + df['IonMobility'] = speclib._precursor_df.mobility + + # df['LabelModifiedSequence'] = df['ModifiedPeptide'] + df['StrippedPeptide'] = speclib._precursor_df['sequence'] + + if 'precursor_mz' not in speclib._precursor_df.columns: + speclib.calc_precursor_mz() + df['PrecursorMz'] = speclib._precursor_df['precursor_mz'] + + if 'uniprot_ids' in speclib._precursor_df.columns: + df['ProteinID'] = speclib._precursor_df.uniprot_ids + elif 'proteins' in speclib._precursor_df.columns: + df['ProteinID'] = speclib._precursor_df.proteins + + if 'genes' in speclib._precursor_df.columns: + df['Genes'] = speclib._precursor_df['genes'] + + # if 'protein_group' in speclib._precursor_df.columns: + # df['ProteinGroups'] = speclib._precursor_df['protein_group'] + + if min_frag_mz > 0 or max_frag_mz > 0: + mask_fragment_intensity_by_mz_( + speclib._fragment_mz_df, + speclib._fragment_intensity_df, + min_frag_mz, max_frag_mz + ) + + if min_frag_nAA > 0: + mask_fragment_intensity_by_frag_nAA( + speclib._fragment_intensity_df, + speclib._precursor_df, + max_mask_frag_nAA=min_frag_nAA-1 + ) + + df = merge_precursor_fragment_df( + df, + speclib._fragment_mz_df, + speclib._fragment_intensity_df, + top_n_inten=keep_k_highest_fragments, + frag_type_head=frag_type_head, + frag_mass_head=frag_mass_head, + frag_inten_head=frag_inten_head, + frag_charge_head=frag_charge_head, + frag_loss_head=frag_loss_head, + frag_num_head=frag_num_head, + verbose=verbose + ) + df = df[df['RelativeIntensity']>min_frag_intensity] + df.loc[df[frag_loss_head]=='modloss',frag_loss_head] = modloss + + return df.drop(['frag_start_idx','frag_end_idx'], axis=1) + +def speclib_to_swath_df( + speclib:SpecLibBase, + *, + keep_k_highest_fragments:int=12, + min_frag_mz = 200, + max_frag_mz = 2000, + min_frag_intensity = 0.01, +)->pd.DataFrame: + speclib_to_single_df( + speclib, + translate_mod_dict=mod_to_modname_dict, + keep_k_highest_fragments=keep_k_highest_fragments, + min_frag_mz = min_frag_mz, + max_frag_mz = max_frag_mz, + min_frag_intensity = min_frag_intensity, + ) + +class WritingProcess(mp.Process): + def __init__(self, task_queue, tsv, *args, **kwargs): + self.task_queue:mp.Queue = task_queue + self.tsv = tsv + super().__init__(*args, **kwargs) + + def run(self): + while True: + df, batch = self.task_queue.get() + if df is None: break + df.to_csv(self.tsv, header=(batch==0), sep="\t", mode="a", index=False) + + +def translate_to_tsv( + speclib:SpecLibBase, + tsv:str, + *, + keep_k_highest_fragments:int=12, + min_frag_mz:float = 200, + max_frag_mz:float = 2000, + min_frag_intensity:float = 0.01, + min_frag_nAA:int = 0, + batch_size:int = 100000, + translate_mod_dict:dict = mod_to_modname_dict, + multiprocessing:bool=True +): + if multiprocessing: + queue_size = 1000000//batch_size + if queue_size < 2: + queue_size = 2 + elif queue_size > 10: + queue_size = 10 + df_head_queue = mp.Queue(maxsize=queue_size) + writing_process = WritingProcess(df_head_queue, tsv) + writing_process.start() + mask_fragment_intensity_by_mz_( + speclib._fragment_mz_df, + speclib._fragment_intensity_df, + min_frag_mz, max_frag_mz + ) + if min_frag_nAA > 0: + mask_fragment_intensity_by_frag_nAA( + speclib._fragment_intensity_df, + speclib._precursor_df, + max_mask_frag_nAA=min_frag_nAA-1 + ) + if isinstance(tsv, str): + with open(tsv, "w"): pass + _speclib = SpecLibBase() + _speclib._fragment_intensity_df = speclib._fragment_intensity_df + _speclib._fragment_mz_df = speclib._fragment_mz_df + precursor_df = speclib._precursor_df + for i in tqdm.tqdm(range(0, len(precursor_df), batch_size)): + _speclib._precursor_df = precursor_df.iloc[i:i+batch_size] + df = speclib_to_single_df( + _speclib, translate_mod_dict=translate_mod_dict, + keep_k_highest_fragments=keep_k_highest_fragments, + min_frag_mz=0, + max_frag_mz=0, + min_frag_intensity=min_frag_intensity, + min_frag_nAA=0, + verbose=False + ) + if multiprocessing: + df_head_queue.put((df, i)) + else: + df.to_csv(tsv, header=(i==0), sep="\t", mode='a', index=False) + if multiprocessing: + df_head_queue.put((None, None)) + print("Translation finished, it will take several minutes to export the rest precursors to the tsv file...") + writing_process.join() + diff --git a/alphabase/statistics/__init__.py b/alphabase/statistics/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/alphabase/statistics/regression.py b/alphabase/statistics/regression.py new file mode 100644 index 00000000..1247c691 --- /dev/null +++ b/alphabase/statistics/regression.py @@ -0,0 +1,277 @@ +import numpy as np + +from sklearn.preprocessing import PolynomialFeatures +from sklearn.base import BaseEstimator, RegressorMixin + +from sklearn.utils.estimator_checks import check_estimator + + +EPSILON = 1e-6 + +class LOESSRegression(BaseEstimator, RegressorMixin): + """scikit-learn estimator which implements a LOESS style local polynomial regression. The number of basis functions or kernels can be explicitly defined which allows for faster and cheaper training and inference. + + Parameters + ---------- + + n_kernels : int + default = 6, The number of local polynomial functions used to approximate the data. The location and extend of the kernels will be distributed to contain an equal number of datapoints in the training set. + + kernel_size : float + default = 2, A factor increasing the kernel size to overlap with the neighboring kernel. + + polynomial_degree : int + default = 2, Degree of the polynomial functions used for the local approximation. + + """ + + def __init__(self, + n_kernels: int = 6, + kernel_size: float = 2., + polynomial_degree: int = 2): + + self.n_kernels = n_kernels + self.kernel_size = kernel_size + self.polynomial_degree = polynomial_degree + + def get_params(self, deep: bool = True): + return super().get_params(deep) + + def set_params(self, **params): + return super().set_params(**params) + + def _more_tags(self): + return {'X_types': ['1darray']} + + def calculate_kernel_indices(self, x: np.ndarray): + """Determine the indices of the datapoints belonging to each kernel. + + Parameters + ---------- + x : numpy.ndarray + float, of shape (n_datapoints) + + Returns + ------- + numpy.ndarray, int + of shape (n_kernels, 2) + + """ + + num_datapoints = len(x) + interval_size = num_datapoints // self.n_kernels + + start = np.arange(0,self.n_kernels) * interval_size + end = start + interval_size + + interval_extension = ((interval_size * self.kernel_size - interval_size) //2) + + start = start - interval_extension + start = np.maximum(0,start) + + end = end + interval_extension + end = np.minimum(num_datapoints,end) + + return np.column_stack([start,end]).astype(int) + + + def fit(self, x: np.ndarray, y: np.ndarray): + """fit the model passed on provided training data. + + Parameters + ---------- + + x : numpy.ndarray + float, of shape (n_samples,) or (n_samples, 1), Training data. Note that only a single feature is supported at the moment. + + y : numpy.ndarray, float + of shape (n_samples,) or (n_samples, 1) Target values. + + Returns + ------- + + self: object + Returns the fitted estimator. + + """ + + # As required by scikit-learn estimator guidelines + self.n_features_in_ = 1 + + # === start === sanity checks === + # Does not yet work with more than one input dimension + # axis-wise scaling and improved distance function need to be implemented + if len(x.shape) > 1: + if x.shape[1] > 1: + raise ValueError('Input arrays with more than one feature not yet supported. Please provide a matrix of shape (n_datapoints, 1) or (n_datapoints,)') + + # at least two datapoints required + if len(x.flat) < 2: + raise ValueError('At least two datapoints required for fitting.') + + # sanity check for number of datapoints, reduce n_kernels if needed + degrees_freedom = (1 + self.polynomial_degree) * self.n_kernels + + if len(x.flat) < degrees_freedom: + print(f"Curve fitting with {self.n_kernels} kernels and polynomials of {self.polynomial_degree} degree requires at least {degrees_freedom} datapoints.") + + self.n_kernels = np.max([len(x.flat) // (1 + self.polynomial_degree),1]) + + print(f"Number of kernels will be reduced to {self.n_kernels} kernels.") + + # sanity check for number of datapoints, reduce degree of polynomial if necessary + degrees_freedom = (1 + self.polynomial_degree) * self.n_kernels + if len(x.flat) < degrees_freedom: + self.polynomial_degree = len(x.flat) - 1 + + print(f"Polynomial degree will be reduced to {self.polynomial_degree}.") + + # reshape both arrays to column arrays + if len(x.shape) == 1: + x = x[...,np.newaxis] + + if len(y.shape) == 1: + y = y[...,np.newaxis] + + # === end === sanity checks === + + # create flat version of the array for + idx_sorted = np.argsort(x.flat) + x_sorted = x.flat[idx_sorted] + + # kernel indices will only be calculated during fitting + kernel_indices = self.calculate_kernel_indices(x_sorted) + + # scale max and scale mean will then be used for calculating the weighht matrix + self.scale_mean = np.zeros((self.n_kernels)) + self.scale_max = np.zeros((self.n_kernels)) + + # scale mean and max are calculated and contain the scaling before applying the kernel + for i, area in enumerate(kernel_indices): + area_slice = slice(*area) + self.scale_mean[i] = x_sorted[area_slice].mean() + self.scale_max[i] = np.max(np.abs(x_sorted[area_slice] - self.scale_mean[i])) + + # from here on, the original column arrays are used + w = self.get_weight_matrix(x) + + + # build design matrix + polynomial_transform = PolynomialFeatures(self.polynomial_degree) + x_design = polynomial_transform.fit_transform(x) + number_of_dimensions = len(x_design[0]) + + + self.beta = np.zeros((number_of_dimensions,self.n_kernels)) + + for i, weights in enumerate(w.T): + + loadings = np.linalg.inv(x_design.T * weights @ x_design)@x_design.T + beta = (loadings*weights)@y + y_m = np.sum(x_design @ beta, axis=1) + self.beta[:,i] = np.ravel((loadings*weights)@y) + + + return self + + def predict(self, x: np.ndarray): + """Predict using the LOESS model. + + Parameters + ---------- + + x : numpy.ndarray + float, of shape (n_samples,) or (n_samples, 1) Feature data. Note that only a single feature is supported at the moment. + + Returns + ------- + + y : numpy.ndarray, float + of shape (n_samples,) + Target values. + + """ + + if len(x.shape) == 1: + x = x[...,np.newaxis] + + w = self.get_weight_matrix(x) + polynomial_transform = PolynomialFeatures(self.polynomial_degree) + x_design = polynomial_transform.fit_transform(x) + + return np.sum(x_design @ self.beta * w, axis=1) + + + def get_weight_matrix(self, x: np.ndarray): + """Applies the fitted scaling parameter and the kernel to yield a weight matrix. + + The weight matrix is calculated based on the self.scale_mean and self.scale_max parameters which need to be calculated before calling this function. + They define the center and extend of the tricubic kernels. The first and last column are one-padded at the start and beginning to allow for extrapolation. + + Parameters + ---------- + + x: numpy.ndarray + Numpy array of shape (n_datapoints, 1) which should be transformed to weights. + + + Returns + ------- + + numpy.ndarray + Weight matrix with the shape (n_datapoints, n_kernels). + + """ + w = np.tile(x,(1,self.n_kernels)) + + w = w - self.scale_mean + w = w/self.scale_max + + # apply weighting kernel + w = apply_kernel(w) + + w = w/np.sum(w, axis=1, keepdims=True) + + return w + + +def apply_kernel(w): + + num_cols = w.shape[1] + + if num_cols == 1: + return np.ones(w.shape) + + if num_cols == 2: + w[:,0] = left_open_tricubic(w[:,0]) + w[:,1] = right_open_tricubic(w[:,1]) + + return w + + if num_cols > 2 : + w[:,0] = left_open_tricubic(w[:,0]) + w[:,1:-1] = tricubic(w[:,1:-1]) + w[:,-1] = right_open_tricubic(w[:,-1]) + + return w + +def tricubic(x): + """tricubic weight kernel""" + epsilon = EPSILON + mask = np.abs(x) <= 1 + return mask * (np.power(1-np.power(np.abs(x),3),3) + epsilon) + + +def left_open_tricubic(x): + """tricubic weight kernel which weights assigns 1 to values x < 0""" + y = tricubic(x) + y[x < 0] = 1 + return y + + +def right_open_tricubic(x): + """tricubic weight kernel which weights assigns 1 to values x > 0""" + y = tricubic(x) + y[x > 0] = 1 + return y + diff --git a/alphabase/utils.py b/alphabase/utils.py index d707ce1e..13e25633 100644 --- a/alphabase/utils.py +++ b/alphabase/utils.py @@ -1,9 +1,3 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbdev_nbs/utils.ipynb. - -# %% auto 0 -__all__ = ['process_bar', 'explode_multiple_columns'] - -# %% ../nbdev_nbs/utils.ipynb 2 import tqdm import os import sys diff --git a/alphabase/yaml_utils.py b/alphabase/yaml_utils.py index a0877d0c..ee6b8c28 100644 --- a/alphabase/yaml_utils.py +++ b/alphabase/yaml_utils.py @@ -1,9 +1,3 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbdev_nbs/yaml_utils.ipynb. - -# %% auto 0 -__all__ = ['load_yaml', 'save_yaml'] - -# %% ../nbdev_nbs/yaml_utils.ipynb 2 import yaml def load_yaml(filename)->dict: diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..41c270bb --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/build_docs.sh b/docs/build_docs.sh new file mode 100644 index 00000000..fc2fd6fb --- /dev/null +++ b/docs/build_docs.sh @@ -0,0 +1,11 @@ +rm -rf build +conda env remove -n alphabasedocs +conda create -n alphabasedocs python=3.8 -y +# conda create -n alphatimsinstaller python=3.8 +conda activate alphabasedocs +# call conda install git -y +# call pip install 'git+https://github.com/MannLabs/alphatims.git#egg=alphatims[gui]' --use-feature=2020-resolver +# brew install freetype +pip install '../.[development]' +make html +conda deactivate \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..4d82ff0a --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,107 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +import importlib +import inspect +sys.path.insert(0, os.path.abspath('..')) + + +# -- Project information ----------------------------------------------------- + +project = 'alphabase' +copyright = '2022, Mann Labs, MPIB' +author = 'Mann Labs, MPIB' + +release = "0.2.1" + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.napoleon', + "sphinx.ext.intersphinx", + "sphinx.ext.linkcode", + 'sphinx.ext.viewcode', + # 'sphinx.ext.autodoc', + 'autodocsumm', + 'nbsphinx', + 'myst_parser', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [ + '_build', 'Thumbs.db', '.DS_Store', + '_modidx,py' +] + +code_url = f"https://github.com/mannlabs/alphabase/blob/main" + +def linkcode_resolve(domain, info): + # Non-linkable objects from the starter kit in the tutorial. + if domain == "js" or info["module"] == "connect4": + return + + if domain != "py": return + + mod = importlib.import_module(info["module"]) + if "." in info["fullname"]: + objname, attrname = info["fullname"].split(".") + obj = getattr(mod, objname) + try: + # object is a method of a class + obj = getattr(obj, attrname) + except AttributeError: + # object is an attribute of a class + return None + else: + obj = getattr(mod, info["fullname"]) + + try: + file = inspect.getsourcefile(obj) + lines = inspect.getsourcelines(obj) + except TypeError: + # e.g. object is a typing.Union + return None + file = os.path.relpath(file, os.path.abspath("..")) + if not file.startswith("alphabase"): + # e.g. object is a typing.NewType + return None + start, end = lines[1], lines[1] + len(lines[0]) - 1 + + return f"{code_url}/{file}#L{start}-L{end}" + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'furo' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +autodoc_default_options = { + 'autosummary': True, + 'special-members': '__init__', # Include __init__ methods. +} \ No newline at end of file diff --git a/docs/constants/aa.html b/docs/constants/aa.html deleted file mode 100644 index 75ea6bca..00000000 --- a/docs/constants/aa.html +++ /dev/null @@ -1,895 +0,0 @@ - - - - - - - - - -alphabase - Amino acid information - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- -
- - - - - -
- -
-
-

Amino acid information

-
- - - -
- - - -
- - -
- - -

We use all 128 ASCII code to represent amino acids for flexible extensions in the future.

-

The amino acid masses are stored in 128-lengh array AA_ASCII_MASS. If an ASCII code is not in AA_CHEM, the mass will be 1e8 to disable it for MS search.

-

We also provide a AA table (AA_DF dataframe) for users.

-
-

source

-
-

reset_AA_df

-
-
 reset_AA_df ()
-
-
-

source

-
-
-

reset_AA_mass

-
-
 reset_AA_mass ()
-
-

AA mass in np.array with shape (128,)

-
-
AA_DF.loc[ord('A'):ord('Z'),:]
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
aaformulamass
65AC(3)H(5)N(1)O(1)S(0)7.103711e+01
66BC(1000000)1.200000e+07
67CC(3)H(5)N(1)O(1)S(1)1.030092e+02
68DC(4)H(5)N(1)O(3)S(0)1.150269e+02
69EC(5)H(7)N(1)O(3)S(0)1.290426e+02
70FC(9)H(9)N(1)O(1)S(0)1.470684e+02
71GC(2)H(3)N(1)O(1)S(0)5.702146e+01
72HC(6)H(7)N(3)O(1)S(0)1.370589e+02
73IC(6)H(11)N(1)O(1)S(0)1.130841e+02
74JC(6)H(11)N(1)O(1)S(0)1.130841e+02
75KC(6)H(12)N(2)O(1)S(0)1.280950e+02
76LC(6)H(11)N(1)O(1)S(0)1.130841e+02
77MC(5)H(9)N(1)O(1)S(1)1.310405e+02
78NC(4)H(6)N(2)O(2)S(0)1.140429e+02
79OC(12)H(19)N(3)O(2)2.371477e+02
80PC(5)H(7)N(1)O(1)S(0)9.705276e+01
81QC(5)H(8)N(2)O(2)S(0)1.280586e+02
82RC(6)H(12)N(4)O(1)S(0)1.561011e+02
83SC(3)H(5)N(1)O(2)S(0)8.703203e+01
84TC(4)H(7)N(1)O(2)S(0)1.010477e+02
85UC(3)H(5)N(1)O(1)Se(1)1.509536e+02
86VC(5)H(9)N(1)O(1)S(0)9.906841e+01
87WC(11)H(10)N(2)O(1)S(0)1.860793e+02
88XC(1000000)1.200000e+07
89YC(9)H(9)N(1)O(2)S(0)1.630633e+02
90ZC(1000000)1.200000e+07
-
-
-
-

calc_sequence_mass can easily get the mass list of each amino acid. The key is: np.array(sequence, 'c').view(np.int8) converts a string into an ASCII code array

-

Note that this function is rarely used in alphabase as it is not fast for a set of peptides.

-
-

source

-
-
-

calc_sequence_mass

-
-
 calc_sequence_mass (sequence:str)
-
- - - - - - - - - - - - - - - - - - - - -
TypeDetails
sequencestrUnmodified peptide sequence
ReturnsndarrayMasses of each amino acid.
-

We provide calc_AA_masses_for_same_len_seqs and calc_sequence_masses_for_same_len_seqs functions to fast calculate masses for a given array of AA sequences with same length. They are fast because they both use slicing and reshape operation based on AA_ASCII_MASS array.

-
/Users/zengwenfeng/opt/anaconda3/lib/python3.8/site-packages/fastcore/docscrape.py:225: UserWarning: potentially wrong underline length... 
-Raises 
-------- in 
-Calculate sequence masses for the array of same-len AA sequences.
-...
-  else: warn(msg)
-/Users/zengwenfeng/opt/anaconda3/lib/python3.8/site-packages/fastcore/docscrape.py:225: UserWarning: Unknown section Raises
-  else: warn(msg)
-
-

source

-
-
-

calc_sequence_masses_for_same_len_seqs

-
-
 calc_sequence_masses_for_same_len_seqs (sequence_array:numpy.ndarray)
-
-

Calculate sequence masses for the array of same-len AA sequences.

- ----- - - - - - - - - - - - - - - - - - - - -
TypeDetails
sequence_arrayndarrayunmodified sequences with the same length.
Returnsndarray1-D (array_size, sequence_len) array of masses.
-
/Users/zengwenfeng/opt/anaconda3/lib/python3.8/site-packages/fastcore/docscrape.py:225: UserWarning: potentially wrong underline length... 
-Raises 
-------- in 
-Calculate AA masses for the array of same-len AA sequences.
-...
-  else: warn(msg)
-
-

source

-
-
-

calc_AA_masses_for_same_len_seqs

-
-
 calc_AA_masses_for_same_len_seqs (sequence_array:numpy.ndarray)
-
-

Calculate AA masses for the array of same-len AA sequences.

- ----- - - - - - - - - - - - - - - - - - - - -
TypeDetails
sequence_arrayndarrayunmodified sequences with the same length.
Returnsndarray2-D (array_size, sequence_len) array of masses.
-

For a single sequence

-
-
assert np.allclose(
-    calc_sequence_mass('ACDEFGNYK'),
-    [ 71.03711379, 103.00918496, 115.02694302, 129.04259309,
-       147.06841391,  57.02146372, 114.04292744, 163.06332853,
-       128.09496302 ]
-)
-
-

For sequences with the same length

-

It is very easy to generate b/y ions from a sequence or a list of sequences with same length

-
-
aa_masses = calc_AA_masses_for_same_len_seqs(['ACDEFGHIK','BCDEFGHIK','CCDEFGHIK'])
-b_masses = np.cumsum(aa_masses, axis=1)
-b_masses, pepmass = b_masses[:,:-1], b_masses[:,-1:]
-pepmass += MASS_H2O
-{'pepmass':pepmass, 'b masses':b_masses, 'y masses':pepmass-b_masses}
-
-
{'pepmass': array([[1.01845422e+03],
-        [1.20009474e+07],
-        [1.05042629e+03]]),
- 'b masses': array([[7.10371138e+01, 1.74046299e+02, 2.89073242e+02, 4.18115835e+02,
-         5.65184249e+02, 6.22205712e+02, 7.59264624e+02, 8.72348688e+02],
-        [1.20000000e+07, 1.20001030e+07, 1.20002180e+07, 1.20003471e+07,
-         1.20004941e+07, 1.20005512e+07, 1.20006882e+07, 1.20008013e+07],
-        [1.03009185e+02, 2.06018370e+02, 3.21045313e+02, 4.50087906e+02,
-         5.97156320e+02, 6.54177784e+02, 7.91236696e+02, 9.04320760e+02]]),
- 'y masses': array([[947.41710224, 844.40791728, 729.38097426, 600.33838117,
-         453.26996726, 396.24850354, 259.18959168, 146.1055277 ],
-        [947.41710224, 844.40791728, 729.38097426, 600.33838117,
-         453.26996726, 396.24850354, 259.18959168, 146.1055277 ],
-        [947.41710224, 844.40791728, 729.38097426, 600.33838117,
-         453.26996726, 396.24850354, 259.18959168, 146.1055277 ]])}
-
-
-

calc_AA_masses_for_var_len_seqs is rarely used in alphabase.

-
-

source

-
-
-

calc_AA_masses_for_var_len_seqs

-
-
 calc_AA_masses_for_var_len_seqs (sequence_array:numpy.ndarray)
-
-

We recommend to use calc_AA_masses_for_same_len_seqs as it is much faster.

- ----- - - - - - - - - - - - - - - - - - - - -
TypeDetails
sequence_arrayndarraySequences with variable lengths.
Returnsndarray1D array of masses, zero values are padded to fill the max length.
-
-
masses = calc_AA_masses_for_var_len_seqs(['EFGHIK','AAAGCDEFGHIK','DDDDCCDEFGHIK'])
-masses
-
-
array([[1.29042593e+02, 1.47068414e+02, 5.70214637e+01, 1.37058912e+02,
-        1.13084064e+02, 1.28094963e+02, 1.00000000e+08, 1.00000000e+08,
-        1.00000000e+08, 1.00000000e+08, 1.00000000e+08, 1.00000000e+08,
-        1.00000000e+08],
-       [7.10371138e+01, 7.10371138e+01, 7.10371138e+01, 5.70214637e+01,
-        1.03009185e+02, 1.15026943e+02, 1.29042593e+02, 1.47068414e+02,
-        5.70214637e+01, 1.37058912e+02, 1.13084064e+02, 1.28094963e+02,
-        1.00000000e+08],
-       [1.15026943e+02, 1.15026943e+02, 1.15026943e+02, 1.15026943e+02,
-        1.03009185e+02, 1.03009185e+02, 1.15026943e+02, 1.29042593e+02,
-        1.47068414e+02, 5.70214637e+01, 1.37058912e+02, 1.13084064e+02,
-        1.28094963e+02]])
-
-
- - -
- -
- -
- - - - \ No newline at end of file diff --git a/docs/constants/aa.rst b/docs/constants/aa.rst new file mode 100644 index 00000000..00f3d0ba --- /dev/null +++ b/docs/constants/aa.rst @@ -0,0 +1,7 @@ +alphabase.constants.aa +====================== + +.. automodule:: alphabase.constants.aa + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/constants/element.html b/docs/constants/element.html deleted file mode 100644 index 8a54c8c3..00000000 --- a/docs/constants/element.html +++ /dev/null @@ -1,538 +0,0 @@ - - - - - - - - - -alphabase - Atom element information - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- -
- - - - - -
- -
-
-

Atom element information

-
- - - -
- - - -
- - -
- - -

When we have the chemical element information, we define the max isotope abundance distribution length (MAX_ISOTOPE_LEN) for each element and combination of elements. If the isotope length is larger than MAX_ISOTOPE_LEN, we truncate_isotope by keeping the monoisotope and its top MAX_ISOTOPE_LEN-1 abundant neighbors.

-

EMPTY_DIST defines a “zero element”, its monoisotopic position is 0 with abundance 1. It is used for abundance convolution between different isotopes (see abundance_convolution).

-
-

source

-
-

truncate_isotope

-
-
 truncate_isotope (isotopes:numpy.ndarray, mono_idx:int)
-
-

For a given isotope distribution (intensity patterns), this function truncates the distribution by top MAX_ISOTOPE_LEN neighbors those contain the monoisotopic peak pointed by mono_idx.

- ----- - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDetails
isotopesndarrayIsotope patterns with size > MAX_ISOTOPE_LEN.
mono_idxintMonoisotopic peak position (index) in the isotope patterns
Returnstuplethe new position of mono_idx
-
-
-

Load chemical element information

-

First, we load alphadeep/constants/nist_element.yaml into CHEM_INFO_DICT, which is the base dict for further processing.

-

Then we call reset_elements to extract corresponding information for CHEM_MONO_MASS (mono mass dict), CHEM_ISOTOPE_DIST (isotope distribution dict), and CHEM_MONO_IDX (dict of mono position in the isotope distribution).

-

At last, MASS_H2O and MASS_NH3 are re-calculated based on masses of H, O, and N in CHEM_MONO_MASS.

-

All these steps are done in load_elem_yaml(yaml_file).

-
-

source

-
-
-

load_elem_yaml

-
-
 load_elem_yaml (yaml_file:str)
-
-

Load built-in or user-defined element yaml file. Default yaml is: os.path.join(_base_dir, ‘nist_element.yaml’)

-
-

source

-
-
-

reset_elements

-
-
 reset_elements ()
-
-
-
-

Calculate mass from a formula

-

Now we have CHEM_MONO_MASS, we can calculate the mass of different chemical formula. Formula format: H(1)C(2)O(3)...

-
-

source

-
-
-

calc_mass_from_formula

-
-
 calc_mass_from_formula (formula:str)
-
-

Calculates the mass of the formula`

- - - - - - - - - - - - - - - - - - - - -
TypeDetails
formulastre.g. H(1)C(2)O(3)
Returnsfloatmass of the formula
-
-

source

-
-
-

parse_formula

-
-
 parse_formula (formula:str)
-
-

Given a formula (str, e.g. H(1)C(2)O(3)), it generates [('H', 2), ('C', 2), ('O', 1)]

-

Example

- - -
- -
- -
- - - - \ No newline at end of file diff --git a/docs/constants/element.rst b/docs/constants/element.rst new file mode 100644 index 00000000..cc980484 --- /dev/null +++ b/docs/constants/element.rst @@ -0,0 +1,7 @@ +alphabase.constants.element +=========================== + +.. automodule:: alphabase.constants.element + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/constants/isotope.html b/docs/constants/isotope.html deleted file mode 100644 index fb0e47f9..00000000 --- a/docs/constants/isotope.html +++ /dev/null @@ -1,732 +0,0 @@ - - - - - - - - - -alphabase - Isotope distribution - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- -
- - - - - -
- -
-
-

Isotope distribution

-
- - - -
- - - -
- - -
- - -

If we have two isotope distributions, we can use convolute them into one distribution by using abundance_convolution.

-
-

source

-
-

abundance_convolution

-
-
 abundance_convolution (d1:numpy.ndarray, mono1:int, d2:numpy.ndarray,
-                        mono2:int)
-
-

If we have two isotope distributions, we can convolute them into one distribution.

- ----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDetails
d1ndarrayisotope distribution to convolute
mono1intmono position of d1.
d2ndarrayisotope distribution to convolute
mono2intmono position of d2
Returnstyping.Tuple[numpy.ndarray, int]np.ndarray, convoluted isotope distribution
int, new mono position.
-

For a given chemical formula, e.g. H(100)O(50)N(20), we first calculate the isotope distribution using “binary search”-like method for each type of element (here are H(100), O(50) and N(20)) (see one_element_dist). And then we convolute these distributions of all types into one distribution (see formula_dist).

-
-

source

-
-
-

formula_dist

-
-
 formula_dist (formula:Union[list,str])
-
-

Generate the isotope distribution and the mono index for a given formula (as a list, e.g. [('H', 2), ('C', 2), ('O', 1)]).

- ----- - - - - - - - - - - - - - - - - - - - -
TypeDetails
formulatyping.Union[list, str]chemical formula, could be str or list.
If str: “H(1)N(2)O(3)”.
If list: “[(‘H’,1),(‘H’,2),(‘H’,3)]”.
Returnstyping.Tuple[numpy.ndarray, int]np.ndarray, isotope distribution
int, mono position
-
-

source

-
-
-

one_element_dist

-
-
 one_element_dist (elem:str, n:int,
-                   chem_isotope_dist:numba.typed.typeddict.Dict,
-                   chem_mono_idx:numba.typed.typeddict.Dict)
-
-

Calculate the isotope distribution for an element and its numbers.

- ----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDetails
elemstrelement.
nintelement number.
chem_isotope_distDictuse CHEM_ISOTOPE_DIST as parameter.
chem_mono_idxDictuse CHEM_MONO_IDX as parameter.
Returnstyping.Tuple[numpy.ndarray, int]np.ndarray, isotope distribution of the element.
int, mono position in the distribution
-

Compare calculated isotope distributions with sisweb.com/mstools/isotope.htm

-

Desired distribution for H10: (100, 0.16, 0.0001) calculated from sisweb.com/mstools/isotope.htm in low resolution mode (centroid mode)

-

Desired distribution for C(100)H(100)O(10): (90.7784, 100, 56.368, 21.6475, 6.3624, 1.524, 0.3093) calculated from sisweb.com/mstools/isotope.htm in low resolution mode (centroid mode)

-

The target and calculated distributions are very similar

-

Compare with Averagine

-

Test for heavy labeled formula

-
-
-

IsotopeDistribution

-

formula_dist always calculates the distribution of each element based on the element number (using binary-search-like operation) and convolute distributions of different elements. If we have many peptides to calculate, each element’s distribution will be calculated repeatly. In IsotopeDistribution, instead of generating on-the-fly, we pre-built the isotope distribution table for each of the most common elements (C,H,N,O,S,P) with the element number from 0 to N, and N is large enough to cover all composition in shotgun proteomics. Thus, for a given chemical formula, we just need to check the distribution table for each element and convolute distributions among different elements.

-
/Users/zengwenfeng/opt/anaconda3/lib/python3.8/site-packages/fastcore/docscrape.py:225: UserWarning: Unknown section Attributes
-  else: warn(msg)
-
-

source

-
-
-

IsotopeDistribution

-
-
 IsotopeDistribution (max_elem_num_dict:dict={'C': 2000, 'H': 5000, 'N':
-                      1000, 'O': 1000, 'S': 200, 'P': 200})
-
-

Faster calculation of isotope abundance distribution by pre-building isotope distribution tables for most common elements.

-

We have considered large enough number of elements for shotgun proteomics. We can increase max_elem_num_dict to support larger peptide or top-down in the future. However, current MAX_ISOTOPE_LEN is not suitable for top-down, it must be extended to a larger number (100?). Note that non-standard amino acids have 1000000 C elements in AlphaBase, We clip 1000000 C to the maximal number of C in max_elem_num_dict. As they have very large masses thus impossible to identify, their isotope distributions do not matter.

- ------ - - - - - - - - - - - - - - - - -
TypeDefaultDetails
max_elem_num_dictdict{‘C’: 2000, ‘H’: 5000, ‘N’: 1000, ‘O’: 1000, ‘S’: 200, ‘P’: 200}Define the maximal number of the elements.
Defaults to { ‘C’: 2000, ‘H’: 5000, ‘N’: 1000, ‘O’: 1000, ‘S’: 200, ‘P’: 200, }
-
/Users/zengwenfeng/opt/anaconda3/lib/python3.8/site-packages/fastcore/docscrape.py:225: UserWarning: Unknown section Examples
-  else: warn(msg)
-
-

source

-
-
-

IsotopeDistribution.calc_formula_distribution

-
-
 IsotopeDistribution.calc_formula_distribution
-                                                (formula:List[Tuple[str,in
-                                                t]])
-
-

Calculate isotope abundance distribution for a given formula

- ----- - - - - - - - - - - - - - - - - - - - -
TypeDetails
formulatyping.List[typing.Tuple[str, int]]chemical formula: “[(‘H’,1),(‘C’,2),(‘O’,3)]”.
Returnstyping.Tuple[numpy.ndarray, int]np.ndarray, isotope abundance distribution
int, monoisotope position in the distribution array
-
-
iso = IsotopeDistribution()
-formula = 'C(100)H(100)O(10)Na(1)Fe(1)'
-formula = parse_formula(formula)
-dist, mono = iso.calc_formula_distribution(formula)
-dist1, mono1 = formula_dist(formula)
-assert np.allclose(dist, dist1)
-assert mono==mono1
-assert mono==2
-dist
-
-
array([1.92320044e-02, 2.10952666e-02, 3.13753566e-01, 3.42663681e-01,
-       1.95962632e-01, 7.69157517e-02, 2.31993814e-02, 5.71948249e-03,
-       1.19790438e-03, 2.18815385e-04])
-
-
- - -
- -
- -
- - - - \ No newline at end of file diff --git a/docs/constants/isotope.rst b/docs/constants/isotope.rst new file mode 100644 index 00000000..b888413c --- /dev/null +++ b/docs/constants/isotope.rst @@ -0,0 +1,7 @@ +alphabase.constants.isotope +=========================== + +.. automodule:: alphabase.constants.isotope + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/constants/modification.html b/docs/constants/modification.html deleted file mode 100644 index 86463909..00000000 --- a/docs/constants/modification.html +++ /dev/null @@ -1,1543 +0,0 @@ - - - - - - - - - -alphabase - Modification information - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- -
- - - - - -
- -
-
-

Modification information

-
- - - -
- - - -
- - -
- - -

The default modification TSV is stored in alphabase/constants/const_files/modification.tsv. Please check it to add more modifications.

-

First, we load modification.tsv into MOD_DF.

-

Then, we extract information of MOD_CHEM (dict), MOD_MASS (dict), MOD_LOSS_MASS (dict), MOD_INFO_DICT (dict) … from MOD_DF. This step is done in update_all_by_MOD_DF.

-

All these steps are done by load_mod_df.

-
-

source

-
-

add_modifications_for_lower_case_AA

-
-
 add_modifications_for_lower_case_AA ()
-
-

Add modifications for lower-case AAs for advanced usages

-
-

source

-
-
-

update_all_by_MOD_DF

-
-
 update_all_by_MOD_DF ()
-
-

As DataFrame is more conveneint in data operation, we can also process MOD_DF and then update all global modification variables from MOD_DF

-
-

source

-
-
-

load_mod_df

-
-
 load_mod_df (tsv:str='/Users/zengwenfeng/Workspace/AlphaBase/alphabase/co
-              nstants/const_files/modification.tsv',
-              modloss_importance_level=1)
-
-
-

source

-
-
-

keep_modloss_by_importance

-
-
 keep_modloss_by_importance (modloss_importance_level:float=1.0)
-
-
-
MOD_DF
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mod_nameavge_massclassificationcompositionmodloss_compositionmono_massunimod_idunimod_massunimod_modlossmodloss_importancemassmodloss_originalmodloss
mod_name
GlyGly@KGlyGly@K114.042927Post-translationalH(6)C(4)N(2)O(2)H(6)C(4)N(2)O(2)114.042927121114.042927114.0429271000000.0114.042927114.042927114.042927
15N-oxobutanoic@C^Any N-term15N-oxobutanoic@C^Any N-term-18.023900ArtefactH(-3)15N(-1)-18.0235841419-18.0235840.0000000.0-18.0235840.0000000.000000
15N-oxobutanoic@S^Protein N-term15N-oxobutanoic@S^Protein N-term-18.023900Post-translationalH(-3)15N(-1)-18.0235841419-18.0235840.0000000.0-18.0235840.0000000.000000
15N-oxobutanoic@T^Protein N-term15N-oxobutanoic@T^Protein N-term-18.023900Post-translationalH(-3)15N(-1)-18.0235841419-18.0235840.0000000.0-18.0235840.0000000.000000
2-dimethylsuccinyl@C2-dimethylsuccinyl@C144.125300Chemical derivativeH(8)C(6)O(4)144.0422591262144.0422590.0000000.0144.0422590.0000000.000000
..........................................
spermidine@Qspermidine@Q128.215300Chemical derivativeH(16)C(7)N(2)128.1313491421128.1313490.0000000.0128.1313490.0000000.000000
spermine@Qspermine@Q185.309700Chemical derivativeH(23)C(10)N(3)185.1891981420185.1891980.0000000.0185.1891980.0000000.000000
sulfo+amino@Ysulfo+amino@Y95.077800Chemical derivativeH(1)N(1)O(3)S(1)94.96771499794.9677140.0000000.094.9677140.0000000.000000
thioacylPA@KthioacylPA@K159.206200Chemical derivativeH(9)C(6)N(1)O(2)S(1)159.035399967159.0353990.0000000.0159.0354000.0000000.000000
trifluoro@Ltrifluoro@L53.971400Non-standard residueH(-3)F(3)53.97173575053.9717350.0000000.053.9717340.0000000.000000
-

2685 rows × 13 columns

-
-
-
-
-
-

With NIST elements, all calculated masses are the same as unimod_mass now.

-
-
-

Mod site representation

-
    -
  • site=0 refers to an N-term modification
  • -
  • site=-1 refers to a C-term modification
  • -
  • 1<=site<=peplen refers to a normal modification
  • -
-

For example: _0A1B2C3D4E5F6G7H8I9J10K11_-1

-

calc_modification_mass and calc_modification_mass_sum are base functions to calculate masses. But for large sets of peptides, we recommend to use calc_mod_masses_for_same_len_seqs instead of calc_modification_mass.

-
-

source

-
-

calc_modification_mass_sum

-
-
 calc_modification_mass_sum (mod_names:List[str])
-
-

Calculate summed mass of the given modification without knowing the sites and peptide length. It is useful to calculate peptide mass.

- - - - - - - - - - - - - - - - - - - - -
TypeDetails
mod_namestyping.List[str]Modification name list
ReturnsfloatTotal mass
-
-

source

-
-
-

calc_mod_masses_for_same_len_seqs

-
-
 calc_mod_masses_for_same_len_seqs (nAA:int,
-                                    mod_names_list:List[List[str]],
-                                    mod_sites_list:List[List[int]])
-
-

Calculate modification masses for the given peptides with same peptide length (nAA).

- ----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDetails
nAAintPeptide length
mod_names_listtyping.List[typing.List[str]]List (pep_count) of modification list (n_mod on each peptide)
mod_sites_listtyping.List[typing.List[int]]List of modification site list corresponding to mod_names_list.
* site=0 refers to an N-term modification
* site=-1 refers to a C-term modification
* 1<=site<=peplen refers to a normal modification
Returnsndarray2-D array with shape=(nAA, pep_count or len(mod_names_list))).
Masses of modifications through all the peptides,
0 if sites without modifications.
-
-

source

-
-
-

calc_modification_mass

-
-
 calc_modification_mass (nAA:int, mod_names:List[str],
-                         mod_sites:List[int])
-
-

Calculate modification masses for the given peptide length (nAA), and modified site list.

- ----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDetails
nAAintPeptide length
mod_namestyping.List[str]List[str]. Modification name list
mod_sitestyping.List[int]List[int]. Modification site list corresponding to mod_names.
* site=0 refers to an N-term modification
* site=-1 refers to a C-term modification
* 1<=site<=peplen refers to a normal modification
Returnsndarray1-D array with length=nAA.
Masses of modifications through the peptide,
0 if sites has no modifications
-
-

source

-
-
-

calc_modloss_mass

-
-
 calc_modloss_mass (nAA:int, mod_names:List, mod_sites:List,
-                    for_nterm_frag:bool)
-
-

Calculate modification loss masses (e.g. -98 Da for Phospho@S/T, -64 Da for Oxidation@M). The mod loss mass is calculated by the modification closer to the fragment sites. For example, the modloss of the b3 ion for AS(Phospho@S)M(Oxidation@M)... will be -64 Da.

- ----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDetails
nAAintPeptide length
mod_namestyping.ListModification name list
mod_sitestyping.ListModification site list corresponding
for_nterm_fragboolIf True, the loss will be on the
N-term fragments (mainly b ions);
If False, the loss will be on the
C-term fragments (mainly y ions)
Returnsndarraymod_loss masses
-
-

source

-
-
-

calc_modloss_mass_with_importance

-
-
 calc_modloss_mass_with_importance (nAA:int, mod_names:List,
-                                    mod_sites:List, for_nterm_frag:bool)
-
-

Calculate modification loss masses (e.g. -98 Da for Phospho@S/T, -64 Da for Oxidation@M). Modifications with higher MOD_LOSS_IMPORTANCE have higher priorities. For example, AS(Phospho@S)M(Oxidation@M)..., importance of Phospho@S > importance of Oxidation@M, so the modloss of b3 ion will be -98 Da, not -64 Da.

- ----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDetails
nAAintPeptide length
mod_namestyping.ListModification name list
mod_sitestyping.ListModification site list
for_nterm_fragboolIf True, the loss will be on the
N-term fragments (mainly b ions);
If False, the loss will be on the
C-term fragments (mainly y ions)
Returnsndarraymod_loss masses
-
-
-

Note that get_modloss_mass is a little bit time comsuming

-

%timeit get_modloss_mass(10, mod_names, mod_sites, False)

-

Results (12 seconds in total): 12.6 µs ± 96.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

-
-
MOD_DF.drop_duplicates('classification')
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mod_nameavge_massclassificationcompositionmodloss_compositionmono_massunimod_idunimod_massunimod_modlossmodloss_importancemassmodloss_originalmodloss
mod_name
GlyGly@KGlyGly@K114.042927Post-translationalH(6)C(4)N(2)O(2)H(6)C(4)N(2)O(2)114.042927121114.042927114.0429271000000.0114.042927114.042927114.042927
15N-oxobutanoic@C^Any N-term15N-oxobutanoic@C^Any N-term-18.023900ArtefactH(-3)15N(-1)-18.0235841419-18.0235840.0000000.0-18.0235840.0000000.000000
2-dimethylsuccinyl@C2-dimethylsuccinyl@C144.125300Chemical derivativeH(8)C(6)O(4)144.0422591262144.0422590.0000000.0144.0422590.0000000.000000
3-deoxyglucosone@R3-deoxyglucosone@R144.125300MultipleH(8)C(6)O(4)144.042259949144.0422590.0000000.0144.0422590.0000000.000000
ADP-Ribosyl@CADP-Ribosyl@C541.300500Other glycosylationH(21)C(15)N(5)O(13)P(2)541.061110213541.0611100.0000000.0541.0611100.0000000.000000
ADP-Ribosyl@NADP-Ribosyl@N541.300500N-linked glycosylationH(21)C(15)N(5)O(13)P(2)H(21)C(15)N(5)O(13)P(2)541.061110213541.061110541.0611100.0541.061110541.0611100.000000
ADP-Ribosyl@SADP-Ribosyl@S541.300500O-linked glycosylationH(21)C(15)N(5)O(13)P(2)H(21)C(15)N(5)O(13)P(2)541.061110213541.061110541.0611100.0541.061110541.0611100.000000
AEC-MAEC:2H(4)@SAEC-MAEC:2H(4)@S63.158000Isotopic labelH(1)2H(4)C(2)N(1)O(-1)S(1)63.04446279263.0444620.0000000.063.0444630.0000000.000000
Ahx2+Hsl@Any C-termAhx2+Hsl@Any C-term309.403900Non-standard residueH(27)C(16)N(3)O(3)309.2052421015309.2052420.0000000.0309.2052420.0000000.000000
Ala->Arg@AAla->Arg@A85.107800AA substitutionH(7)C(3)N(3)O(0)S(0)85.063997105285.0639970.0000000.085.0639970.0000000.000000
Arg-loss@R^Any C-termArg-loss@R^Any C-term-156.185700OtherH(-12)C(-6)N(-4)O(-1)-156.1011111287-156.1011110.0000000.0-156.1011110.0000000.000000
FormylMet@Protein N-termFormylMet@Protein N-term159.206200Pre-translationalH(9)C(6)N(1)O(2)S(1)159.035399107159.0353990.0000000.0159.0354000.0000000.000000
HexN@KHexN@K161.155800Synth. pep. protect. gp.H(11)C(6)N(1)O(4)161.068808454161.0688080.0000000.0161.0688080.0000000.000000
Met-loss+Acetyl@M^Protein N-termMet-loss+Acetyl@M^Protein N-term-89.159400Co-translationalH(-7)C(-3)N(-1)S(-1)-89.029920766-89.0299200.0000000.0-89.0299200.0000000.000000
-
-
-
-
-
-

We can update modification list for differet requirements, for example:

-
-
add_modifications_for_lower_case_AA()
-MOD_DF = MOD_DF[
-    (MOD_DF['classification'].isin(['Post-translational','O-linked glycosylation','AA substitution','Multiple','Non-standard residue','Pre-translational']))
-    & MOD_DF['lower_case_AA']
-] # we only need PTMs
-update_all_by_MOD_DF()
-# MOD_INFO_DICT is also updated
-pd.DataFrame().from_dict(MOD_INFO_DICT, orient='index')
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mod_nameavge_massclassificationcompositionmodloss_compositionmono_massunimod_idunimod_massunimod_modlossmodloss_importancemassmodloss_originalmodlosslower_case_AA
GlyGly@kGlyGly@k114.042927Post-translationalH(6)C(4)N(2)O(2)H(6)C(4)N(2)O(2)114.042927121114.042927114.0429271000000.0114.042927114.042927114.042927True
15N-oxobutanoic@s^Protein N-term15N-oxobutanoic@s^Protein N-term-18.023900Post-translationalH(-3)15N(-1)-18.0235841419-18.0235840.0000000.0-18.0235840.0000000.000000True
15N-oxobutanoic@t^Protein N-term15N-oxobutanoic@t^Protein N-term-18.023900Post-translationalH(-3)15N(-1)-18.0235841419-18.0235840.0000000.0-18.0235840.0000000.000000True
3-deoxyglucosone@r3-deoxyglucosone@r144.125300MultipleH(8)C(6)O(4)144.042259949144.0422590.0000000.0144.0422590.0000000.000000True
3-phosphoglyceryl@k3-phosphoglyceryl@k168.042000Post-translationalH(5)C(3)O(6)P(1)167.9823751387167.9823750.0000000.0167.9823750.0000000.000000True
.............................................
pyrophospho@tpyrophospho@t159.959800Post-translationalH(2)O(6)P(2)H(3)O(7)P(2)159.932662898159.932662176.9354020.0159.932662176.9354010.000000True
s-GlcNAc@ss-GlcNAc@s283.255700O-linked glycosylationH(13)C(8)N(1)O(8)S(1)H(13)C(8)N(1)O(8)S(1)283.0361871412283.036187283.0361870.0283.036188283.0361880.000000True
s-GlcNAc@ts-GlcNAc@t283.255700O-linked glycosylationH(13)C(8)N(1)O(8)S(1)H(13)C(8)N(1)O(8)S(1)283.0361871412283.036187283.0361870.0283.036188283.0361880.000000True
serotonylation@qserotonylation@q159.184600Post-translationalH(9)C(10)N(1)O(1)159.0684141992159.0684140.0000000.0159.0684140.0000000.000000True
trifluoro@ltrifluoro@l53.971400Non-standard residueH(-3)F(3)53.97173575053.9717350.0000000.053.9717340.0000000.000000True
-

1249 rows × 14 columns

-
-
-
-
-

source

-
-

add_new_modifications

-
-
 add_new_modifications (new_mods:list)
-
-

Add new modifications into MOD_DF

- ----- - - - - - - - - - - - - - - -
TypeDetails
new_modslistlist of tuples. Tuple example:
(
modname@site:str (e.g. Mod@S),
chemical compositions:str (e.g. “H(4)O(2)”),
[optional] modloss compositions:str (e.g. “H(2)O(1)”),
)
- - -
-
-
- -
- -
- - - - \ No newline at end of file diff --git a/docs/constants/modification.rst b/docs/constants/modification.rst new file mode 100644 index 00000000..687f9bd1 --- /dev/null +++ b/docs/constants/modification.rst @@ -0,0 +1,7 @@ +alphabase.constants.modification +================================ + +.. automodule:: alphabase.constants.modification + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index b3e6f02e..00000000 --- a/docs/index.html +++ /dev/null @@ -1,586 +0,0 @@ - - - - - - - - - -alphabase - AlphaBase - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- -
- - - - - -
- -
-
-

AlphaBase

-
- - - -
- - - -
- - -
- - -

-

AlphaBase provides all basic python functionalities for AlphaPept ecosystem from the Mann Labs at the Max Planck Institute of Biochemistry and the University of Copenhagen. To enable all hyperlinks in this document, please view it at GitHub. For documentation, please see GitHub Pages

- -
-
-

About

-

An open-source Python package of the AlphaPept ecosystem from the Mann Labs at the Max Planck Institute of Biochemistry and the University of Copenhagen. It provides basic functionalities for AlphaPept ecosystem.

-
-
-
-

License

-

AlphaBase was developed by the Mann Labs at the Max Planck Institute of Biochemistry and the University of Copenhagen and is freely available with an Apache License. External Python packages (available in the requirements folder) have their own licenses, which can be consulted on their respective websites.

-
-
-
-

Installation

-

AlphaBase can be installed and used on all major operating systems (Windows, macOS and Linux). There are two different types of installation possible:

-
    -
  • Pip installer: Choose this installation if you want to use AlphaBase as a Python package in an existing Python 3.8 environment (e.g. a Jupyter notebook).
  • -
  • Developer installer: Choose this installation if you are familiar with conda and Python. This installation allows access to all available features of AlphaBase and even allows to modify its source code directly. Generally, the developer version of AlphaBase outperforms the precompiled versions which makes this the installation of choice for high-throughput experiments.
  • -
-
-

Pip

-

AlphaBase can be installed in an existing Python 3.8 environment with a single bash command. This bash command can also be run directly from within a Jupyter notebook by prepending it with a !:

-
pip install alphabase
-

Installing AlphaBase like this avoids conflicts when integrating it in other tools, as this does not enforce strict versioning of dependancies. However, if new versions of dependancies are released, they are not guaranteed to be fully compatible with AlphaBase. While this should only occur in rare cases where dependencies are not backwards compatible, you can always force AlphaBase to use dependancy versions which are known to be compatible with:

-
pip install "alphabase[stable]"
-

NOTE: You might need to run pip install -U pip before installing AlphaBase like this. Also note the double quotes ".

-

For those who are really adventurous, it is also possible to directly install any branch (e.g. @development) with any extras (e.g. #egg=alphabase[stable,development-stable]) from GitHub with e.g.

-
pip install "git+https://github.com/MannLabs/alphabase.git@development#egg=alphabase[stable,development-stable]"
-
-
-

Developer

-

AlphaBase can also be installed in editable (i.e. developer) mode with a few bash commands. This allows to fully customize the software and even modify the source code to your specific needs. When an editable Python package is installed, its source code is stored in a transparent location of your choice. While optional, it is advised to first (create and) navigate to e.g. a general software folder:

-
mkdir ~/folder/where/to/install/software
-cd ~/folder/where/to/install/software
-

The following commands assume you do not perform any additional cd commands anymore.

-

Next, download the AlphaBase repository from GitHub either directly or with a git command. This creates a new AlphaBase subfolder in your current directory.

-
git clone https://github.com/MannLabs/alphabase.git
-

For any Python package, it is highly recommended to use a separate conda virtual environment, as otherwise dependancy conflicts can occur with already existing packages.

-
conda create --name alphabase python=3.8 -y
-conda activate alphabase
-

Finally, AlphaBase and all its dependancies need to be installed. To take advantage of all features and allow development (with the -e flag), this is best done by also installing the development dependencies instead of only the core dependencies:

-
pip install -e "./alphabase[development]"
-

By default this installs loose dependancies (no explicit versioning), although it is also possible to use stable dependencies (e.g. pip install -e "./alphabase[stable,development-stable]").

-

By using the editable flag -e, all modifications to the AlphaBase source code folder are directly reflected when running AlphaBase. Note that the AlphaBase folder cannot be moved and/or renamed if an editable version is installed. In case of confusion, you can always retrieve the location of any Python module with e.g. the command import module followed by module.__file__.

-
-
-
-
-

Usage

-

TODO

-
-
-
-

Troubleshooting

-

In case of issues, check out the following:

-
    -
  • Issues: Try a few different search terms to find out if a similar problem has been encountered before
  • -
  • Discussions: Check if your problem or feature requests has been discussed before.
  • -
-
-
-
-

Citations

-

There are currently no plans to draft a manuscript.

-
-
-
-

How to contribute

-

If you like this software, you can give us a star to boost our visibility! All direct contributions are also welcome. Feel free to post a new issue or clone the repository and create a pull request with a new branch. For an even more interactive participation, check out the discussions and the the Contributors License Agreement.

-
-
-
-

Changelog

-

See the HISTORY.md for a full overview of the changes made in each version.

- - -
- -
- -
- - - - \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 00000000..82f40c12 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,19 @@ +Documentation for AlphaBase +===================================== + +The infrastructure of AlphaX ecosystem for MS proteomics. +For more information, see AlphaBase on `GitHub `_. + +.. toctree:: + :maxdepth: 2 + + modules_spectral_library + modules_protein + modules_peptide + modules_constants + modules_io + modules_psm_reader + modules_scoring + modules_statistics + + notebooks \ No newline at end of file diff --git a/docs/io/hdf.html b/docs/io/hdf.html deleted file mode 100644 index e23020e9..00000000 --- a/docs/io/hdf.html +++ /dev/null @@ -1,508 +0,0 @@ - - - - - - - - - -alphabase - HDF functionalities - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- -
- - - - - -
- -
-
-

HDF functionalities

-
- - - -
- - - -
- - -
- - -

This module provides a common interface to access HDF files. It can be imported as follows:

-
-
import alphabase.io.hdf
-
-# Other packages used to demonstrate functionality
-import numpy as np
-import pandas as pd
-import os
-
-

Instead of relying directly on the h5py interface, we will use an HDF wrapper file to provide consistent access to only those specific HDF features we want. Since components of an HDF file come in three shapes datasets, groups and attributes, we will first define a generic HDF wrapper object to handle these components. Once this is done, the HDF wrapper file can be treated as such an object with additional features to open and close the initial connection.

-
-
#| hide
-from nbdev.showdoc import show_doc
-
-
-
-

HDF_File

-
-
 HDF_File (file_name:str, read_only:bool=True, truncate:bool=False,
-           delete_existing:bool=False)
-
-

A generic class to access HDF components.

- - -
- -
- -
- - - - \ No newline at end of file diff --git a/docs/io/hdf.rst b/docs/io/hdf.rst new file mode 100644 index 00000000..6b300133 --- /dev/null +++ b/docs/io/hdf.rst @@ -0,0 +1,7 @@ +alphabase.io.hdf +=========================== + +.. automodule:: alphabase.io.hdf + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/io/tempmmap.rst b/docs/io/tempmmap.rst new file mode 100644 index 00000000..8182b3f7 --- /dev/null +++ b/docs/io/tempmmap.rst @@ -0,0 +1,7 @@ +alphabase.io.tempmmap +=========================== + +.. automodule:: alphabase.io.tempmmap + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/modules_constants.rst b/docs/modules_constants.rst new file mode 100644 index 00000000..b39c6800 --- /dev/null +++ b/docs/modules_constants.rst @@ -0,0 +1,10 @@ +alphabase.constants +==================== + +.. toctree:: + :maxdepth: 1 + + constants/element + constants/aa + constants/modification + constants/isotope \ No newline at end of file diff --git a/docs/modules_io.rst b/docs/modules_io.rst new file mode 100644 index 00000000..70484e01 --- /dev/null +++ b/docs/modules_io.rst @@ -0,0 +1,8 @@ +alphabase.io +=========================== + +.. toctree:: + :maxdepth: 1 + + io/hdf +.. io/tempmmap \ No newline at end of file diff --git a/docs/modules_peptide.rst b/docs/modules_peptide.rst new file mode 100644 index 00000000..bd8b8461 --- /dev/null +++ b/docs/modules_peptide.rst @@ -0,0 +1,10 @@ +alphabase.peptide +=========================== + +.. toctree:: + :maxdepth: 1 + + peptide/precursor + peptide/fragment + peptide/mass_calc + peptide/mobility \ No newline at end of file diff --git a/docs/modules_protein.rst b/docs/modules_protein.rst new file mode 100644 index 00000000..3f9e63ca --- /dev/null +++ b/docs/modules_protein.rst @@ -0,0 +1,7 @@ +alphabase.protein +=========================== + +.. toctree:: + :maxdepth: 1 + + protein/fasta \ No newline at end of file diff --git a/docs/modules_psm_reader.rst b/docs/modules_psm_reader.rst new file mode 100644 index 00000000..89dab448 --- /dev/null +++ b/docs/modules_psm_reader.rst @@ -0,0 +1,16 @@ +alphabase.psm_reader +=========================== + +All psm_readers can be accessed by +:obj:`psm_reader_provider `. +See examples in :doc:`psm_reader notebook <../nbs/psm_readers>`. + +.. toctree:: + :maxdepth: 1 + + psm_reader/psm_reader + psm_reader/alphapept_reader + psm_reader/pfind_reader + psm_reader/maxquant_reader + psm_reader/msfragger_reader + psm_reader/dia_psm_reader \ No newline at end of file diff --git a/docs/modules_scoring.rst b/docs/modules_scoring.rst new file mode 100644 index 00000000..6bbbc9ae --- /dev/null +++ b/docs/modules_scoring.rst @@ -0,0 +1,9 @@ +alphabase.scoring +=========================== + +.. toctree:: + :maxdepth: 1 + + scoring/fdr + scoring/feature_extraction_base + scoring/ml_scoring_base \ No newline at end of file diff --git a/docs/modules_spectral_library.rst b/docs/modules_spectral_library.rst new file mode 100644 index 00000000..7aa1b52c --- /dev/null +++ b/docs/modules_spectral_library.rst @@ -0,0 +1,11 @@ +alphabase.spectral_library +=========================== + +.. toctree:: + :maxdepth: 1 + + spectral_library/base + spectral_library/flat + spectral_library/decoy + spectral_library/reader + spectral_library/translate \ No newline at end of file diff --git a/docs/modules_statistics.rst b/docs/modules_statistics.rst new file mode 100644 index 00000000..d1e4b63d --- /dev/null +++ b/docs/modules_statistics.rst @@ -0,0 +1,7 @@ +alphabase.statistics +=========================== + +.. toctree:: + :maxdepth: 1 + + statistics/regression \ No newline at end of file diff --git a/docs/nbs/basic_setup.ipynb b/docs/nbs/basic_setup.ipynb new file mode 100644 index 00000000..b272bff1 --- /dev/null +++ b/docs/nbs/basic_setup.ipynb @@ -0,0 +1,30 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.8.3 ('base')", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.8.3" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "8a3b27e141e49c996c9b863f8707e97aabd49c4a7e8445b9b783b34e4a21a9b2" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/nbs/library_from_fasta.ipynb b/docs/nbs/library_from_fasta.ipynb new file mode 100644 index 00000000..bd6ef999 --- /dev/null +++ b/docs/nbs/library_from_fasta.ipynb @@ -0,0 +1,2234 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# FastaLib usage" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "%reload_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "from alphabase.protein.fasta import FastaLib" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Proteins from a dict (or loaded from fasta files)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "prot1 = 'MABCDESTKAFGHIJKLMNOPQRAFGHIJK'\n", + "prot2 = 'AFGHIJKLMNOPQR'\n", + "protein_dict = {\n", + " 'xx': {\n", + " 'protein_id': 'xx',\n", + " 'gene_name': '',\n", + " 'sequence': prot1\n", + " },\n", + " 'yy': {\n", + " 'protein_id': 'yy',\n", + " 'gene_name': 'gene',\n", + " 'sequence': prot2\n", + " }\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`alphabase.protein.fasta.FastaLib.get_peptides_from_protein_dict` will digest a protein dict into a peptide dataframe. \n", + "\n", + "`alphabase.protein.fasta.FastaLib.get_peptides_from_fasta` will digest a fasta file or a fasta list into a peptide dataframe. " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sequenceprotein_idxesmiss_cleavageis_prot_ntermis_prot_ctermmodsmod_sitesnAA
0AFGHIJK0;10TrueTrue7
1LMNOPQR0;10FalseTrue7
2ABCDESTK00TrueFalse8
3MABCDESTK00TrueFalse9
4AFGHIJKLMNOPQR0;11TrueTrue14
5LMNOPQRAFGHIJK01FalseTrue14
6ABCDESTKAFGHIJK01TrueFalse15
7MABCDESTKAFGHIJK01TrueFalse16
8AFGHIJKLMNOPQRAFGHIJK02FalseTrue21
9ABCDESTKAFGHIJKLMNOPQR02TrueFalse22
10MABCDESTKAFGHIJKLMNOPQR02TrueFalse23
\n", + "
" + ], + "text/plain": [ + " sequence protein_idxes miss_cleavage is_prot_nterm \\\n", + "0 AFGHIJK 0;1 0 True \n", + "1 LMNOPQR 0;1 0 False \n", + "2 ABCDESTK 0 0 True \n", + "3 MABCDESTK 0 0 True \n", + "4 AFGHIJKLMNOPQR 0;1 1 True \n", + "5 LMNOPQRAFGHIJK 0 1 False \n", + "6 ABCDESTKAFGHIJK 0 1 True \n", + "7 MABCDESTKAFGHIJK 0 1 True \n", + "8 AFGHIJKLMNOPQRAFGHIJK 0 2 False \n", + "9 ABCDESTKAFGHIJKLMNOPQR 0 2 True \n", + "10 MABCDESTKAFGHIJKLMNOPQR 0 2 True \n", + "\n", + " is_prot_cterm mods mod_sites nAA \n", + "0 True 7 \n", + "1 True 7 \n", + "2 False 8 \n", + "3 False 9 \n", + "4 True 14 \n", + "5 True 14 \n", + "6 False 15 \n", + "7 False 16 \n", + "8 True 21 \n", + "9 False 22 \n", + "10 False 23 " + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fasta_lib = FastaLib(\n", + " ['b_z1','y_z1'], I_to_L=False, decoy='pseudo_reverse',\n", + " var_mods=['Acetyl@Protein N-term', 'Oxidation@M'],\n", + " fix_mods=['Carbamidomethyl@C'],\n", + ")\n", + "# fasta_lib.get_peptides_from_fasta(fasta_files)\n", + "fasta_lib.get_peptides_from_protein_dict(protein_dict)\n", + "fasta_lib.precursor_df" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
protein_idgene_namesequence
0xxMABCDESTKAFGHIJKLMNOPQRAFGHIJK
1yygeneAFGHIJKLMNOPQR
\n", + "
" + ], + "text/plain": [ + " protein_id gene_name sequence\n", + "0 xx MABCDESTKAFGHIJKLMNOPQRAFGHIJK\n", + "1 yy gene AFGHIJKLMNOPQR" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fasta_lib.protein_df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also append the protein names to precursor_df" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sequenceprotein_idxesmiss_cleavageis_prot_ntermis_prot_ctermmodsmod_sitesnAAproteinsgenes
0AFGHIJK0;10TrueTrue7xx;yygene
1LMNOPQR0;10FalseTrue7xx;yygene
2ABCDESTK00TrueFalse8xx
3MABCDESTK00TrueFalse9xx
4AFGHIJKLMNOPQR0;11TrueTrue14xx;yygene
5LMNOPQRAFGHIJK01FalseTrue14xx
6ABCDESTKAFGHIJK01TrueFalse15xx
7MABCDESTKAFGHIJK01TrueFalse16xx
8AFGHIJKLMNOPQRAFGHIJK02FalseTrue21xx
9ABCDESTKAFGHIJKLMNOPQR02TrueFalse22xx
10MABCDESTKAFGHIJKLMNOPQR02TrueFalse23xx
\n", + "
" + ], + "text/plain": [ + " sequence protein_idxes miss_cleavage is_prot_nterm \\\n", + "0 AFGHIJK 0;1 0 True \n", + "1 LMNOPQR 0;1 0 False \n", + "2 ABCDESTK 0 0 True \n", + "3 MABCDESTK 0 0 True \n", + "4 AFGHIJKLMNOPQR 0;1 1 True \n", + "5 LMNOPQRAFGHIJK 0 1 False \n", + "6 ABCDESTKAFGHIJK 0 1 True \n", + "7 MABCDESTKAFGHIJK 0 1 True \n", + "8 AFGHIJKLMNOPQRAFGHIJK 0 2 False \n", + "9 ABCDESTKAFGHIJKLMNOPQR 0 2 True \n", + "10 MABCDESTKAFGHIJKLMNOPQR 0 2 True \n", + "\n", + " is_prot_cterm mods mod_sites nAA proteins genes \n", + "0 True 7 xx;yy gene \n", + "1 True 7 xx;yy gene \n", + "2 False 8 xx \n", + "3 False 9 xx \n", + "4 True 14 xx;yy gene \n", + "5 True 14 xx \n", + "6 False 15 xx \n", + "7 False 16 xx \n", + "8 True 21 xx \n", + "9 False 22 xx \n", + "10 False 23 xx " + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fasta_lib.append_protein_name()\n", + "fasta_lib.precursor_df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we have our own precursor_df loaded by psm_readers, we can directly assign it to fasta_lib. \n", + "\n", + "``` python\n", + "fasta_lib._precursor_df = precursor_df\n", + "```\n", + "Thus, we can still use FastaLib functionalities for this precursor_df." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Add modifications including both var_mods (`Acetyl@Protein N-term`, `Oxidation@M`, see initialzation of fasta_lib) and fix_mods (`Carbamidomethyl@C`) into the precursor_df." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sequencemodsmod_sites
0AFGHIJK
1AFGHIJKAcetyl@Protein N-term0
2LMNOPQROxidation@M2
3LMNOPQR
4ABCDESTKCarbamidomethyl@C3
5ABCDESTKCarbamidomethyl@C;Acetyl@Protein N-term3;0
6MABCDESTKCarbamidomethyl@C;Oxidation@M4;1
7MABCDESTKCarbamidomethyl@C4
8MABCDESTKCarbamidomethyl@C;Acetyl@Protein N-term;Oxidat...4;0;1
9MABCDESTKCarbamidomethyl@C;Acetyl@Protein N-term4;0
10AFGHIJKLMNOPQROxidation@M9
11AFGHIJKLMNOPQR
12AFGHIJKLMNOPQRAcetyl@Protein N-term;Oxidation@M0;9
13AFGHIJKLMNOPQRAcetyl@Protein N-term0
14LMNOPQRAFGHIJKOxidation@M2
15LMNOPQRAFGHIJK
16ABCDESTKAFGHIJKCarbamidomethyl@C3
17ABCDESTKAFGHIJKCarbamidomethyl@C;Acetyl@Protein N-term3;0
18MABCDESTKAFGHIJKCarbamidomethyl@C;Oxidation@M4;1
19MABCDESTKAFGHIJKCarbamidomethyl@C4
20MABCDESTKAFGHIJKCarbamidomethyl@C;Acetyl@Protein N-term;Oxidat...4;0;1
21MABCDESTKAFGHIJKCarbamidomethyl@C;Acetyl@Protein N-term4;0
22AFGHIJKLMNOPQRAFGHIJKOxidation@M9
23AFGHIJKLMNOPQRAFGHIJK
24ABCDESTKAFGHIJKLMNOPQRCarbamidomethyl@C;Oxidation@M3;17
25ABCDESTKAFGHIJKLMNOPQRCarbamidomethyl@C3
26ABCDESTKAFGHIJKLMNOPQRCarbamidomethyl@C;Acetyl@Protein N-term;Oxidat...3;0;17
27ABCDESTKAFGHIJKLMNOPQRCarbamidomethyl@C;Acetyl@Protein N-term3;0
28MABCDESTKAFGHIJKLMNOPQRCarbamidomethyl@C;Oxidation@M4;1
29MABCDESTKAFGHIJKLMNOPQRCarbamidomethyl@C;Oxidation@M4;18
30MABCDESTKAFGHIJKLMNOPQRCarbamidomethyl@C;Oxidation@M;Oxidation@M4;1;18
31MABCDESTKAFGHIJKLMNOPQRCarbamidomethyl@C4
32MABCDESTKAFGHIJKLMNOPQRCarbamidomethyl@C;Acetyl@Protein N-term;Oxidat...4;0;1
33MABCDESTKAFGHIJKLMNOPQRCarbamidomethyl@C;Acetyl@Protein N-term;Oxidat...4;0;18
34MABCDESTKAFGHIJKLMNOPQRCarbamidomethyl@C;Acetyl@Protein N-term;Oxidat...4;0;1;18
35MABCDESTKAFGHIJKLMNOPQRCarbamidomethyl@C;Acetyl@Protein N-term4;0
\n", + "
" + ], + "text/plain": [ + " sequence \\\n", + "0 AFGHIJK \n", + "1 AFGHIJK \n", + "2 LMNOPQR \n", + "3 LMNOPQR \n", + "4 ABCDESTK \n", + "5 ABCDESTK \n", + "6 MABCDESTK \n", + "7 MABCDESTK \n", + "8 MABCDESTK \n", + "9 MABCDESTK \n", + "10 AFGHIJKLMNOPQR \n", + "11 AFGHIJKLMNOPQR \n", + "12 AFGHIJKLMNOPQR \n", + "13 AFGHIJKLMNOPQR \n", + "14 LMNOPQRAFGHIJK \n", + "15 LMNOPQRAFGHIJK \n", + "16 ABCDESTKAFGHIJK \n", + "17 ABCDESTKAFGHIJK \n", + "18 MABCDESTKAFGHIJK \n", + "19 MABCDESTKAFGHIJK \n", + "20 MABCDESTKAFGHIJK \n", + "21 MABCDESTKAFGHIJK \n", + "22 AFGHIJKLMNOPQRAFGHIJK \n", + "23 AFGHIJKLMNOPQRAFGHIJK \n", + "24 ABCDESTKAFGHIJKLMNOPQR \n", + "25 ABCDESTKAFGHIJKLMNOPQR \n", + "26 ABCDESTKAFGHIJKLMNOPQR \n", + "27 ABCDESTKAFGHIJKLMNOPQR \n", + "28 MABCDESTKAFGHIJKLMNOPQR \n", + "29 MABCDESTKAFGHIJKLMNOPQR \n", + "30 MABCDESTKAFGHIJKLMNOPQR \n", + "31 MABCDESTKAFGHIJKLMNOPQR \n", + "32 MABCDESTKAFGHIJKLMNOPQR \n", + "33 MABCDESTKAFGHIJKLMNOPQR \n", + "34 MABCDESTKAFGHIJKLMNOPQR \n", + "35 MABCDESTKAFGHIJKLMNOPQR \n", + "\n", + " mods mod_sites \n", + "0 \n", + "1 Acetyl@Protein N-term 0 \n", + "2 Oxidation@M 2 \n", + "3 \n", + "4 Carbamidomethyl@C 3 \n", + "5 Carbamidomethyl@C;Acetyl@Protein N-term 3;0 \n", + "6 Carbamidomethyl@C;Oxidation@M 4;1 \n", + "7 Carbamidomethyl@C 4 \n", + "8 Carbamidomethyl@C;Acetyl@Protein N-term;Oxidat... 4;0;1 \n", + "9 Carbamidomethyl@C;Acetyl@Protein N-term 4;0 \n", + "10 Oxidation@M 9 \n", + "11 \n", + "12 Acetyl@Protein N-term;Oxidation@M 0;9 \n", + "13 Acetyl@Protein N-term 0 \n", + "14 Oxidation@M 2 \n", + "15 \n", + "16 Carbamidomethyl@C 3 \n", + "17 Carbamidomethyl@C;Acetyl@Protein N-term 3;0 \n", + "18 Carbamidomethyl@C;Oxidation@M 4;1 \n", + "19 Carbamidomethyl@C 4 \n", + "20 Carbamidomethyl@C;Acetyl@Protein N-term;Oxidat... 4;0;1 \n", + "21 Carbamidomethyl@C;Acetyl@Protein N-term 4;0 \n", + "22 Oxidation@M 9 \n", + "23 \n", + "24 Carbamidomethyl@C;Oxidation@M 3;17 \n", + "25 Carbamidomethyl@C 3 \n", + "26 Carbamidomethyl@C;Acetyl@Protein N-term;Oxidat... 3;0;17 \n", + "27 Carbamidomethyl@C;Acetyl@Protein N-term 3;0 \n", + "28 Carbamidomethyl@C;Oxidation@M 4;1 \n", + "29 Carbamidomethyl@C;Oxidation@M 4;18 \n", + "30 Carbamidomethyl@C;Oxidation@M;Oxidation@M 4;1;18 \n", + "31 Carbamidomethyl@C 4 \n", + "32 Carbamidomethyl@C;Acetyl@Protein N-term;Oxidat... 4;0;1 \n", + "33 Carbamidomethyl@C;Acetyl@Protein N-term;Oxidat... 4;0;18 \n", + "34 Carbamidomethyl@C;Acetyl@Protein N-term;Oxidat... 4;0;1;18 \n", + "35 Carbamidomethyl@C;Acetyl@Protein N-term 4;0 " + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fasta_lib.add_modifications()\n", + "fasta_lib.precursor_df[['sequence','mods','mod_sites']]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`alphabase.protein.fasta.FastaLib.add_additional_modifications` is specially designed for `Phospho`, as it may generate thousands of peptidoforms for a peptide with multiple phospho sites. " + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sequenceprotein_idxesmiss_cleavageis_prot_ntermis_prot_ctermmodsmod_sitesnAAproteinsgenes
0AFGHIJK0;10TrueTrue7xx;yygene
1AFGHIJK0;10TrueTrueAcetyl@Protein N-term07xx;yygene
2LMNOPQR0;10FalseTrueOxidation@M27xx;yygene
3LMNOPQR0;10FalseTrue7xx;yygene
4ABCDESTK00TrueFalseCarbamidomethyl@C;Phospho@S3;68xx
.................................
79MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term;Oxidat...4;0;1;18;823xx
80MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term;Oxidat...4;0;1;1823xx
81MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term;Phospho@S4;0;723xx
82MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term;Phospho@T4;0;823xx
83MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term4;023xx
\n", + "

84 rows × 10 columns

\n", + "
" + ], + "text/plain": [ + " sequence protein_idxes miss_cleavage is_prot_nterm \\\n", + "0 AFGHIJK 0;1 0 True \n", + "1 AFGHIJK 0;1 0 True \n", + "2 LMNOPQR 0;1 0 False \n", + "3 LMNOPQR 0;1 0 False \n", + "4 ABCDESTK 0 0 True \n", + ".. ... ... ... ... \n", + "79 MABCDESTKAFGHIJKLMNOPQR 0 2 True \n", + "80 MABCDESTKAFGHIJKLMNOPQR 0 2 True \n", + "81 MABCDESTKAFGHIJKLMNOPQR 0 2 True \n", + "82 MABCDESTKAFGHIJKLMNOPQR 0 2 True \n", + "83 MABCDESTKAFGHIJKLMNOPQR 0 2 True \n", + "\n", + " is_prot_cterm mods \\\n", + "0 True \n", + "1 True Acetyl@Protein N-term \n", + "2 True Oxidation@M \n", + "3 True \n", + "4 False Carbamidomethyl@C;Phospho@S \n", + ".. ... ... \n", + "79 False Carbamidomethyl@C;Acetyl@Protein N-term;Oxidat... \n", + "80 False Carbamidomethyl@C;Acetyl@Protein N-term;Oxidat... \n", + "81 False Carbamidomethyl@C;Acetyl@Protein N-term;Phospho@S \n", + "82 False Carbamidomethyl@C;Acetyl@Protein N-term;Phospho@T \n", + "83 False Carbamidomethyl@C;Acetyl@Protein N-term \n", + "\n", + " mod_sites nAA proteins genes \n", + "0 7 xx;yy gene \n", + "1 0 7 xx;yy gene \n", + "2 2 7 xx;yy gene \n", + "3 7 xx;yy gene \n", + "4 3;6 8 xx \n", + ".. ... ... ... ... \n", + "79 4;0;1;18;8 23 xx \n", + "80 4;0;1;18 23 xx \n", + "81 4;0;7 23 xx \n", + "82 4;0;8 23 xx \n", + "83 4;0 23 xx \n", + "\n", + "[84 rows x 10 columns]" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fasta_lib.add_additional_modifications(\n", + " ['Phospho@S','Phospho@T'], max_mod_num=1, max_peptidoform_num=100,\n", + ")\n", + "fasta_lib.precursor_df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Flexible method to add peptide labeling" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sequenceprotein_idxesmiss_cleavageis_prot_ntermis_prot_ctermmodsmod_sitesnAAproteinsgeneslabel_channel
0AFGHIJK0;10TrueTrue7xx;yygene
1AFGHIJK0;10TrueTrueAcetyl@Protein N-term07xx;yygene
2LMNOPQR0;10FalseTrueOxidation@M27xx;yygene
3LMNOPQR0;10FalseTrue7xx;yygene
4ABCDESTK00TrueFalseCarbamidomethyl@C;Phospho@S3;68xx
....................................
247MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term;Oxidat...4;0;1;18;8;9;1623xx8
248MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term;Oxidat...4;0;1;18;9;1623xx8
249MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term;Phosph...4;0;7;9;1623xx8
250MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term;Phosph...4;0;8;9;1623xx8
251MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term;Dimeth...4;0;9;1623xx8
\n", + "

252 rows × 11 columns

\n", + "
" + ], + "text/plain": [ + " sequence protein_idxes miss_cleavage is_prot_nterm \\\n", + "0 AFGHIJK 0;1 0 True \n", + "1 AFGHIJK 0;1 0 True \n", + "2 LMNOPQR 0;1 0 False \n", + "3 LMNOPQR 0;1 0 False \n", + "4 ABCDESTK 0 0 True \n", + ".. ... ... ... ... \n", + "247 MABCDESTKAFGHIJKLMNOPQR 0 2 True \n", + "248 MABCDESTKAFGHIJKLMNOPQR 0 2 True \n", + "249 MABCDESTKAFGHIJKLMNOPQR 0 2 True \n", + "250 MABCDESTKAFGHIJKLMNOPQR 0 2 True \n", + "251 MABCDESTKAFGHIJKLMNOPQR 0 2 True \n", + "\n", + " is_prot_cterm mods \\\n", + "0 True \n", + "1 True Acetyl@Protein N-term \n", + "2 True Oxidation@M \n", + "3 True \n", + "4 False Carbamidomethyl@C;Phospho@S \n", + ".. ... ... \n", + "247 False Carbamidomethyl@C;Acetyl@Protein N-term;Oxidat... \n", + "248 False Carbamidomethyl@C;Acetyl@Protein N-term;Oxidat... \n", + "249 False Carbamidomethyl@C;Acetyl@Protein N-term;Phosph... \n", + "250 False Carbamidomethyl@C;Acetyl@Protein N-term;Phosph... \n", + "251 False Carbamidomethyl@C;Acetyl@Protein N-term;Dimeth... \n", + "\n", + " mod_sites nAA proteins genes label_channel \n", + "0 7 xx;yy gene \n", + "1 0 7 xx;yy gene \n", + "2 2 7 xx;yy gene \n", + "3 7 xx;yy gene \n", + "4 3;6 8 xx \n", + ".. ... ... ... ... ... \n", + "247 4;0;1;18;8;9;16 23 xx 8 \n", + "248 4;0;1;18;9;16 23 xx 8 \n", + "249 4;0;7;9;16 23 xx 8 \n", + "250 4;0;8;9;16 23 xx 8 \n", + "251 4;0;9;16 23 xx 8 \n", + "\n", + "[252 rows x 11 columns]" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fasta_lib.add_peptide_labeling({\n", + " '': [], # not labelled for reference\n", + " '0': ['Dimethyl@Any N-term','Dimethyl@K'],\n", + " '8': ['Dimethyl:2H(6)13C(2)@Any N-term','Dimethyl:2H(6)13C(2)@K'],\n", + "})\n", + "fasta_lib.precursor_df" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sequencemodsmod_sitescharge
0AFGHIJK2
1AFGHIJK3
2AFGHIJK4
3AFGHIJKAcetyl@Protein N-term02
4AFGHIJKAcetyl@Protein N-term03
...............
751MABCDESTKAFGHIJKLMNOPQRCarbamidomethyl@C;Acetyl@Protein N-term;Phosph...4;0;8;9;163
752MABCDESTKAFGHIJKLMNOPQRCarbamidomethyl@C;Acetyl@Protein N-term;Phosph...4;0;8;9;164
753MABCDESTKAFGHIJKLMNOPQRCarbamidomethyl@C;Acetyl@Protein N-term;Dimeth...4;0;9;162
754MABCDESTKAFGHIJKLMNOPQRCarbamidomethyl@C;Acetyl@Protein N-term;Dimeth...4;0;9;163
755MABCDESTKAFGHIJKLMNOPQRCarbamidomethyl@C;Acetyl@Protein N-term;Dimeth...4;0;9;164
\n", + "

756 rows × 4 columns

\n", + "
" + ], + "text/plain": [ + " sequence \\\n", + "0 AFGHIJK \n", + "1 AFGHIJK \n", + "2 AFGHIJK \n", + "3 AFGHIJK \n", + "4 AFGHIJK \n", + ".. ... \n", + "751 MABCDESTKAFGHIJKLMNOPQR \n", + "752 MABCDESTKAFGHIJKLMNOPQR \n", + "753 MABCDESTKAFGHIJKLMNOPQR \n", + "754 MABCDESTKAFGHIJKLMNOPQR \n", + "755 MABCDESTKAFGHIJKLMNOPQR \n", + "\n", + " mods mod_sites charge \n", + "0 2 \n", + "1 3 \n", + "2 4 \n", + "3 Acetyl@Protein N-term 0 2 \n", + "4 Acetyl@Protein N-term 0 3 \n", + ".. ... ... ... \n", + "751 Carbamidomethyl@C;Acetyl@Protein N-term;Phosph... 4;0;8;9;16 3 \n", + "752 Carbamidomethyl@C;Acetyl@Protein N-term;Phosph... 4;0;8;9;16 4 \n", + "753 Carbamidomethyl@C;Acetyl@Protein N-term;Dimeth... 4;0;9;16 2 \n", + "754 Carbamidomethyl@C;Acetyl@Protein N-term;Dimeth... 4;0;9;16 3 \n", + "755 Carbamidomethyl@C;Acetyl@Protein N-term;Dimeth... 4;0;9;16 4 \n", + "\n", + "[756 rows x 4 columns]" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fasta_lib.add_charge()\n", + "fasta_lib.precursor_df[['sequence','mods','mod_sites','charge']]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Append precursor mz and isotope information" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
precursor_mzisotope_m1_intensityisotope_apex_intensityisotope_apex_offsetisotope_right_most_intensityisotope_right_most_offsetisotope_m1_mzisotope_apex_mzisotope_right_most_mz
0414.2423380.4791101.00000000.4791101414.743988414.242338414.743988
1506.2738440.5365891.00000000.2086702506.775494506.273844507.277144
2498.2763870.5362081.00000000.2064102498.778037498.276387499.279687
3889.4983410.9934571.00000000.2393823889.999991889.498341891.003291
4593.3346530.9934571.00000000.2393823593.669086593.334653594.337953
..............................
78884.8933211.2596191.25961910.5105753885.227755885.227755885.896621
79663.9218101.2596191.25961910.5105753664.172635664.172635664.674285
801318.8388861.2589721.25897210.50769431319.3405361319.3405361320.343836
81879.5616831.2589721.25897210.5076943879.896116879.896116880.564983
82659.9230811.2589721.25897210.5076943660.173906660.173906660.675556
\n", + "

83 rows × 9 columns

\n", + "
" + ], + "text/plain": [ + " precursor_mz isotope_m1_intensity isotope_apex_intensity \\\n", + "0 414.242338 0.479110 1.000000 \n", + "1 506.273844 0.536589 1.000000 \n", + "2 498.276387 0.536208 1.000000 \n", + "3 889.498341 0.993457 1.000000 \n", + "4 593.334653 0.993457 1.000000 \n", + ".. ... ... ... \n", + "78 884.893321 1.259619 1.259619 \n", + "79 663.921810 1.259619 1.259619 \n", + "80 1318.838886 1.258972 1.258972 \n", + "81 879.561683 1.258972 1.258972 \n", + "82 659.923081 1.258972 1.258972 \n", + "\n", + " isotope_apex_offset isotope_right_most_intensity \\\n", + "0 0 0.479110 \n", + "1 0 0.208670 \n", + "2 0 0.206410 \n", + "3 0 0.239382 \n", + "4 0 0.239382 \n", + ".. ... ... \n", + "78 1 0.510575 \n", + "79 1 0.510575 \n", + "80 1 0.507694 \n", + "81 1 0.507694 \n", + "82 1 0.507694 \n", + "\n", + " isotope_right_most_offset isotope_m1_mz isotope_apex_mz \\\n", + "0 1 414.743988 414.242338 \n", + "1 2 506.775494 506.273844 \n", + "2 2 498.778037 498.276387 \n", + "3 3 889.999991 889.498341 \n", + "4 3 593.669086 593.334653 \n", + ".. ... ... ... \n", + "78 3 885.227755 885.227755 \n", + "79 3 664.172635 664.172635 \n", + "80 3 1319.340536 1319.340536 \n", + "81 3 879.896116 879.896116 \n", + "82 3 660.173906 660.173906 \n", + "\n", + " isotope_right_most_mz \n", + "0 414.743988 \n", + "1 507.277144 \n", + "2 499.279687 \n", + "3 891.003291 \n", + "4 594.337953 \n", + ".. ... \n", + "78 885.896621 \n", + "79 664.674285 \n", + "80 1320.343836 \n", + "81 880.564983 \n", + "82 660.675556 \n", + "\n", + "[83 rows x 9 columns]" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fasta_lib.calc_precursor_mz()\n", + "fasta_lib.calc_precursor_isotope()\n", + "fasta_lib.precursor_df[['precursor_mz']+[col for col in fasta_lib.precursor_df.columns if col.startswith('isotope')]]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using `alphabase.spectral_library.base.SpecLibBase.calc_fragment_mz_df` to calculate fragment mz dataframe." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
b_z1y_z1
0114.054955714.429722
1261.123369567.361308
2318.144833510.339844
3455.203744373.280932
4568.287808260.196868
.........
11232034.240795603.436978
11242091.262258546.415514
11252228.321170409.356602
11262341.405234296.272538
11272454.489298183.188474
\n", + "

1128 rows × 2 columns

\n", + "
" + ], + "text/plain": [ + " b_z1 y_z1\n", + "0 114.054955 714.429722\n", + "1 261.123369 567.361308\n", + "2 318.144833 510.339844\n", + "3 455.203744 373.280932\n", + "4 568.287808 260.196868\n", + "... ... ...\n", + "1123 2034.240795 603.436978\n", + "1124 2091.262258 546.415514\n", + "1125 2228.321170 409.356602\n", + "1126 2341.405234 296.272538\n", + "1127 2454.489298 183.188474\n", + "\n", + "[1128 rows x 2 columns]" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fasta_lib.calc_fragment_mz_df()\n", + "fasta_lib.fragment_mz_df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`calc_fragment_mz_df()` also generate pointers `frag_start_idx` and `frag_end_idx` in the precursor_df to locate fragments of each precursor. " + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
frag_start_idxfrag_end_idx
006
1612
21218
31831
43144
.........
7810281048
7910481068
8010681088
8110881108
8211081128
\n", + "

83 rows × 2 columns

\n", + "
" + ], + "text/plain": [ + " frag_start_idx frag_end_idx\n", + "0 0 6\n", + "1 6 12\n", + "2 12 18\n", + "3 18 31\n", + "4 31 44\n", + ".. ... ...\n", + "78 1028 1048\n", + "79 1048 1068\n", + "80 1068 1088\n", + "81 1088 1108\n", + "82 1108 1128\n", + "\n", + "[83 rows x 2 columns]" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fasta_lib.precursor_df[['frag_start_idx','frag_end_idx']]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that all fragment ions are stored from peptide's N-terminal to C-terminal, so the b-ions are in the ascending order (from b1 to bn) and y-ions are in the decending order (from yn to y1)." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
b_z1y_z1
6114.091340898.456348
7261.126740751.420948
8375.169668637.378020
9612.317394400.230294
10709.370158303.177530
11837.428736175.118952
\n", + "
" + ], + "text/plain": [ + " b_z1 y_z1\n", + "6 114.091340 898.456348\n", + "7 261.126740 751.420948\n", + "8 375.169668 637.378020\n", + "9 612.317394 400.230294\n", + "10 709.370158 303.177530\n", + "11 837.428736 175.118952" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "start, end = fasta_lib.precursor_df[['frag_start_idx','frag_end_idx']].values[1]\n", + "fasta_lib.fragment_mz_df.iloc[start:end,:]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Save protein_df, precursor_df, fragment_mz_df, fragment_intensity_df into a hdf file." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "# fasta_lib.save_hdf('path/to/hdf_file.hdf')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.8.3 ('base')", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.3" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "8a3b27e141e49c996c9b863f8707e97aabd49c4a7e8445b9b783b34e4a21a9b2" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/nbs/library_reader.ipynb b/docs/nbs/library_reader.ipynb new file mode 100644 index 00000000..e6e7e3f6 --- /dev/null +++ b/docs/nbs/library_reader.ipynb @@ -0,0 +1,2174 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Library reader with fragments" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "%reload_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "SWATH/Spectronaut TSV library reader (`SWATHLibraryReader`)." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sequencechargertmobilitymodsmod_sitesnAAfrag_start_idxfrag_end_idxrt_normprecursor_mzccs
0AVVVSPK2-22.8497400.9Phospho@S57060.075327390.206780366.858877
1DPLAVDK2-15.0871000.976120.199375379.208161367.043100
2MGSLDSK2-27.5635000.9Phospho@S3712180.000000409.161712366.564438
3SVSFSLK135.0141100.9Phospho@S3718241.000000847.396112183.178171
4VSVSPGR2-23.9308500.9Phospho@S;Phospho@S2;4724300.058050431.167001366.254833
5YSLSPSK2-6.4281980.9Phospho@S4730360.337745431.191327366.254509
\n", + "
" + ], + "text/plain": [ + " sequence charge rt mobility mods mod_sites nAA \\\n", + "0 AVVVSPK 2 -22.849740 0.9 Phospho@S 5 7 \n", + "1 DPLAVDK 2 -15.087100 0.9 7 \n", + "2 MGSLDSK 2 -27.563500 0.9 Phospho@S 3 7 \n", + "3 SVSFSLK 1 35.014110 0.9 Phospho@S 3 7 \n", + "4 VSVSPGR 2 -23.930850 0.9 Phospho@S;Phospho@S 2;4 7 \n", + "5 YSLSPSK 2 -6.428198 0.9 Phospho@S 4 7 \n", + "\n", + " frag_start_idx frag_end_idx rt_norm precursor_mz ccs \n", + "0 0 6 0.075327 390.206780 366.858877 \n", + "1 6 12 0.199375 379.208161 367.043100 \n", + "2 12 18 0.000000 409.161712 366.564438 \n", + "3 18 24 1.000000 847.396112 183.178171 \n", + "4 24 30 0.058050 431.167001 366.254833 \n", + "5 30 36 0.337745 431.191327 366.254509 " + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from alphabase.spectral_library.reader import SWATHLibraryReader\n", + "from io import StringIO\n", + "tsv_str = \"\"\"PrecursorCharge\tModifiedPeptide\tStrippedPeptide\tiRT\tLabeledPeptide\tPrecursorMz\tFragmentLossType\tFragmentNumber\tFragmentType\tFragmentCharge\tFragmentMz\tRelativeIntensity\tIonMobility\n", + "2\t_DPLAVDK_\tDPLAVDK\t-15.0871\t_DPLAVDK_\t379.2081611\tnoloss\t3\tb\t1\t326.1710473\t14.37029\t0.9\n", + "2\t_DPLAVDK_\tDPLAVDK\t-15.0871\t_DPLAVDK_\t379.2081611\tnoloss\t3\ty\t1\t361.2081611\t37.7585\t0.9\n", + "2\t_DPLAVDK_\tDPLAVDK\t-15.0871\t_DPLAVDK_\t379.2081611\tnoloss\t4\tb\t1\t397.2081611\t9.488808\t0.9\n", + "2\t_DPLAVDK_\tDPLAVDK\t-15.0871\t_DPLAVDK_\t379.2081611\tnoloss\t4\ty\t1\t432.2452749\t100\t0.9\n", + "2\t_DPLAVDK_\tDPLAVDK\t-15.0871\t_DPLAVDK_\t379.2081611\tnoloss\t5\tb\t1\t496.276575\t5.498003\t0.9\n", + "2\t_DPLAVDK_\tDPLAVDK\t-15.0871\t_DPLAVDK_\t379.2081611\tnoloss\t5\ty\t1\t545.3293389\t74.56643\t0.9\n", + "2\t_DPLAVDK_\tDPLAVDK\t-15.0871\t_DPLAVDK_\t379.2081611\tnoloss\t6\ty\t2\t321.6946896\t51.50719\t0.9\n", + "2\t_AVVVS[Phospho (STY)]PK_\tAVVVSPK\t-22.84974\t_AVVVS[Phospho (STY)]PK_\t390.2067795\tnoloss\t3\ty\t1\t411.1639269\t6.911595\t0.9\n", + "2\t_AVVVS[Phospho (STY)]PK_\tAVVVSPK\t-22.84974\t_AVVVS[Phospho (STY)]PK_\t390.2067795\tH3PO4\t3\ty\t1\t313.1870287\t17.38582\t0.9\n", + "2\t_AVVVS[Phospho (STY)]PK_\tAVVVSPK\t-22.84974\t_AVVVS[Phospho (STY)]PK_\t390.2067795\tnoloss\t4\ty\t1\t510.2323409\t10.65426\t0.9\n", + "2\t_AVVVS[Phospho (STY)]PK_\tAVVVSPK\t-22.84974\t_AVVVS[Phospho (STY)]PK_\t390.2067795\tH3PO4\t4\ty\t1\t412.2554427\t37.41231\t0.9\n", + "2\t_AVVVS[Phospho (STY)]PK_\tAVVVSPK\t-22.84974\t_AVVVS[Phospho (STY)]PK_\t390.2067795\tnoloss\t5\ty\t1\t609.3007548\t45.03617\t0.9\n", + "2\t_AVVVS[Phospho (STY)]PK_\tAVVVSPK\t-22.84974\t_AVVVS[Phospho (STY)]PK_\t390.2067795\tH3PO4\t5\ty\t1\t511.3238566\t100\t0.9\n", + "2\t_MGS[Phospho (STY)]LDSK_\tMGSLDSK\t-27.5635\t_MGS[Phospho (STY)]LDSK_\t409.1617118\tnoloss\t3\ty\t1\t349.1717756\t9.20575\t0.9\n", + "2\t_MGS[Phospho (STY)]LDSK_\tMGSLDSK\t-27.5635\t_MGS[Phospho (STY)]LDSK_\t409.1617118\tnoloss\t6\ty\t1\t686.2756622\t10.37339\t0.9\n", + "2\t_MGS[Phospho (STY)]LDSK_\tMGSLDSK\t-27.5635\t_MGS[Phospho (STY)]LDSK_\t409.1617118\tH3PO4\t6\ty\t1\t588.298764\t100\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tnoloss\t3\ty\t1\t347.2288965\t88.27327\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tH3PO4\t3\tb\t1\t256.1291795\t64.97146\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tnoloss\t4\ty\t1\t494.2973105\t100\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tH3PO4\t4\tb\t1\t403.1975934\t35.17805\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tnoloss\t5\ty\t1\t661.2956694\t19.89741\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tH3PO4\t5\tb\t1\t490.2296218\t40.04738\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tH3PO4\t5\ty\t1\t563.3187712\t77.43164\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tnoloss\t6\tb\t1\t701.290584\t24.43497\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tH3PO4\t6\tb\t1\t603.3136858\t63.09999\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\t1(+H2+O)1(+H3+O4+P)\t3\tb\t1\t238.1186147\t62.60851\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\t1(+H2+O)1(+H3+O4+P)\t5\tb\t1\t472.219057\t22.99903\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\t1(+H2+O)1(+H3+O4+P)\t6\tb\t1\t585.303121\t66.30389\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tnoloss\t3\ty\t1\t329.1931797\t100\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tH3PO4\t3\tb\t1\t268.165565\t5.755442\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tnoloss\t4\tb\t2\t267.0740493\t8.743931\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tnoloss\t4\ty\t1\t496.1915387\t27.69686\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tH3PO4\t4\tb\t1\t435.1639239\t6.162673\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\t2(+H3+O4+P)\t4\tb\t1\t337.1870258\t10.84257\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tH3PO4\t4\ty\t1\t398.2146405\t26.28527\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tH3PO4\t5\ty\t1\t497.2830544\t28.41294\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tnoloss\t6\ty\t1\t762.2583115\t8.490795\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tH3PO4\t6\ty\t1\t664.2814133\t32.87384\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\t2(+H3+O4+P)\t6\ty\t1\t566.3045151\t35.87218\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\tnoloss\t3\ty\t1\t331.1975964\t49.20179\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\tnoloss\t4\ty\t1\t498.1959553\t10.89141\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\tH3PO4\t4\ty\t1\t400.2190571\t27.99594\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\tnoloss\t5\ty\t1\t611.2800193\t14.11057\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\tH3PO4\t5\ty\t1\t513.3031211\t70.5295\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\tnoloss\t6\ty\t1\t698.3120477\t60.23455\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\tH3PO4\t6\ty\t1\t600.3351495\t100\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\t1(+H2+O)1(+H3+O4+P)\t6\ty\t1\t582.3245847\t5.233977\t0.9\n", + "\"\"\"\n", + "\n", + "reader = SWATHLibraryReader()\n", + "psm_df = reader.import_file(StringIO(tsv_str))\n", + "for col in ['sequence','charge','rt','rt_norm','mods','mod_sites','nAA','frag_start_idx','frag_end_idx']:\n", + " assert col in psm_df.columns\n", + "reader.psm_df" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
b_z1b_z2y_z1y_z2b_modloss_z1b_modloss_z2y_modloss_z1y_modloss_z2
00.0000000.0000000.0000000.0000000.0000000.00.0000000.0
10.0000000.0000000.4503620.0000000.0000000.01.0000000.0
20.0000000.0000000.1065430.0000000.0000000.00.3741230.0
30.0000000.0000000.0691160.0000000.0000000.00.1738580.0
40.0000000.0000000.0000000.0000000.0000000.00.0000000.0
50.0000000.0000000.0000000.0000000.0000000.00.0000000.0
60.0000000.0000000.0000000.5150720.0000000.00.0000000.0
70.0000000.0000000.7456640.0000000.0000000.00.0000000.0
80.1437030.0000001.0000000.0000000.0000000.00.0000000.0
90.0948880.0000000.3775850.0000000.0000000.00.0000000.0
100.0549800.0000000.0000000.0000000.0000000.00.0000000.0
110.0000000.0000000.0000000.0000000.0000000.00.0000000.0
120.0000000.0000000.1037340.0000000.0000000.01.0000000.0
130.0000000.0000000.0000000.0000000.0000000.00.0000000.0
140.0000000.0000000.0000000.0000000.0000000.00.0000000.0
150.0000000.0000000.0920580.0000000.0000000.00.0000000.0
160.0000000.0000000.0000000.0000000.0000000.00.0000000.0
170.0000000.0000000.0000000.0000000.0000000.00.0000000.0
180.0000000.0000000.0000000.0000000.0000000.00.0000000.0
190.0000000.0000000.1989740.0000000.0000000.00.7743160.0
200.0000000.0000001.0000000.0000000.6497150.00.0000000.0
210.0000000.0000000.8827330.0000000.3517810.00.0000000.0
220.0000000.0000000.0000000.0000000.4004740.00.0000000.0
230.2443500.0000000.0000000.0000000.6310000.00.0000000.0
240.0000000.0000000.0849080.0000000.0000000.00.3287380.0
250.0000000.0000000.0000000.0000000.0000000.00.2841290.0
260.0000000.0000000.2769690.0000000.0575540.00.2628530.0
270.0000000.0874391.0000000.0000000.0616270.00.0000000.0
280.0000000.0000000.0000000.0000000.0000000.00.0000000.0
290.0000000.0000000.0000000.0000000.0000000.00.0000000.0
300.0000000.0000000.6023460.0000000.0000000.01.0000000.0
310.0000000.0000000.1411060.0000000.0000000.00.7052950.0
320.0000000.0000000.1089140.0000000.0000000.00.2799590.0
330.0000000.0000000.4920180.0000000.0000000.00.0000000.0
340.0000000.0000000.0000000.0000000.0000000.00.0000000.0
350.0000000.0000000.0000000.0000000.0000000.00.0000000.0
\n", + "
" + ], + "text/plain": [ + " b_z1 b_z2 y_z1 y_z2 b_modloss_z1 b_modloss_z2 \\\n", + "0 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "1 0.000000 0.000000 0.450362 0.000000 0.000000 0.0 \n", + "2 0.000000 0.000000 0.106543 0.000000 0.000000 0.0 \n", + "3 0.000000 0.000000 0.069116 0.000000 0.000000 0.0 \n", + "4 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "5 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "6 0.000000 0.000000 0.000000 0.515072 0.000000 0.0 \n", + "7 0.000000 0.000000 0.745664 0.000000 0.000000 0.0 \n", + "8 0.143703 0.000000 1.000000 0.000000 0.000000 0.0 \n", + "9 0.094888 0.000000 0.377585 0.000000 0.000000 0.0 \n", + "10 0.054980 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "11 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "12 0.000000 0.000000 0.103734 0.000000 0.000000 0.0 \n", + "13 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "14 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "15 0.000000 0.000000 0.092058 0.000000 0.000000 0.0 \n", + "16 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "17 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "18 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "19 0.000000 0.000000 0.198974 0.000000 0.000000 0.0 \n", + "20 0.000000 0.000000 1.000000 0.000000 0.649715 0.0 \n", + "21 0.000000 0.000000 0.882733 0.000000 0.351781 0.0 \n", + "22 0.000000 0.000000 0.000000 0.000000 0.400474 0.0 \n", + "23 0.244350 0.000000 0.000000 0.000000 0.631000 0.0 \n", + "24 0.000000 0.000000 0.084908 0.000000 0.000000 0.0 \n", + "25 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "26 0.000000 0.000000 0.276969 0.000000 0.057554 0.0 \n", + "27 0.000000 0.087439 1.000000 0.000000 0.061627 0.0 \n", + "28 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "29 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "30 0.000000 0.000000 0.602346 0.000000 0.000000 0.0 \n", + "31 0.000000 0.000000 0.141106 0.000000 0.000000 0.0 \n", + "32 0.000000 0.000000 0.108914 0.000000 0.000000 0.0 \n", + "33 0.000000 0.000000 0.492018 0.000000 0.000000 0.0 \n", + "34 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "35 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "\n", + " y_modloss_z1 y_modloss_z2 \n", + "0 0.000000 0.0 \n", + "1 1.000000 0.0 \n", + "2 0.374123 0.0 \n", + "3 0.173858 0.0 \n", + "4 0.000000 0.0 \n", + "5 0.000000 0.0 \n", + "6 0.000000 0.0 \n", + "7 0.000000 0.0 \n", + "8 0.000000 0.0 \n", + "9 0.000000 0.0 \n", + "10 0.000000 0.0 \n", + "11 0.000000 0.0 \n", + "12 1.000000 0.0 \n", + "13 0.000000 0.0 \n", + "14 0.000000 0.0 \n", + "15 0.000000 0.0 \n", + "16 0.000000 0.0 \n", + "17 0.000000 0.0 \n", + "18 0.000000 0.0 \n", + "19 0.774316 0.0 \n", + "20 0.000000 0.0 \n", + "21 0.000000 0.0 \n", + "22 0.000000 0.0 \n", + "23 0.000000 0.0 \n", + "24 0.328738 0.0 \n", + "25 0.284129 0.0 \n", + "26 0.262853 0.0 \n", + "27 0.000000 0.0 \n", + "28 0.000000 0.0 \n", + "29 0.000000 0.0 \n", + "30 1.000000 0.0 \n", + "31 0.705295 0.0 \n", + "32 0.279959 0.0 \n", + "33 0.000000 0.0 \n", + "34 0.000000 0.0 \n", + "35 0.000000 0.0 " + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reader.fragment_intensity_df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "fragment mz values are theoritically calculated (not from the library files)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
b_z1b_z2y_z1y_z2b_modloss_z1b_modloss_z2y_modloss_z1y_modloss_z2
072.04439036.525833708.369169354.6882230.0000000.000000610.392273305.699775
1171.11280486.060040609.300755305.1540160.0000000.000000511.323860256.165568
2270.181218135.594247510.232341255.6198090.0000000.000000412.255446206.631361
3369.249632185.128454411.163927206.0856020.0000000.000000313.187032157.097154
4536.247991268.627634244.165568122.586422438.271096219.6391860.0000000.000000
5633.300755317.154016147.11280474.060040535.323860268.1655680.0000000.000000
6116.03421958.520748642.382103321.6946900.0000000.0000000.0000000.000000
7213.086983107.047130545.329339273.1683080.0000000.0000000.0000000.000000
8326.171047163.589162432.245275216.6262760.0000000.0000000.0000000.000000
9397.208161199.107719361.208161181.1077190.0000000.0000000.0000000.000000
10496.276575248.641926262.139747131.5735120.0000000.0000000.0000000.000000
11611.303518306.155397147.11280474.0600400.0000000.0000000.0000000.000000
12132.04776266.527519686.275663343.6414700.0000000.000000588.298767294.653022
13189.06922595.038251629.254199315.1307380.0000000.000000531.277303266.142290
14356.067585178.537431462.255840231.631558258.090689129.5489830.0000000.000000
15469.151649235.079463349.171776175.089526371.174753186.0910150.0000000.000000
16584.178592292.592934234.144833117.576055486.201696243.6044860.0000000.000000
17671.210620336.108948147.11280474.060040573.233724287.1205000.0000000.000000
1888.0393050.000000760.3640840.0000000.0000000.000000662.3871880.000000
19187.1077190.000000661.2956700.0000000.0000000.000000563.3187740.000000
20354.1060780.000000494.2973100.000000256.1291830.0000000.0000000.000000
21501.1744920.000000347.2288970.000000403.1975960.0000000.0000000.000000
22588.2065200.000000260.1968680.000000490.2296250.0000000.0000000.000000
23701.2905840.000000147.1128040.000000603.3136890.0000000.0000000.000000
24100.07569050.541483762.258312381.6327940.0000000.000000664.281417332.644347
25267.074050134.040663595.259953298.133615169.09715485.052215497.283057249.145167
26366.142464183.574870496.191539248.599408268.165568134.586422398.214643199.610960
27533.140823267.074050329.193180165.100228435.163927218.0856020.0000000.000000
28630.193587315.600432232.140416116.573846532.216691266.6119840.0000000.000000
29687.215050344.111163175.11895288.063114589.238155295.1227160.0000000.000000
30164.07060582.538941698.312048349.6596620.0000000.000000600.335153300.671214
31251.102633126.054955611.280020306.1436480.0000000.000000513.303124257.155200
32364.186697182.596987498.195956249.6016160.0000000.000000400.219060200.613168
33531.185057266.096167331.197596166.102436433.208161217.1077190.0000000.000000
34628.237821314.622548234.144833117.576055530.260925265.6341010.0000000.000000
35715.269849358.138563147.11280474.060040617.292953309.1501150.0000000.000000
\n", + "
" + ], + "text/plain": [ + " b_z1 b_z2 y_z1 y_z2 b_modloss_z1 \\\n", + "0 72.044390 36.525833 708.369169 354.688223 0.000000 \n", + "1 171.112804 86.060040 609.300755 305.154016 0.000000 \n", + "2 270.181218 135.594247 510.232341 255.619809 0.000000 \n", + "3 369.249632 185.128454 411.163927 206.085602 0.000000 \n", + "4 536.247991 268.627634 244.165568 122.586422 438.271096 \n", + "5 633.300755 317.154016 147.112804 74.060040 535.323860 \n", + "6 116.034219 58.520748 642.382103 321.694690 0.000000 \n", + "7 213.086983 107.047130 545.329339 273.168308 0.000000 \n", + "8 326.171047 163.589162 432.245275 216.626276 0.000000 \n", + "9 397.208161 199.107719 361.208161 181.107719 0.000000 \n", + "10 496.276575 248.641926 262.139747 131.573512 0.000000 \n", + "11 611.303518 306.155397 147.112804 74.060040 0.000000 \n", + "12 132.047762 66.527519 686.275663 343.641470 0.000000 \n", + "13 189.069225 95.038251 629.254199 315.130738 0.000000 \n", + "14 356.067585 178.537431 462.255840 231.631558 258.090689 \n", + "15 469.151649 235.079463 349.171776 175.089526 371.174753 \n", + "16 584.178592 292.592934 234.144833 117.576055 486.201696 \n", + "17 671.210620 336.108948 147.112804 74.060040 573.233724 \n", + "18 88.039305 0.000000 760.364084 0.000000 0.000000 \n", + "19 187.107719 0.000000 661.295670 0.000000 0.000000 \n", + "20 354.106078 0.000000 494.297310 0.000000 256.129183 \n", + "21 501.174492 0.000000 347.228897 0.000000 403.197596 \n", + "22 588.206520 0.000000 260.196868 0.000000 490.229625 \n", + "23 701.290584 0.000000 147.112804 0.000000 603.313689 \n", + "24 100.075690 50.541483 762.258312 381.632794 0.000000 \n", + "25 267.074050 134.040663 595.259953 298.133615 169.097154 \n", + "26 366.142464 183.574870 496.191539 248.599408 268.165568 \n", + "27 533.140823 267.074050 329.193180 165.100228 435.163927 \n", + "28 630.193587 315.600432 232.140416 116.573846 532.216691 \n", + "29 687.215050 344.111163 175.118952 88.063114 589.238155 \n", + "30 164.070605 82.538941 698.312048 349.659662 0.000000 \n", + "31 251.102633 126.054955 611.280020 306.143648 0.000000 \n", + "32 364.186697 182.596987 498.195956 249.601616 0.000000 \n", + "33 531.185057 266.096167 331.197596 166.102436 433.208161 \n", + "34 628.237821 314.622548 234.144833 117.576055 530.260925 \n", + "35 715.269849 358.138563 147.112804 74.060040 617.292953 \n", + "\n", + " b_modloss_z2 y_modloss_z1 y_modloss_z2 \n", + "0 0.000000 610.392273 305.699775 \n", + "1 0.000000 511.323860 256.165568 \n", + "2 0.000000 412.255446 206.631361 \n", + "3 0.000000 313.187032 157.097154 \n", + "4 219.639186 0.000000 0.000000 \n", + "5 268.165568 0.000000 0.000000 \n", + "6 0.000000 0.000000 0.000000 \n", + "7 0.000000 0.000000 0.000000 \n", + "8 0.000000 0.000000 0.000000 \n", + "9 0.000000 0.000000 0.000000 \n", + "10 0.000000 0.000000 0.000000 \n", + "11 0.000000 0.000000 0.000000 \n", + "12 0.000000 588.298767 294.653022 \n", + "13 0.000000 531.277303 266.142290 \n", + "14 129.548983 0.000000 0.000000 \n", + "15 186.091015 0.000000 0.000000 \n", + "16 243.604486 0.000000 0.000000 \n", + "17 287.120500 0.000000 0.000000 \n", + "18 0.000000 662.387188 0.000000 \n", + "19 0.000000 563.318774 0.000000 \n", + "20 0.000000 0.000000 0.000000 \n", + "21 0.000000 0.000000 0.000000 \n", + "22 0.000000 0.000000 0.000000 \n", + "23 0.000000 0.000000 0.000000 \n", + "24 0.000000 664.281417 332.644347 \n", + "25 85.052215 497.283057 249.145167 \n", + "26 134.586422 398.214643 199.610960 \n", + "27 218.085602 0.000000 0.000000 \n", + "28 266.611984 0.000000 0.000000 \n", + "29 295.122716 0.000000 0.000000 \n", + "30 0.000000 600.335153 300.671214 \n", + "31 0.000000 513.303124 257.155200 \n", + "32 0.000000 400.219060 200.613168 \n", + "33 217.107719 0.000000 0.000000 \n", + "34 265.634101 0.000000 0.000000 \n", + "35 309.150115 0.000000 0.000000 " + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reader.fragment_mz_df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "More examples" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
raw_namesequencechargertmobilitymodsmod_sitesnAAfrag_start_idxfrag_end_idxrt_normprecursor_mzccs
0202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph...AGSPDVLR2-0.7970190.780Phospho@S38070.344252447.707675317.236399
1202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph...ALVATPGK2-5.0327030.758Phospho@T587140.261972418.717512308.612143
2202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph...ELIQEYGAQSGGLEK239.0846101.081Phospho@S101514281.000000851.390200436.485165
3202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph...GGSPDLWK230.2007200.775Phospho@S3828350.946396470.202226314.974129
4202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph...NLTEDNSQNQDLIAK212.6500001.0921535490.541092851.915755440.924535
5202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph...SSPLSWR232.9602100.806Phospho@S1749551.000000456.702393327.713047
6202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph...TLTPPLR227.7165900.818Phospho@T3755610.898140439.230786332.788837
7202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph...TRLSPPR2-18.5187200.785Phospho@S4761670.000000453.731485319.205696
\n", + "
" + ], + "text/plain": [ + " raw_name sequence charge \\\n", + "0 202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph... AGSPDVLR 2 \n", + "1 202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph... ALVATPGK 2 \n", + "2 202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph... ELIQEYGAQSGGLEK 2 \n", + "3 202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph... GGSPDLWK 2 \n", + "4 202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph... NLTEDNSQNQDLIAK 2 \n", + "5 202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph... SSPLSWR 2 \n", + "6 202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph... TLTPPLR 2 \n", + "7 202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph... TRLSPPR 2 \n", + "\n", + " rt mobility mods mod_sites nAA frag_start_idx \\\n", + "0 -0.797019 0.780 Phospho@S 3 8 0 \n", + "1 -5.032703 0.758 Phospho@T 5 8 7 \n", + "2 39.084610 1.081 Phospho@S 10 15 14 \n", + "3 30.200720 0.775 Phospho@S 3 8 28 \n", + "4 12.650000 1.092 15 35 \n", + "5 32.960210 0.806 Phospho@S 1 7 49 \n", + "6 27.716590 0.818 Phospho@T 3 7 55 \n", + "7 -18.518720 0.785 Phospho@S 4 7 61 \n", + "\n", + " frag_end_idx rt_norm precursor_mz ccs \n", + "0 7 0.344252 447.707675 317.236399 \n", + "1 14 0.261972 418.717512 308.612143 \n", + "2 28 1.000000 851.390200 436.485165 \n", + "3 35 0.946396 470.202226 314.974129 \n", + "4 49 0.541092 851.915755 440.924535 \n", + "5 55 1.000000 456.702393 327.713047 \n", + "6 61 0.898140 439.230786 332.788837 \n", + "7 67 0.000000 453.731485 319.205696 " + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tsv_str = \"\"\"ReferenceRun\tPrecursorCharge\tWorkflow\tIntModifiedPeptide\tCV\tAllowForNormalization\tModifiedPeptide\tStrippedPeptide\tiRT\tIonMobility\tiRTSourceSpecific\tBGSInferenceId\tIsProteotypic\tIntLabeledPeptide\tLabeledPeptide\tPrecursorMz\tReferenceRunQvalue\tReferenceRunMS1Response\tFragmentLossType\tFragmentNumber\tFragmentType\tFragmentCharge\tFragmentMz\tRelativeIntensity\tExcludeFromAssay\tDatabase\tProteinGroups\tUniProtIds\tProtein Name\tProteinDescription\tOrganisms\tOrganismId\tGenes\tProtein Existence\tSequence Version\tFASTAName\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_ALVAT[+80]PGK_\t\tTrue\t_ALVAT[Phospho (STY)]PGK_\tALVATPGK\t-5.032703\t0.758\t-5.032703\tP19338\tFalse\t_ALVAT[+80]PGK_\t_ALVAT[Phospho (STY)]PGK_\t418.717511324722\t0\t10352\tnoloss\t3\ty\t1\t301.187031733932\t53.1991\tFalse\tsp\tP19338\tP19338\tNUCL_HUMAN\tNucleolin\tHomo sapiens\t\tNCL\t1\t3\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_ALVAT[+80]PGK_\t\tTrue\t_ALVAT[Phospho (STY)]PGK_\tALVATPGK\t-5.032703\t0.758\t-5.032703\tP19338\tFalse\t_ALVAT[+80]PGK_\t_ALVAT[Phospho (STY)]PGK_\t418.717511324722\t0\t10352\tH3PO4\t4\ty\t1\t384.224142529733\t26.31595\tFalse\tsp\tP19338\tP19338\tNUCL_HUMAN\tNucleolin\tHomo sapiens\t\tNCL\t1\t3\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_ALVAT[+80]PGK_\t\tTrue\t_ALVAT[Phospho (STY)]PGK_\tALVATPGK\t-5.032703\t0.758\t-5.032703\tP19338\tFalse\t_ALVAT[+80]PGK_\t_ALVAT[Phospho (STY)]PGK_\t418.717511324722\t0\t10352\tnoloss\t5\ty\t1\t553.238154507802\t54.60104\tFalse\tsp\tP19338\tP19338\tNUCL_HUMAN\tNucleolin\tHomo sapiens\t\tNCL\t1\t3\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_ALVAT[+80]PGK_\t\tTrue\t_ALVAT[Phospho (STY)]PGK_\tALVATPGK\t-5.032703\t0.758\t-5.032703\tP19338\tFalse\t_ALVAT[+80]PGK_\t_ALVAT[Phospho (STY)]PGK_\t418.717511324722\t0\t10352\tH3PO4\t5\ty\t1\t455.261256314443\t46.09977\tFalse\tsp\tP19338\tP19338\tNUCL_HUMAN\tNucleolin\tHomo sapiens\t\tNCL\t1\t3\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_ALVAT[+80]PGK_\t\tTrue\t_ALVAT[Phospho (STY)]PGK_\tALVATPGK\t-5.032703\t0.758\t-5.032703\tP19338\tFalse\t_ALVAT[+80]PGK_\t_ALVAT[Phospho (STY)]PGK_\t418.717511324722\t0\t10352\tnoloss\t6\ty\t1\t652.306568420792\t100\tFalse\tsp\tP19338\tP19338\tNUCL_HUMAN\tNucleolin\tHomo sapiens\t\tNCL\t1\t3\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_ALVAT[+80]PGK_\t\tTrue\t_ALVAT[Phospho (STY)]PGK_\tALVATPGK\t-5.032703\t0.758\t-5.032703\tP19338\tFalse\t_ALVAT[+80]PGK_\t_ALVAT[Phospho (STY)]PGK_\t418.717511324722\t0\t10352\tH3PO4\t6\ty\t1\t554.329670227433\t50.4698\tFalse\tsp\tP19338\tP19338\tNUCL_HUMAN\tNucleolin\tHomo sapiens\t\tNCL\t1\t3\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TLT[+80]PPLR_\t\tTrue\t_TLT[Phospho (STY)]PPLR_\tTLTPPLR\t27.71659\t0.818\t27.71659\tQ5T200\tFalse\t_TLT[+80]PPLR_\t_TLT[Phospho (STY)]PPLR_\t439.230785875227\t0.000138389150379226\t23117\tnoloss\t3\tb\t1\t396.153027901512\t6.3264\tFalse\tsp\tQ5T200\tQ5T200\tZC3HD_HUMAN\tZinc finger CCCH domain-containing protein 13\tHomo sapiens\t\tZC3H13\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TLT[+80]PPLR_\t\tTrue\t_TLT[Phospho (STY)]PPLR_\tTLTPPLR\t27.71659\t0.818\t27.71659\tQ5T200\tFalse\t_TLT[+80]PPLR_\t_TLT[Phospho (STY)]PPLR_\t439.230785875227\t0.000138389150379226\t23117\tnoloss\t3\ty\t1\t385.255780000092\t29.70625\tFalse\tsp\tQ5T200\tQ5T200\tZC3HD_HUMAN\tZinc finger CCCH domain-containing protein 13\tHomo sapiens\t\tZC3H13\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TLT[+80]PPLR_\t\tTrue\t_TLT[Phospho (STY)]PPLR_\tTLTPPLR\t27.71659\t0.818\t27.71659\tQ5T200\tFalse\t_TLT[+80]PPLR_\t_TLT[Phospho (STY)]PPLR_\t439.230785875227\t0.000138389150379226\t23117\tnoloss\t4\ty\t1\t482.308543848942\t100\tFalse\tsp\tQ5T200\tQ5T200\tZC3HD_HUMAN\tZinc finger CCCH domain-containing protein 13\tHomo sapiens\t\tZC3H13\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TLT[+80]PPLR_\t\tTrue\t_TLT[Phospho (STY)]PPLR_\tTLTPPLR\t27.71659\t0.818\t27.71659\tQ5T200\tFalse\t_TLT[+80]PPLR_\t_TLT[Phospho (STY)]PPLR_\t439.230785875227\t0.000138389150379226\t23117\tnoloss\t5\ty\t1\t663.322552838102\t15.22549\tFalse\tsp\tQ5T200\tQ5T200\tZC3HD_HUMAN\tZinc finger CCCH domain-containing protein 13\tHomo sapiens\t\tZC3H13\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TLT[+80]PPLR_\t\tTrue\t_TLT[Phospho (STY)]PPLR_\tTLTPPLR\t27.71659\t0.818\t27.71659\tQ5T200\tFalse\t_TLT[+80]PPLR_\t_TLT[Phospho (STY)]PPLR_\t439.230785875227\t0.000138389150379226\t23117\tH3PO4\t5\ty\t1\t565.345654644743\t78.98973\tFalse\tsp\tQ5T200\tQ5T200\tZC3HD_HUMAN\tZinc finger CCCH domain-containing protein 13\tHomo sapiens\t\tZC3H13\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TLT[+80]PPLR_\t\tTrue\t_TLT[Phospho (STY)]PPLR_\tTLTPPLR\t27.71659\t0.818\t27.71659\tQ5T200\tFalse\t_TLT[+80]PPLR_\t_TLT[Phospho (STY)]PPLR_\t439.230785875227\t0.000138389150379226\t23117\tH3PO4\t6\ty\t1\t678.429718621873\t7.326889\tFalse\tsp\tQ5T200\tQ5T200\tZC3HD_HUMAN\tZinc finger CCCH domain-containing protein 13\tHomo sapiens\t\tZC3H13\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TLT[+80]PPLR_\t\tTrue\t_TLT[Phospho (STY)]PPLR_\tTLTPPLR\t27.71659\t0.818\t27.71659\tQ5T200\tFalse\t_TLT[+80]PPLR_\t_TLT[Phospho (STY)]PPLR_\t439.230785875227\t0.000138389150379226\t23117\tNH3\t3\ty\t1\t368.229231614472\t5.478241\tFalse\tsp\tQ5T200\tQ5T200\tZC3HD_HUMAN\tZinc finger CCCH domain-containing protein 13\tHomo sapiens\t\tZC3H13\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TLT[+80]PPLR_\t\tTrue\t_TLT[Phospho (STY)]PPLR_\tTLTPPLR\t27.71659\t0.818\t27.71659\tQ5T200\tFalse\t_TLT[+80]PPLR_\t_TLT[Phospho (STY)]PPLR_\t439.230785875227\t0.000138389150379226\t23117\tnoloss\t6\ty\t2\t388.706946641022\t5.111521\tFalse\tsp\tQ5T200\tQ5T200\tZC3HD_HUMAN\tZinc finger CCCH domain-containing protein 13\tHomo sapiens\t\tZC3H13\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_AGS[+80]PDVLR_\t\tTrue\t_AGS[Phospho (STY)]PDVLR_\tAGSPDVLR\t-0.7970191\t0.78\t-0.7970191\tQ8NDX6\tTrue\t_AGS[+80]PDVLR_\t_AGS[Phospho (STY)]PDVLR_\t447.707674917012\t0\t20561\tnoloss\t3\ty\t1\t387.271430064232\t52.42308\tFalse\tsp\tQ8NDX6\tQ8NDX6\tZN740_HUMAN\tZinc finger protein 740\tHomo sapiens\t\tZNF740\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_AGS[+80]PDVLR_\t\tTrue\t_AGS[Phospho (STY)]PDVLR_\tAGSPDVLR\t-0.7970191\t0.78\t-0.7970191\tQ8NDX6\tTrue\t_AGS[+80]PDVLR_\t_AGS[Phospho (STY)]PDVLR_\t447.707674917012\t0\t20561\tnoloss\t4\ty\t1\t502.298373088062\t9.560875\tFalse\tsp\tQ8NDX6\tQ8NDX6\tZN740_HUMAN\tZinc finger protein 740\tHomo sapiens\t\tZNF740\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_AGS[+80]PDVLR_\t\tTrue\t_AGS[Phospho (STY)]PDVLR_\tAGSPDVLR\t-0.7970191\t0.78\t-0.7970191\tQ8NDX6\tTrue\t_AGS[+80]PDVLR_\t_AGS[Phospho (STY)]PDVLR_\t447.707674917012\t0\t20561\tnoloss\t5\ty\t1\t599.351136936912\t100\tFalse\tsp\tQ8NDX6\tQ8NDX6\tZN740_HUMAN\tZinc finger protein 740\tHomo sapiens\t\tZNF740\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_AGS[+80]PDVLR_\t\tTrue\t_AGS[Phospho (STY)]PDVLR_\tAGSPDVLR\t-0.7970191\t0.78\t-0.7970191\tQ8NDX6\tTrue\t_AGS[+80]PDVLR_\t_AGS[Phospho (STY)]PDVLR_\t447.707674917012\t0\t20561\tH3PO4\t6\ty\t2\t334.689937067692\t68.40089\tFalse\tsp\tQ8NDX6\tQ8NDX6\tZN740_HUMAN\tZinc finger protein 740\tHomo sapiens\t\tZNF740\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_AGS[+80]PDVLR_\t\tTrue\t_AGS[Phospho (STY)]PDVLR_\tAGSPDVLR\t-0.7970191\t0.78\t-0.7970191\tQ8NDX6\tTrue\t_AGS[+80]PDVLR_\t_AGS[Phospho (STY)]PDVLR_\t447.707674917012\t0\t20561\tH3PO4\t7\ty\t2\t363.200668927977\t27.03024\tFalse\tsp\tQ8NDX6\tQ8NDX6\tZN740_HUMAN\tZinc finger protein 740\tHomo sapiens\t\tZNF740\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TRLS[+80]PPR_\t\tTrue\t_TRLS[Phospho (STY)]PPR_\tTRLSPPR\t-18.51872\t0.785\t-18.51872\tQ96PK6\tTrue\t_TRLS[+80]PPR_\t_TRLS[Phospho (STY)]PPR_\t453.731484366392\t0.000731277163140476\t55003\tnoloss\t3\ty\t1\t369.224479871812\t97.64322\tFalse\tsp\tQ96PK6\tQ96PK6\tRBM14_HUMAN\tRNA-binding protein 14\tHomo sapiens\t\tRBM14\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TRLS[+80]PPR_\t\tTrue\t_TRLS[Phospho (STY)]PPR_\tTRLSPPR\t-18.51872\t0.785\t-18.51872\tQ96PK6\tTrue\t_TRLS[+80]PPR_\t_TRLS[Phospho (STY)]PPR_\t453.731484366392\t0.000731277163140476\t55003\tnoloss\t4\tb\t1\t538.238488860972\t17.74173\tFalse\tsp\tQ96PK6\tQ96PK6\tRBM14_HUMAN\tRNA-binding protein 14\tHomo sapiens\t\tRBM14\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TRLS[+80]PPR_\t\tTrue\t_TRLS[Phospho (STY)]PPR_\tTRLSPPR\t-18.51872\t0.785\t-18.51872\tQ96PK6\tTrue\t_TRLS[+80]PPR_\t_TRLS[Phospho (STY)]PPR_\t453.731484366392\t0.000731277163140476\t55003\tH3PO4\t4\tb\t1\t440.261590667613\t100\tFalse\tsp\tQ96PK6\tQ96PK6\tRBM14_HUMAN\tRNA-binding protein 14\tHomo sapiens\t\tRBM14\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TRLS[+80]PPR_\t\tTrue\t_TRLS[Phospho (STY)]PPR_\tTRLSPPR\t-18.51872\t0.785\t-18.51872\tQ96PK6\tTrue\t_TRLS[+80]PPR_\t_TRLS[Phospho (STY)]PPR_\t453.731484366392\t0.000731277163140476\t55003\tH3PO4\t4\ty\t1\t438.245940603473\t7.038487\tFalse\tsp\tQ96PK6\tQ96PK6\tRBM14_HUMAN\tRNA-binding protein 14\tHomo sapiens\t\tRBM14\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TRLS[+80]PPR_\t\tTrue\t_TRLS[Phospho (STY)]PPR_\tTRLSPPR\t-18.51872\t0.785\t-18.51872\tQ96PK6\tTrue\t_TRLS[+80]PPR_\t_TRLS[Phospho (STY)]PPR_\t453.731484366392\t0.000731277163140476\t55003\tnoloss\t5\ty\t1\t649.306902773962\t6.46876\tFalse\tsp\tQ96PK6\tQ96PK6\tRBM14_HUMAN\tRNA-binding protein 14\tHomo sapiens\t\tRBM14\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TRLS[+80]PPR_\t\tTrue\t_TRLS[Phospho (STY)]PPR_\tTRLSPPR\t-18.51872\t0.785\t-18.51872\tQ96PK6\tTrue\t_TRLS[+80]PPR_\t_TRLS[Phospho (STY)]PPR_\t453.731484366392\t0.000731277163140476\t55003\tH3PO4\t5\tb\t1\t537.314354516463\t10.4885\tFalse\tsp\tQ96PK6\tQ96PK6\tRBM14_HUMAN\tRNA-binding protein 14\tHomo sapiens\t\tRBM14\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TRLS[+80]PPR_\t\tTrue\t_TRLS[Phospho (STY)]PPR_\tTRLSPPR\t-18.51872\t0.785\t-18.51872\tQ96PK6\tTrue\t_TRLS[+80]PPR_\t_TRLS[Phospho (STY)]PPR_\t453.731484366392\t0.000731277163140476\t55003\tH3PO4\t5\ty\t1\t551.330004580603\t20.62304\tFalse\tsp\tQ96PK6\tQ96PK6\tRBM14_HUMAN\tRNA-binding protein 14\tHomo sapiens\t\tRBM14\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TRLS[+80]PPR_\t\tTrue\t_TRLS[Phospho (STY)]PPR_\tTRLSPPR\t-18.51872\t0.785\t-18.51872\tQ96PK6\tTrue\t_TRLS[+80]PPR_\t_TRLS[Phospho (STY)]PPR_\t453.731484366392\t0.000731277163140476\t55003\t1(+H3+N)1(+H3+O4+P)\t4\tb\t1\t423.235042281993\t8.850685\tFalse\tsp\tQ96PK6\tQ96PK6\tRBM14_HUMAN\tRNA-binding protein 14\tHomo sapiens\t\tRBM14\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_S[+80]SPLSWR_\t\tTrue\t_S[Phospho (STY)]SPLSWR_\tSSPLSWR\t32.96021\t0.806\t32.96021\tQ8NEY1;Q8NEY1-3\tFalse\t_S[+80]SPLSWR_\t_S[Phospho (STY)]SPLSWR_\t456.702392575162\t0.00218558823689818\t6996\tnoloss\t3\ty\t1\t448.230293528242\t74.2921\tFalse\tsp\tQ8NEY1;Q8NEY1-3\tQ8NEY1;Q8NEY1-3\tNAV1_HUMAN\tNeuron navigator 1;Isoform of Q8NEY1, Isoform 3 of Neuron navigator 1\tHomo sapiens\t\tNAV1\t1;\t2;\tMCT_human_UP000005640_9606;MCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_S[+80]SPLSWR_\t\tTrue\t_S[Phospho (STY)]SPLSWR_\tSSPLSWR\t32.96021\t0.806\t32.96021\tQ8NEY1;Q8NEY1-3\tFalse\t_S[+80]SPLSWR_\t_S[Phospho (STY)]SPLSWR_\t456.702392575162\t0.00218558823689818\t6996\tnoloss\t4\ty\t1\t561.314357505372\t100\tFalse\tsp\tQ8NEY1;Q8NEY1-3\tQ8NEY1;Q8NEY1-3\tNAV1_HUMAN\tNeuron navigator 1;Isoform of Q8NEY1, Isoform 3 of Neuron navigator 1\tHomo sapiens\t\tNAV1\t1;\t2;\tMCT_human_UP000005640_9606;MCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_S[+80]SPLSWR_\t\tTrue\t_S[Phospho (STY)]SPLSWR_\tSSPLSWR\t32.96021\t0.806\t32.96021\tQ8NEY1;Q8NEY1-3\tFalse\t_S[+80]SPLSWR_\t_S[Phospho (STY)]SPLSWR_\t456.702392575162\t0.00218558823689818\t6996\tnoloss\t5\ty\t1\t658.367121354222\t53.05514\tFalse\tsp\tQ8NEY1;Q8NEY1-3\tQ8NEY1;Q8NEY1-3\tNAV1_HUMAN\tNeuron navigator 1;Isoform of Q8NEY1, Isoform 3 of Neuron navigator 1\tHomo sapiens\t\tNAV1\t1;\t2;\tMCT_human_UP000005640_9606;MCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_S[+80]SPLSWR_\t\tTrue\t_S[Phospho (STY)]SPLSWR_\tSSPLSWR\t32.96021\t0.806\t32.96021\tQ8NEY1;Q8NEY1-3\tFalse\t_S[+80]SPLSWR_\t_S[Phospho (STY)]SPLSWR_\t456.702392575162\t0.00218558823689818\t6996\tH2O\t4\ty\t1\t543.303792701295\t8.122206\tFalse\tsp\tQ8NEY1;Q8NEY1-3\tQ8NEY1;Q8NEY1-3\tNAV1_HUMAN\tNeuron navigator 1;Isoform of Q8NEY1, Isoform 3 of Neuron navigator 1\tHomo sapiens\t\tNAV1\t1;\t2;\tMCT_human_UP000005640_9606;MCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_S[+80]SPLSWR_\t\tTrue\t_S[Phospho (STY)]SPLSWR_\tSSPLSWR\t32.96021\t0.806\t32.96021\tQ8NEY1;Q8NEY1-3\tFalse\t_S[+80]SPLSWR_\t_S[Phospho (STY)]SPLSWR_\t456.702392575162\t0.00218558823689818\t6996\tNH3\t4\ty\t1\t544.287809119752\t11.54993\tFalse\tsp\tQ8NEY1;Q8NEY1-3\tQ8NEY1;Q8NEY1-3\tNAV1_HUMAN\tNeuron navigator 1;Isoform of Q8NEY1, Isoform 3 of Neuron navigator 1\tHomo sapiens\t\tNAV1\t1;\t2;\tMCT_human_UP000005640_9606;MCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_GGS[+80]PDLWK_\t\tTrue\t_GGS[Phospho (STY)]PDLWK_\tGGSPDLWK\t30.20072\t0.775\t30.20072\tQ96JM3\tTrue\t_GGS[+80]PDLWK_\t_GGS[Phospho (STY)]PDLWK_\t470.202225398577\t0\t14524\tnoloss\t3\ty\t1\t446.276181091502\t14.71406\tFalse\tsp\tQ96JM3\tQ96JM3\tCHAP1_HUMAN\tChromosome alignment-maintaining phosphoprotein 1\tHomo sapiens\t\tCHAMP1\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_GGS[+80]PDLWK_\t\tTrue\t_GGS[Phospho (STY)]PDLWK_\tGGSPDLWK\t30.20072\t0.775\t30.20072\tQ96JM3\tTrue\t_GGS[+80]PDLWK_\t_GGS[Phospho (STY)]PDLWK_\t470.202225398577\t0\t14524\tnoloss\t4\ty\t1\t561.303124115332\t33.08263\tFalse\tsp\tQ96JM3\tQ96JM3\tCHAP1_HUMAN\tChromosome alignment-maintaining phosphoprotein 1\tHomo sapiens\t\tCHAMP1\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_GGS[+80]PDLWK_\t\tTrue\t_GGS[Phospho (STY)]PDLWK_\tGGSPDLWK\t30.20072\t0.775\t30.20072\tQ96JM3\tTrue\t_GGS[+80]PDLWK_\t_GGS[Phospho (STY)]PDLWK_\t470.202225398577\t0\t14524\tnoloss\t5\tb\t1\t494.128269705652\t6.559356\tFalse\tsp\tQ96JM3\tQ96JM3\tCHAP1_HUMAN\tChromosome alignment-maintaining phosphoprotein 1\tHomo sapiens\t\tCHAMP1\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_GGS[+80]PDLWK_\t\tTrue\t_GGS[Phospho (STY)]PDLWK_\tGGSPDLWK\t30.20072\t0.775\t30.20072\tQ96JM3\tTrue\t_GGS[+80]PDLWK_\t_GGS[Phospho (STY)]PDLWK_\t470.202225398577\t0\t14524\tnoloss\t5\ty\t1\t658.355887964182\t100\tFalse\tsp\tQ96JM3\tQ96JM3\tCHAP1_HUMAN\tChromosome alignment-maintaining phosphoprotein 1\tHomo sapiens\t\tCHAMP1\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_GGS[+80]PDLWK_\t\tTrue\t_GGS[Phospho (STY)]PDLWK_\tGGSPDLWK\t30.20072\t0.775\t30.20072\tQ96JM3\tTrue\t_GGS[+80]PDLWK_\t_GGS[Phospho (STY)]PDLWK_\t470.202225398577\t0\t14524\tH3PO4\t5\tb\t1\t396.151371512293\t6.920845\tFalse\tsp\tQ96JM3\tQ96JM3\tCHAP1_HUMAN\tChromosome alignment-maintaining phosphoprotein 1\tHomo sapiens\t\tCHAMP1\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_GGS[+80]PDLWK_\t\tTrue\t_GGS[Phospho (STY)]PDLWK_\tGGSPDLWK\t30.20072\t0.775\t30.20072\tQ96JM3\tTrue\t_GGS[+80]PDLWK_\t_GGS[Phospho (STY)]PDLWK_\t470.202225398577\t0\t14524\tnoloss\t6\tb\t1\t607.212333682782\t6.388004\tFalse\tsp\tQ96JM3\tQ96JM3\tCHAP1_HUMAN\tChromosome alignment-maintaining phosphoprotein 1\tHomo sapiens\t\tCHAMP1\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_GGS[+80]PDLWK_\t\tTrue\t_GGS[Phospho (STY)]PDLWK_\tGGSPDLWK\t30.20072\t0.775\t30.20072\tQ96JM3\tTrue\t_GGS[+80]PDLWK_\t_GGS[Phospho (STY)]PDLWK_\t470.202225398577\t0\t14524\tH3PO4\t6\tb\t1\t509.235435489423\t19.9082\tFalse\tsp\tQ96JM3\tQ96JM3\tCHAP1_HUMAN\tChromosome alignment-maintaining phosphoprotein 1\tHomo sapiens\t\tCHAMP1\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_GGS[+80]PDLWK_\t\tTrue\t_GGS[Phospho (STY)]PDLWK_\tGGSPDLWK\t30.20072\t0.775\t30.20072\tQ96JM3\tTrue\t_GGS[+80]PDLWK_\t_GGS[Phospho (STY)]PDLWK_\t470.202225398577\t0\t14524\tH3PO4\t6\ty\t2\t364.192312581327\t80.62402\tFalse\tsp\tQ96JM3\tQ96JM3\tCHAP1_HUMAN\tChromosome alignment-maintaining phosphoprotein 1\tHomo sapiens\t\tCHAMP1\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_GGS[+80]PDLWK_\t\tTrue\t_GGS[Phospho (STY)]PDLWK_\tGGSPDLWK\t30.20072\t0.775\t30.20072\tQ96JM3\tTrue\t_GGS[+80]PDLWK_\t_GGS[Phospho (STY)]PDLWK_\t470.202225398577\t0\t14524\tH3PO4\t7\tb\t1\t695.314748439283\t16.95742\tFalse\tsp\tQ96JM3\tQ96JM3\tCHAP1_HUMAN\tChromosome alignment-maintaining phosphoprotein 1\tHomo sapiens\t\tCHAMP1\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_GGS[+80]PDLWK_\t\tTrue\t_GGS[Phospho (STY)]PDLWK_\tGGSPDLWK\t30.20072\t0.775\t30.20072\tQ96JM3\tTrue\t_GGS[+80]PDLWK_\t_GGS[Phospho (STY)]PDLWK_\t470.202225398577\t0\t14524\tH3PO4\t7\ty\t2\t392.703044441612\t23.94268\tFalse\tsp\tQ96JM3\tQ96JM3\tCHAP1_HUMAN\tChromosome alignment-maintaining phosphoprotein 1\tHomo sapiens\t\tCHAMP1\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_GGS[+80]PDLWK_\t\tTrue\t_GGS[Phospho (STY)]PDLWK_\tGGSPDLWK\t30.20072\t0.775\t30.20072\tQ96JM3\tTrue\t_GGS[+80]PDLWK_\t_GGS[Phospho (STY)]PDLWK_\t470.202225398577\t0\t14524\t1(+H2+O)1(+H3+O4+P)\t6\tb\t1\t491.224876407391\t7.7026\tFalse\tsp\tQ96JM3\tQ96JM3\tCHAP1_HUMAN\tChromosome alignment-maintaining phosphoprotein 1\tHomo sapiens\t\tCHAMP1\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tnoloss\t8\tb\t1\t904.441074140122\t13.24587\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tnoloss\t8\ty\t1\t869.376438885762\t9.73339\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tH3PO4\t8\ty\t1\t771.399540692403\t15.5311\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tnoloss\t9\ty\t1\t926.397902606332\t62.03978\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tH3PO4\t9\ty\t1\t828.421004412973\t100\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tnoloss\t10\ty\t1\t1089.46123113888\t27.16885\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tH3PO4\t10\ty\t1\t991.484332945523\t37.66399\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tnoloss\t11\ty\t1\t1218.50382422685\t11.55311\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tH3PO4\t11\ty\t1\t1120.52692603349\t14.68472\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tnoloss\t12\ty\t2\t673.784839099472\t19.2975\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tH3PO4\t13\ty\t2\t681.338421991357\t5.416843\tTrue\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tH2O\t3\tb\t1\t338.207432704965\t52.51799\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tH2O\t4\tb\t1\t466.266010210245\t11.00296\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tH2O\t5\tb\t1\t595.308603298215\t40.71096\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\t1(+H2+O)1(+H3+O4+P)\t7\ty\t2\t341.679569285214\t6.94033\tTrue\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\t1(+H3+N)1(+H3+O4+P)\t7\ty\t1\t683.335878522073\t9.944985\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\t1(+H3+N)1(+H3+O4+P)\t8\ty\t2\t377.690134386797\t6.051629\tTrue\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\t1(+H2+O)1(+H3+O4+P)\t11\ty\t1\t1102.51636122942\t10.49513\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\t1(+H3+N)1(+H3+O4+P)\t11\ty\t1\t1103.50037764787\t5.966991\tTrue\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tH2O\t12\ty\t2\t664.779556697433\t18.91663\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tNH3\t12\ty\t2\t665.271564906662\t5.459162\tTrue\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\t1(+H2+O)1(+H3+O4+P)\t12\ty\t2\t615.791107600754\t16.20821\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tnoloss\t3\tb\t1\t329.181946353492\t19.79472\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tnoloss\t3\ty\t1\t331.233981926352\t34.45748\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tnoloss\t4\ty\t1\t444.318045903482\t41.93548\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tnoloss\t5\tb\t1\t573.251482465292\t56.89149\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tnoloss\t5\ty\t1\t559.344988927312\t31.81818\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tnoloss\t6\ty\t1\t687.403566432592\t6.744868\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tnoloss\t7\ty\t1\t801.446493873732\t100\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tnoloss\t8\ty\t1\t929.505071379012\t6.158358\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tnoloss\t9\ty\t1\t1016.53709978328\t16.27566\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tnoloss\t10\ty\t1\t1130.58002722442\t14.07625\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tnoloss\t12\ty\t1\t1374.64956333622\t23.60704\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tH2O\t3\tb\t1\t311.171381549415\t27.56598\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tNH3\t8\ty\t1\t912.478522993392\t5.718475\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tNH3\t9\ty\t1\t999.510551397662\t6.744868\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tNH3\t12\ty\t1\t1357.6230149506\t10.41056\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "\"\"\"\n", + "\n", + "reader = SWATHLibraryReader()\n", + "psm_df = reader.import_file(StringIO(tsv_str))\n", + "for col in ['sequence','charge','rt','rt_norm','mods','mod_sites','nAA','frag_start_idx','frag_end_idx']:\n", + " assert col in psm_df.columns\n", + "assert 'raw_name' in psm_df.columns\n", + "psm_df" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
b_z1b_z2y_z1y_z2b_modloss_z1b_modloss_z2y_modloss_z1y_modloss_z2
00.0000000.00.0000000.00.0000000.00.0000000.270302
10.0000000.00.0000000.00.0000000.00.0000000.684009
20.0000000.01.0000000.00.0000000.00.0000000.000000
30.0000000.00.0956090.00.0000000.00.0000000.000000
40.0000000.00.5242310.00.0000000.00.0000000.000000
...........................
620.0000000.00.0646880.00.0000000.00.2062300.000000
630.0000000.00.0000000.00.0000000.00.0703850.000000
640.1774170.00.9764320.01.0000000.00.0000000.000000
650.0000000.00.0000000.00.1048850.00.0000000.000000
660.0000000.00.0000000.00.0000000.00.0000000.000000
\n", + "

67 rows × 8 columns

\n", + "
" + ], + "text/plain": [ + " b_z1 b_z2 y_z1 y_z2 b_modloss_z1 b_modloss_z2 y_modloss_z1 \\\n", + "0 0.000000 0.0 0.000000 0.0 0.000000 0.0 0.000000 \n", + "1 0.000000 0.0 0.000000 0.0 0.000000 0.0 0.000000 \n", + "2 0.000000 0.0 1.000000 0.0 0.000000 0.0 0.000000 \n", + "3 0.000000 0.0 0.095609 0.0 0.000000 0.0 0.000000 \n", + "4 0.000000 0.0 0.524231 0.0 0.000000 0.0 0.000000 \n", + ".. ... ... ... ... ... ... ... \n", + "62 0.000000 0.0 0.064688 0.0 0.000000 0.0 0.206230 \n", + "63 0.000000 0.0 0.000000 0.0 0.000000 0.0 0.070385 \n", + "64 0.177417 0.0 0.976432 0.0 1.000000 0.0 0.000000 \n", + "65 0.000000 0.0 0.000000 0.0 0.104885 0.0 0.000000 \n", + "66 0.000000 0.0 0.000000 0.0 0.000000 0.0 0.000000 \n", + "\n", + " y_modloss_z2 \n", + "0 0.270302 \n", + "1 0.684009 \n", + "2 0.000000 \n", + "3 0.000000 \n", + "4 0.000000 \n", + ".. ... \n", + "62 0.000000 \n", + "63 0.000000 \n", + "64 0.000000 \n", + "65 0.000000 \n", + "66 0.000000 \n", + "\n", + "[67 rows x 8 columns]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reader.fragment_intensity_df" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
b_z1b_z2y_z1y_z2b_modloss_z1b_modloss_z2y_modloss_z1y_modloss_z2
072.04439036.525833823.370960412.1891180.0000000.000000725.394064363.200670
1129.06585465.036565766.349496383.6783860.0000000.000000668.372601334.689939
2296.064213148.535745599.351137300.179207198.08731899.5472970.0000000.000000
3393.116977197.062127502.298373251.652825295.140082148.0736790.0000000.000000
4508.143920254.575598387.271430194.139353410.167025205.5871510.0000000.000000
...........................
62258.156066129.581671649.306903325.1570900.0000000.000000551.330008276.168642
63371.240130186.123703536.222839268.6150580.0000000.000000438.245944219.626610
64538.238489269.622883369.224480185.115878440.261594220.6344350.0000000.000000
65635.291253318.149265272.171716136.589496537.314358269.1608170.0000000.000000
66732.344017366.675647175.11895288.063114634.367121317.6871990.0000000.000000
\n", + "

67 rows × 8 columns

\n", + "
" + ], + "text/plain": [ + " b_z1 b_z2 y_z1 y_z2 b_modloss_z1 \\\n", + "0 72.044390 36.525833 823.370960 412.189118 0.000000 \n", + "1 129.065854 65.036565 766.349496 383.678386 0.000000 \n", + "2 296.064213 148.535745 599.351137 300.179207 198.087318 \n", + "3 393.116977 197.062127 502.298373 251.652825 295.140082 \n", + "4 508.143920 254.575598 387.271430 194.139353 410.167025 \n", + ".. ... ... ... ... ... \n", + "62 258.156066 129.581671 649.306903 325.157090 0.000000 \n", + "63 371.240130 186.123703 536.222839 268.615058 0.000000 \n", + "64 538.238489 269.622883 369.224480 185.115878 440.261594 \n", + "65 635.291253 318.149265 272.171716 136.589496 537.314358 \n", + "66 732.344017 366.675647 175.118952 88.063114 634.367121 \n", + "\n", + " b_modloss_z2 y_modloss_z1 y_modloss_z2 \n", + "0 0.000000 725.394064 363.200670 \n", + "1 0.000000 668.372601 334.689939 \n", + "2 99.547297 0.000000 0.000000 \n", + "3 148.073679 0.000000 0.000000 \n", + "4 205.587151 0.000000 0.000000 \n", + ".. ... ... ... \n", + "62 0.000000 551.330008 276.168642 \n", + "63 0.000000 438.245944 219.626610 \n", + "64 220.634435 0.000000 0.000000 \n", + "65 269.160817 0.000000 0.000000 \n", + "66 317.687199 0.000000 0.000000 \n", + "\n", + "[67 rows x 8 columns]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reader.fragment_mz_df" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "MSFragger generated dimethyl TSV library (noloss='')" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sequencechargertmobilitymodsmod_sitesnAAfrag_start_idxfrag_end_idxrt_normprecursor_mzccs
0EDTEEHHLR42.957368NaNDimethyl:2H(4)@Any N-term09080.271196300.150369NaN
1MQHLIAR310.904905NaNDimethyl:2H(4)@Any N-term078141.000000300.851043NaN
\n", + "
" + ], + "text/plain": [ + " sequence charge rt mobility mods \\\n", + "0 EDTEEHHLR 4 2.957368 NaN Dimethyl:2H(4)@Any N-term \n", + "1 MQHLIAR 3 10.904905 NaN Dimethyl:2H(4)@Any N-term \n", + "\n", + " mod_sites nAA frag_start_idx frag_end_idx rt_norm precursor_mz ccs \n", + "0 0 9 0 8 0.271196 300.150369 NaN \n", + "1 0 7 8 14 1.000000 300.851043 NaN " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tsv_str = \"\"\"PrecursorMz\tProductMz\tAnnotation\tProteinId\tGeneName\tPeptideSequence\tModifiedPeptideSequence\tPrecursorCharge\tLibraryIntensity\tNormalizedRetentionTime\tPrecursorIonMobility\tFragmentType\tFragmentCharge\tFragmentSeriesNumber\tFragmentLossType\tAverageExperimentalRetentionTime\n", + "300.150371\t144.605147\ty2^2\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t293.82037\t2.957367634819564\t\ty\t2\t2\t\t256.87189917542054\n", + "300.150371\t175.118953\ty1^1\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t6975.805942\t2.957367634819564\t\ty\t1\t1\t\t256.87189917542054\n", + "300.150371\t188.111798\ty4^3\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t699.9488765\t2.957367634819564\t\ty\t3\t4\t\t256.87189917542054\n", + "300.150371\t213.13460299999997\ty3^2\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t3899.8066759999997\t2.957367634819564\t\ty\t2\t3\t\t256.87189917542054\n", + "300.150371\t231.125996\ty5^3\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t557.755905\t2.957367634819564\t\ty\t3\t5\t\t256.87189917542054\n", + "300.150371\t277.13322200000005\tb2^1\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t5213.9476395\t2.957367634819564\t\tb\t1\t2\t\t256.87189917542054\n", + "300.150371\t281.664059\ty4^2\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t8268.719133999999\t2.957367634819564\t\ty\t2\t4\t\t256.87189917542054\n", + "300.150371\t288.203017\ty2^1\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t7783.7707125\t2.957367634819564\t\ty\t1\t2\t\t256.87189917542054\n", + "300.150371\t346.185356\ty5^2\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t892.8047019999998\t2.957367634819564\t\ty\t2\t5\t\t256.87189917542054\n", + "300.150371\t378.180901\tb3^1\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t2861.0433905\t2.957367634819564\t\tb\t1\t3\t\t256.87189917542054\n", + "300.150371\t410.70665299999996\ty6^2\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t1104.4970805\t2.957367634819564\t\ty\t2\t6\t\t256.87189917542054\n", + "300.150371\t425.261929\ty3^1\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t10000.0\t2.957367634819564\t\ty\t1\t3\t\t256.87189917542054\n", + "300.150371\t461.23049299999997\ty7^2\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t658.40723\t2.957367634819564\t\ty\t2\t7\t\t256.87189917542054\n", + "300.150371\t507.223495\tb4^1\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t544.8236215\t2.957367634819564\t\tb\t1\t4\t\t256.87189917542054\n", + "300.150371\t562.320842\ty4^1\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t758.6205095\t2.957367634819564\t\ty\t1\t4\t\t256.87189917542054\n", + "300.150371\t691.363436\ty5^1\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t386.09158199999996\t2.957367634819564\t\ty\t1\t5\t\t256.87189917542054\n", + "300.851044\t175.118953\ty1^1\tP14618\tPKM\tMQHLIAR\t(UniMod:199)MQHLIAR\t3\t6232.253602000001\t10.90490543435342\t\ty\t1\t1\t\t396.233918513634\n", + "300.851044\t180.123704\ty3^2\tP14618\tPKM\tMQHLIAR\t(UniMod:199)MQHLIAR\t3\t187.126964\t10.90490543435342\t\ty\t2\t3\t\t396.233918513634\n", + "300.851044\t215.11446800000002\tb3^2\tP14618\tPKM\tMQHLIAR\t(UniMod:199)MQHLIAR\t3\t1356.0843869999999\t10.90490543435342\t\tb\t2\t3\t\t396.233918513634\n", + "300.851044\t236.66573599999998\ty4^2\tP14618\tPKM\tMQHLIAR\t(UniMod:199)MQHLIAR\t3\t310.81490499999995\t10.90490543435342\t\ty\t2\t4\t\t396.233918513634\n", + "300.851044\t246.15606699999998\ty2^1\tP14618\tPKM\tMQHLIAR\t(UniMod:199)MQHLIAR\t3\t8887.643795\t10.90490543435342\t\ty\t1\t2\t\t396.233918513634\n", + "\"\"\"\n", + "reader = SWATHLibraryReader()\n", + "reader.import_file(StringIO(tsv_str))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.8.3 ('base')", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.3" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "8a3b27e141e49c996c9b863f8707e97aabd49c4a7e8445b9b783b34e4a21a9b2" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/nbs/tutorial_user.ipynb b/docs/nbs/psm_readers.ipynb similarity index 56% rename from nbs/tutorial_user.ipynb rename to docs/nbs/psm_readers.ipynb index 086a274c..8c376f66 100644 --- a/nbs/tutorial_user.ipynb +++ b/docs/nbs/psm_readers.ipynb @@ -1,1054 +1,25 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%reload_ext autoreload\n", - "%autoreload 2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## The constants module (alphabase.constants)\n", - "\n", - "The `alphabase.constants` module contains chemical element (`alphabase.constants.element.py`), amino acid (`alphabase.constants.aa.py`) and modification (`alphabase.constants.modification.py`) information, which are basic information for all alphabase functionalities. Check `alphabase/constants/nist_element.yaml`, `alphabase/constants/amino_acid.yaml`, `alphabase/constants/used_mod.yaml` for details.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## The peptide module (alphabase.peptide)\n", - "\n", - "The `peptide` module contains peptide-related functionalities.\n", - "\n", - "### alphabase.peptide.precursor\n", - "\n", - "There are two functions in `alphabase.peptide.precursor`: \n", - "\n", - "- `refine_precursor_df(df)`. Sort df by 'nAA' and `reset_index` inplace. For faster precursor and fragment mass calculation.\n", - "- `update_precursor_mz(df)`/`calc_precursor_mz(df)`. The dataframe must contain `sequence, mods, mod_sites, charge` columns.\n", - "- `hash_precursor_df(df, seed=0)`. It generates int64-based unique identity for the modified peptide (`sequence`, `mods`, and `mod_sites`) in `mod_seq_hash` column. It will also generates int64-based unique identity for the precursor (`sequence`, `mods`, `mod_sites`, and `charge`) in the `mod_seq_charge_hash` column." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
sequencemodsmod_siteschargenAAprecursor_mzmod_seq_hashmod_seq_charge_hash
0ACDEFHMK18980.396450-3613625140520963925-3613625140520963924
1ACDEFHMKAcetyl@Protein N-term0181022.407015-4469340833947450-4469340833947449
2ACDEFHMKCarbamidomethyl@C;Oxidation@M2;728527.21005241513349503938639274151334950393863929
\n", - "
" - ], - "text/plain": [ - " sequence mods mod_sites charge nAA \\\n", - "0 ACDEFHMK 1 8 \n", - "1 ACDEFHMK Acetyl@Protein N-term 0 1 8 \n", - "2 ACDEFHMK Carbamidomethyl@C;Oxidation@M 2;7 2 8 \n", - "\n", - " precursor_mz mod_seq_hash mod_seq_charge_hash \n", - "0 980.396450 -3613625140520963925 -3613625140520963924 \n", - "1 1022.407015 -4469340833947450 -4469340833947449 \n", - "2 527.210052 4151334950393863927 4151334950393863929 " - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import alphabase.peptide.precursor as precursor_utils\n", - "import pandas as pd\n", - "\n", - "df = pd.DataFrame()\n", - "df['sequence'] = ['ACDEFHMK']*3\n", - "df['mods'] = ['',\n", - " 'Acetyl@Protein N-term', \n", - " 'Carbamidomethyl@C;Oxidation@M'\n", - "]\n", - "df['mod_sites'] = ['','0','2;7']\n", - "df['charge'] = [1,1,2]\n", - "\n", - "precursor_utils.update_precursor_mz(df)\n", - "precursor_utils.hash_precursor_df(df, seed=0)\n", - "df" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There should be no duplicated hash codes for different modified peptides and precursors in the df:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "assert ~df.mod_seq_charge_hash.duplicated().any()\n", - "assert ~df.mod_seq_hash.duplicated().any()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If hash collision or duplicates are detected, we can change the seed to generate other hash codes. We should make sure that all mod_seq_hash and mod_seq_charge_hash are unique for modified peptides () and precursors." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
sequencemodsmod_siteschargenAAprecursor_mzmod_seq_hashmod_seq_charge_hash
0ACDEFHMK18980.39645048834177638055897954883417763805589796
1ACDEFHMKAcetyl@Protein N-term0181022.407015287597180480789294287597180480789295
2ACDEFHMKCarbamidomethyl@C;Oxidation@M2;728527.21005242433067886696398324243306788669639834
\n", - "
" - ], - "text/plain": [ - " sequence mods mod_sites charge nAA \\\n", - "0 ACDEFHMK 1 8 \n", - "1 ACDEFHMK Acetyl@Protein N-term 0 1 8 \n", - "2 ACDEFHMK Carbamidomethyl@C;Oxidation@M 2;7 2 8 \n", - "\n", - " precursor_mz mod_seq_hash mod_seq_charge_hash \n", - "0 980.396450 4883417763805589795 4883417763805589796 \n", - "1 1022.407015 287597180480789294 287597180480789295 \n", - "2 527.210052 4243306788669639832 4243306788669639834 " - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "precursor_utils.hash_precursor_df(df, seed=1337)\n", - "df" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### alphabase.peptide.mobility\n", - "\n", - "The `mobility` module provides functionalities converting CCS values into mobility values and vice versa." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
sequencemodsmod_siteschargeccs_predmobility_whatevernAAprecursor_mzmobility_predccs_whatever
0ACDEFHMK13001.08980.3964501.477183203.089245
1ACDEFHMKAcetyl@Protein N-term013001.081022.4070151.478027202.973356
2ACDEFHMKCarbamidomethyl@C;Oxidation@M2;723001.08527.2100520.739312405.782410
\n", - "
" - ], - "text/plain": [ - " sequence mods mod_sites charge ccs_pred \\\n", - "0 ACDEFHMK 1 300 \n", - "1 ACDEFHMK Acetyl@Protein N-term 0 1 300 \n", - "2 ACDEFHMK Carbamidomethyl@C;Oxidation@M 2;7 2 300 \n", - "\n", - " mobility_whatever nAA precursor_mz mobility_pred ccs_whatever \n", - "0 1.0 8 980.396450 1.477183 203.089245 \n", - "1 1.0 8 1022.407015 1.478027 202.973356 \n", - "2 1.0 8 527.210052 0.739312 405.782410 " - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import alphabase.peptide.mobility as mobility\n", - "df = pd.DataFrame()\n", - "df['sequence'] = ['ACDEFHMK']*3\n", - "df['mods'] = ['',\n", - " 'Acetyl@Protein N-term', \n", - " 'Carbamidomethyl@C;Oxidation@M'\n", - "]\n", - "df['mod_sites'] = ['','0','2;7']\n", - "df['charge'] = [1,1,2]\n", - "df['ccs_pred'] = 300 # if we predict ccs values\n", - "df['mobility_whatever'] = 1.0\n", - "\n", - "df['mobility_pred'] = mobility.ccs_to_mobility_for_df(\n", - " df, 'ccs_pred'\n", - ")\n", - "df['ccs_whatever'] = mobility.mobility_to_ccs_for_df(\n", - " df, 'mobility_whatever'\n", - ")\n", - "df" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### alphabase.peptide.fragment\n", - "\n", - "This is the most comprehensive module in alphabase. The most important function is `create_fragment_mz_dataframe`, which creates fragment dataframe for the given precursor_df and insert `frag_start_idx` and `frag_end_idx` in the precursor_df." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
b_z1b_z2y_z1y_z2
072.0443900.000000909.3593360.000000
1175.0535750.000000806.3501510.000000
2290.0805180.000000691.3232080.000000
3419.1231110.000000562.2806150.000000
4566.1915250.000000415.2122010.000000
5703.2504370.000000278.1532890.000000
6834.2909220.000000147.1128040.000000
7114.0549550.000000909.3593360.000000
8217.0641400.000000806.3501510.000000
9332.0910830.000000691.3232080.000000
10461.1336760.000000562.2806150.000000
11608.2020900.000000415.2122010.000000
12745.2610020.000000278.1532890.000000
13876.3014870.000000147.1128040.000000
1472.04439036.525833982.375714491.691495
15232.075039116.541158822.345066411.676171
16347.101982174.054629707.318123354.162700
17476.144575238.575926578.275530289.641403
18623.212989312.110133431.207116216.107196
19760.271901380.639589294.148204147.577740
20907.307301454.157288147.11280474.060040
\n", - "
" - ], - "text/plain": [ - " b_z1 b_z2 y_z1 y_z2\n", - "0 72.044390 0.000000 909.359336 0.000000\n", - "1 175.053575 0.000000 806.350151 0.000000\n", - "2 290.080518 0.000000 691.323208 0.000000\n", - "3 419.123111 0.000000 562.280615 0.000000\n", - "4 566.191525 0.000000 415.212201 0.000000\n", - "5 703.250437 0.000000 278.153289 0.000000\n", - "6 834.290922 0.000000 147.112804 0.000000\n", - "7 114.054955 0.000000 909.359336 0.000000\n", - "8 217.064140 0.000000 806.350151 0.000000\n", - "9 332.091083 0.000000 691.323208 0.000000\n", - "10 461.133676 0.000000 562.280615 0.000000\n", - "11 608.202090 0.000000 415.212201 0.000000\n", - "12 745.261002 0.000000 278.153289 0.000000\n", - "13 876.301487 0.000000 147.112804 0.000000\n", - "14 72.044390 36.525833 982.375714 491.691495\n", - "15 232.075039 116.541158 822.345066 411.676171\n", - "16 347.101982 174.054629 707.318123 354.162700\n", - "17 476.144575 238.575926 578.275530 289.641403\n", - "18 623.212989 312.110133 431.207116 216.107196\n", - "19 760.271901 380.639589 294.148204 147.577740\n", - "20 907.307301 454.157288 147.112804 74.060040" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import alphabase.peptide.fragment as fragment\n", - "\n", - "df = pd.DataFrame()\n", - "df['sequence'] = ['ACDEFHMK']*3\n", - "df['mods'] = ['',\n", - " 'Acetyl@Protein N-term', \n", - " 'Carbamidomethyl@C;Oxidation@M'\n", - "]\n", - "df['mod_sites'] = ['','0','2;7']\n", - "df['charge'] = [1,1,2]\n", - "frag_types = fragment.get_charged_frag_types(['b','y'], 2)\n", - "\n", - "frag_df = fragment.create_fragment_mz_dataframe(\n", - " df, frag_types\n", - ")\n", - "assert 'frag_start_idx' in df.columns and 'frag_end_idx' in df.columns\n", - "frag_df" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that all fragment ions are stored from peptide's N-terminal to C-terminal, so the b-ions are in the ascending order (from b1 to bn) and y-ions are in the decending order (from yn to y1)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Performance for fragment mz calculation" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For large number of precursors in the precursor dataframe, we should use `create_fragment_mz_dataframe_by_sort_precursor`. It is similar to `create_fragment_mz_dataframe` but will change the order of the input precursor_df." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## alphabase.io.hdf\n", - "\n", - "It defines functionalities to operate HDF files. We use it to save the spectrum libraries." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## alphabase.spectral_library\n", - "\n", - "Spectrum library functionalities.\n", - "\n", - "### alphabase.spectral_library.library_base\n", - "\n", - "The base structure (`SpecLibBase` class) of the spectrum library in alphabase. The main functions of this class are to save (`SpecLibBase.save_hdf`) and load (`SpecLibBase.load_hdf`) library into/from hdf file, it will also generate `mod_seq_hash` and `mod_seq_charge_hash` for the precurosr_df.\n", - "\n", - "`SpecLibBase` does not define how to get its fragment_mz_df and fragment_intensity_df, this could be done in its sub-classes. We can also generate fragment_mz_df and fragment_intensity_df outside and assign them to `SpecLibBase._fragment_mz_df` and `SpecLibBase._fragment_intensity_df`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import alphabase.spectral_library.library_base as lib_base\n", - "import numpy as np\n", - "\n", - "\n", - "import tempfile\n", - "import os\n", - "TEMPDIR = tempfile.gettempdir()\n", - "hdf_path = os.path.join(TEMPDIR, \"alphabase_speclib.hdf\")\n", - "\n", - "hdflib = lib_base.SpecLibBase(['b_z1','y_z1'])\n", - "\n", - "df = pd.DataFrame()\n", - "df['sequence'] = ['ACDEFHMK']*3\n", - "df['mods'] = ['',\n", - " 'Acetyl@Protein N-term', \n", - " 'Carbamidomethyl@C;Oxidation@M'\n", - "]\n", - "df['mod_sites'] = ['','0','2;7']\n", - "df['charge'] = [1,1,2]\n", - "hdflib.precursor_df = df\n", - "\n", - "# generate fragment_mz_df outside\n", - "frag_df = fragment.create_fragment_mz_dataframe(df, ['b_z1','y_z1'])\n", - "hdflib._fragment_mz_df = frag_df\n", - "\n", - "hdflib._fragment_intensity_df = pd.DataFrame()\n", - "hdflib.save_hdf(hdf_path)\n", - "\n", - "#test load_hdf\n", - "_hdflib = lib_base.SpecLibBase(['b_z1','y_z1'])\n", - "_hdflib.load_hdf(hdf_path, load_mod_seq=True)\n", - "assert all(_hdflib.precursor_df.sequence.values==df.sequence.values)\n", - "assert all(_hdflib.precursor_df.charge.values==df.charge.values)\n", - "assert np.allclose(_hdflib.fragment_mz_df.values, frag_df)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As we have `mod_seq_charge_hash` to uniqely identify the precursors, we split precursor_df into two sub dataframes in the hdf file. \n", - "\n", - "One is still `precursor_df`, but we remove all str columns from it, thus to speed up the data loading and save the memories:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
chargefrag_end_idxfrag_start_idxmod_seq_charge_hashmod_seq_hashnAA
0170-3613625140520963924-36136251405209639258
11147-4469340833947449-44693408339474508
222114415133495039386392941513349503938639278
\n", - "
" - ], - "text/plain": [ - " charge frag_end_idx frag_start_idx mod_seq_charge_hash \\\n", - "0 1 7 0 -3613625140520963924 \n", - "1 1 14 7 -4469340833947449 \n", - "2 2 21 14 4151334950393863929 \n", - "\n", - " mod_seq_hash nAA \n", - "0 -3613625140520963925 8 \n", - "1 -4469340833947450 8 \n", - "2 4151334950393863927 8 " - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "_hdflib.load_hdf(hdf_path)\n", - "_hdflib.precursor_df" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The other is `mod_seq_df`, all str columns are moved into this df, as well as the hash columns:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
mod_seq_charge_hashmod_seq_hashmod_sitesmodssequence
0-3613625140520963924-3613625140520963925ACDEFHMK
1-4469340833947449-44693408339474500Acetyl@Protein N-termACDEFHMK
2415133495039386392941513349503938639272;7Carbamidomethyl@C;Oxidation@MACDEFHMK
\n", - "
" - ], - "text/plain": [ - " mod_seq_charge_hash mod_seq_hash mod_sites \\\n", - "0 -3613625140520963924 -3613625140520963925 \n", - "1 -4469340833947449 -4469340833947450 0 \n", - "2 4151334950393863929 4151334950393863927 2;7 \n", - "\n", - " mods sequence \n", - "0 ACDEFHMK \n", - "1 Acetyl@Protein N-term ACDEFHMK \n", - "2 Carbamidomethyl@C;Oxidation@M ACDEFHMK " - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "mod_seq_df = _hdflib.load_df_from_hdf(hdf_path, 'mod_seq_df')\n", - "mod_seq_df" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can then easily merge precursor_df and mod_seq_df by `mod_seq_charge_hash` to create the original precursor dataframe. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
chargefrag_end_idxfrag_start_idxmod_seq_charge_hashmod_seq_hashnAAmod_sitesmodssequence
0170-3613625140520963924-36136251405209639258ACDEFHMK
11147-4469340833947449-446934083394745080Acetyl@Protein N-termACDEFHMK
2221144151334950393863929415133495039386392782;7Carbamidomethyl@C;Oxidation@MACDEFHMK
\n", - "
" - ], - "text/plain": [ - " charge frag_end_idx frag_start_idx mod_seq_charge_hash \\\n", - "0 1 7 0 -3613625140520963924 \n", - "1 1 14 7 -4469340833947449 \n", - "2 2 21 14 4151334950393863929 \n", - "\n", - " mod_seq_hash nAA mod_sites mods sequence \n", - "0 -3613625140520963925 8 ACDEFHMK \n", - "1 -4469340833947450 8 0 Acetyl@Protein N-term ACDEFHMK \n", - "2 4151334950393863927 8 2;7 Carbamidomethyl@C;Oxidation@M ACDEFHMK " - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "del mod_seq_df['mod_seq_hash']\n", - "_hdflib.precursor_df = _hdflib.precursor_df.merge(mod_seq_df, on='mod_seq_charge_hash')\n", - "_hdflib.precursor_df" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "... and it is extactly the same with the original one. That says, if we have the fragment_mz/intensity_df and unique identifiers for precursors, we don't need the original `['sequence','mods','mod_sites']` information any more during searching. " + "# PSM readers" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ - "assert all(_hdflib.precursor_df.sequence.values==df.sequence.values)\n", - "assert all(_hdflib.precursor_df.charge.values==df.charge.values)\n", - "assert np.allclose(_hdflib.fragment_mz_df.values, frag_df)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## alphabase.io.psm_reader\n" + "%reload_ext autoreload\n", + "%autoreload 2" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -1064,23 +35,26 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{'alphapept': alphabase.io.psm_reader.alphapept_reader.AlphaPeptReader,\n", - " 'maxquant': alphabase.io.psm_reader.maxquant_reader.MaxQuantReader,\n", - " 'spectronaut': alphabase.io.psm_reader.dia_search_reader.SpectronautReader,\n", - " 'openswath': alphabase.io.psm_reader.dia_search_reader.SwathReader,\n", - " 'swath': alphabase.io.psm_reader.dia_search_reader.SwathReader,\n", - " 'diann': alphabase.io.psm_reader.dia_search_reader.DiannReader,\n", - " 'pfind': alphabase.io.psm_reader.pfind_reader.pFindReader,\n", - " 'msfragger_pepxml': alphabase.io.psm_reader.msfragger_reader.MSFraggerPepXML}" + "{'alphapept': alphabase.psm_reader.alphapept_reader.AlphaPeptReader,\n", + " 'maxquant': alphabase.psm_reader.maxquant_reader.MaxQuantReader,\n", + " 'spectronaut': alphabase.psm_reader.dia_psm_reader.SpectronautReader,\n", + " 'openswath': alphabase.psm_reader.dia_psm_reader.SwathReader,\n", + " 'swath': alphabase.psm_reader.dia_psm_reader.SwathReader,\n", + " 'diann': alphabase.psm_reader.dia_psm_reader.DiannReader,\n", + " 'spectronaut_report': alphabase.psm_reader.dia_psm_reader.SpectronautReportReader,\n", + " 'pfind': alphabase.psm_reader.pfind_reader.pFindReader,\n", + " 'msfragger_psm_tsv': alphabase.psm_reader.msfragger_reader.MSFragger_PSM_TSV_Reader,\n", + " 'msfragger': alphabase.psm_reader.msfragger_reader.MSFragger_PSM_TSV_Reader,\n", + " 'msfragger_pepxml': alphabase.psm_reader.msfragger_reader.MSFraggerPepXML}" ] }, - "execution_count": null, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -1093,12 +67,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We can then use `psm_reader_provider.get_reader` to get a reader and then `import_file`:" + "We can then use `psm_reader_provider.get_reader` to get a reader and then `import_file`. \n", + "\n", + "MaxQaunt msms.txt:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -1216,7 +192,7 @@ "2 30 0.772571 " ] }, - "execution_count": null, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -1234,9 +210,16 @@ "mq_reader.import_file(msms_txt)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "pFind pfind.spectra file at 1% FDR by default:" + ] + }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -1344,7 +327,7 @@ "1 0 25801 Didehydro@K^Any C-term -1 20 597.838602 " ] }, - "execution_count": null, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -1359,9 +342,16 @@ "psm_reader_provider.get_reader('pfind').import_file(txt)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Diann TSV report:" + ] + }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -1395,6 +385,7 @@ " genes\n", " scan_num\n", " score\n", + " fdr\n", " spec_idx\n", " mods\n", " mod_sites\n", @@ -1417,8 +408,9 @@ " SRRD\n", " 30053\n", " 0.999997\n", + " 0.000040\n", " 30052\n", - " Acetyl@Protein N-term\n", + " Acetyl@Any N-term\n", " 0\n", " 17\n", " 1.0\n", @@ -1437,8 +429,9 @@ " SRRD\n", " 30029\n", " 0.995505\n", + " 0.000184\n", " 30028\n", - " Acetyl@Protein N-term\n", + " Acetyl@Any N-term\n", " 0\n", " 17\n", " 1.0\n", @@ -1457,8 +450,9 @@ " SRRD\n", " 30005\n", " 0.997286\n", + " 0.000185\n", " 30004\n", - " Acetyl@Protein N-term\n", + " Acetyl@Any N-term\n", " 0\n", " 17\n", " 1.0\n", @@ -1480,18 +474,18 @@ "1 2 19.9050 1.19500 NaN Q9UH36 SRRD 30029 0.995505 \n", "2 2 19.8893 1.19409 NaN Q9UH36 SRRD 30005 0.997286 \n", "\n", - " spec_idx mods mod_sites nAA rt_norm precursor_mz \\\n", - "0 30052 Acetyl@Protein N-term 0 17 1.0 834.428635 \n", - "1 30028 Acetyl@Protein N-term 0 17 1.0 834.428635 \n", - "2 30004 Acetyl@Protein N-term 0 17 1.0 834.428635 \n", + " fdr spec_idx mods mod_sites nAA rt_norm \\\n", + "0 0.000040 30052 Acetyl@Any N-term 0 17 1.0 \n", + "1 0.000184 30028 Acetyl@Any N-term 0 17 1.0 \n", + "2 0.000185 30004 Acetyl@Any N-term 0 17 1.0 \n", "\n", - " ccs \n", - "0 483.435307 \n", - "1 482.595308 \n", - "2 482.227809 " + " precursor_mz ccs \n", + "0 834.428635 483.435307 \n", + "1 834.428635 482.595308 \n", + "2 834.428635 482.227809 " ] }, - "execution_count": null, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -1510,19 +504,26 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Note that, to support both Bruker and Thermo data, we did not use `Scan Number` in the output dataframe but `spec_idx`. It is the scan number in thermo data. " + "Note that, to support both Bruker and Thermo data, we did not use `Scan Number` in the output dataframe but `spec_idx` (starts with 0). `spec_idx = scan_num - 1` in thermo data. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also read spectronaut/openswath's TSV library with out fragment information." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "We can also read spectronaut/openswath's precursor with out fragment information." + "Spectronaut's output library:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -1635,7 +636,7 @@ "2 MAP7 Acetyl@Protein N-term;Phospho@S 0;4 11 1.0 371.282739 " ] }, - "execution_count": null, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -1655,9 +656,16 @@ "psm_reader_provider.get_reader('spectronaut').import_file(tsv)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "OpenSWATH's library:" + ] + }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -1685,6 +693,7 @@ " charge\n", " rt\n", " precursor_mz\n", + " proteins\n", " mods\n", " mod_sites\n", " nAA\n", @@ -1698,10 +707,11 @@ " 3\n", " 59.0\n", " 685.732240\n", + " 1/O14654\n", " \n", " \n", " 23\n", - " 0.000000\n", + " 0.579568\n", " \n", " \n", " 1\n", @@ -1709,10 +719,11 @@ " 4\n", " 59.2\n", " 514.550999\n", + " 1/O14654\n", " \n", " \n", " 23\n", - " 0.004673\n", + " 0.581532\n", " \n", " \n", " 2\n", @@ -1720,6 +731,7 @@ " 5\n", " 101.8\n", " 728.201724\n", + " 1/O14654\n", " Carbamidomethyl@C\n", " 30\n", " 36\n", @@ -1735,13 +747,13 @@ "1 AAAAAAAAAASGAAIPPLIPPRR 4 59.2 514.550999 \n", "2 AAAAAAAAAASGAAIPPLIPPRRVITLYQCFSVSQR 5 101.8 728.201724 \n", "\n", - " mods mod_sites nAA rt_norm \n", - "0 23 0.000000 \n", - "1 23 0.004673 \n", - "2 Carbamidomethyl@C 30 36 1.000000 " + " proteins mods mod_sites nAA rt_norm \n", + "0 1/O14654 23 0.579568 \n", + "1 1/O14654 23 0.581532 \n", + "2 1/O14654 Carbamidomethyl@C 30 36 1.000000 " ] }, - "execution_count": null, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -1767,6 +779,135 @@ "osw_reader.psm_df" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Spectronaut report:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
raw_namertchargemodsmod_sitessequencenAArt_normprecursor_mz
020211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_0112.8398202Oxidation@M4DATMEVQR80.305279483.221474
120211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_0119.1254812GFSNEVSSK90.454726477.729989
220211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_0140.8268472VIETPENDFK100.970697596.298236
320211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_0142.0593303HLLNQAVGEEEVPK141.000000521.610617
\n", + "
" + ], + "text/plain": [ + " raw_name rt charge \\\n", + "0 20211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_01 12.839820 2 \n", + "1 20211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_01 19.125481 2 \n", + "2 20211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_01 40.826847 2 \n", + "3 20211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_01 42.059330 3 \n", + "\n", + " mods mod_sites sequence nAA rt_norm precursor_mz \n", + "0 Oxidation@M 4 DATMEVQR 8 0.305279 483.221474 \n", + "1 GFSNEVSSK 9 0.454726 477.729989 \n", + "2 VIETPENDFK 10 0.970697 596.298236 \n", + "3 HLLNQAVGEEEVPK 14 1.000000 521.610617 " + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tsv = StringIO('''R.FileName,R.Replicate,EG.PrecursorId,EG.ApexRT,FG.CalibratedMassAccuracy (PPM),FG.CalibratedMz\n", + "20211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_01,1,_VIETPENDFK_.2,40.826847076416,-0.6350307649846,596.298998773218\n", + "20211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_01,1,_GFSNEVSSK_.2,19.1254806518555,-1.54873822486555,477.730400257423\n", + "20211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_01,1,_HLLNQAVGEEEVPK_.3,42.0593299865723,-0.309173676987587,521.611288926824\n", + "20211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_01,1,_DATM[Oxidation (M)]EVQR_.2,12.8398199081421,-3.31103772642203,483.222124398527\n", + "''')\n", + "\n", + "spn_reader = psm_reader_provider.get_reader('spectronaut_report')\n", + "spn_reader.import_file(tsv)\n", + "spn_reader.psm_df" + ] + }, { "cell_type": "code", "execution_count": null, @@ -1780,6 +921,23 @@ "display_name": "Python 3.8.3 ('base')", "language": "python", "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.3" + }, + "vscode": { + "interpreter": { + "hash": "8a3b27e141e49c996c9b863f8707e97aabd49c4a7e8445b9b783b34e4a21a9b2" + } } }, "nbformat": 4, diff --git a/docs/notebooks.rst b/docs/notebooks.rst new file mode 100644 index 00000000..88f432ea --- /dev/null +++ b/docs/notebooks.rst @@ -0,0 +1,11 @@ +Jupyter notebooks +==================== + +Tutorials and notebooks for usages. + +.. toctree:: + :maxdepth: 2 + + nbs/library_from_fasta + nbs/psm_readers + nbs/library_reader \ No newline at end of file diff --git a/docs/peptide/fragment.html b/docs/peptide/fragment.html deleted file mode 100644 index ca773653..00000000 --- a/docs/peptide/fragment.html +++ /dev/null @@ -1,1436 +0,0 @@ - - - - - - - - - -alphabase - Fragment Functionalities - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- -
- - - - - -
- -
-
-

Fragment Functionalities

-
- - - -
- - - -
- - -
- - -
-

First, it is worth mentioning that, in AlphaBase:

-
    -
  1. peptide N-term modification site is 0
  2. -
  3. C-term modification site is -1
  4. -
  5. other modifications sites are integers from 1 to nAA
  6. -
-

Just in case that we have two modifications, one is on the peptide N-term, and the other is on the N-term AA site chain. Similar for C-term sites.

-
-

source

-
-
-

parse_charged_frag_type

-
-
 parse_charged_frag_type (charged_frag_type:str)
-
-

Oppsite to get_charged_frag_types.

- ----- - - - - - - - - - - - - - - - - - - - -
TypeDetails
charged_frag_typestre.g. ‘y_z1’, ‘b_modloss_z1’
Returnstyping.Tuple[str, int]str. Fragment type, e.g. ‘b’,‘y’

int. Charge state
-
/Users/zengwenfeng/opt/anaconda3/lib/python3.8/site-packages/fastcore/docscrape.py:225: UserWarning: Unknown section Examples
-  else: warn(msg)
-
-

source

-
-
-

get_charged_frag_types

-
-
 get_charged_frag_types (frag_types:List[str], max_frag_charge:int=2)
-
-

Combine fragment types and charge states.

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
frag_typestyping.List[str]e.g. [‘b’,‘y’,‘b_modloss’,‘y_modloss’]
max_frag_chargeint2max fragment charge. (default: 2)
Returnstyping.List[str]charged fragment types
-
-
assert np.all(np.array(get_charged_frag_types(['b','b_modloss'],2))==np.array(['b_z1', 'b_z2', 'b_modloss_z1', 'b_modloss_z2']))
-
-
-
assert parse_charged_frag_type('b_z2')==('b',2)
-assert parse_charged_frag_type('b_modloss_z2')==('b_modloss', 2)
-
-
-
-

Fragment dataframe processing

-

In AlphaX Ecosystem, library fragments are stored in a dataframe, where the columns are charged_frag_types (['b_z1','b_z2','y_z1','y_z2','b_modloss_z1','y_H2O_z1'...]) and the rows are corresponding positions (starting with peptide N-term) of the fragments. Library precursor/peptide dataframe must contain frag_start_idx and frag_end_idx columns to tell us where are the fragments of each precursor/peptide.

-

We provide different ways to initialize fragment dataframes, see below:

-
-

source

-
-

init_fragment_by_precursor_dataframe

-
-
 init_fragment_by_precursor_dataframe (precursor_df,
-                                       charged_frag_types:List[str], refer
-                                       ence_fragment_df:pandas.core.frame.
-                                       DataFrame=None,
-                                       dtype:numpy.dtype=<class
-                                       'numpy.float64'>,
-                                       inplace_in_reference:bool=False)
-
-

Init zero fragment dataframe for the precursor_df. If the reference_fragment_df is provided, the result dataframe’s length will be the same as reference_fragment_df. Otherwise it generates the dataframe from scratch.

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
precursor_dfpd.DataFrameprecursors to generate fragment masses,
if precursor_df contains the ‘frag_start_idx’ column,
it is better to provide reference_fragment_df as
precursor_df.frag_start_idx and precursor.frag_end_idx
point to the indices in reference_fragment_df
charged_frag_typestyping.List[str]['b_z1','b_z2','y_z1','y_z2','b_modloss_z1','y_H2O_z1'...]
reference_fragment_dfDataFrameNoneinit zero fragment_mz_df based
on this reference. If None, fragment_mz_df will be
initialized by :func:alphabase.peptide.fragment.init_zero_fragment_dataframe.
Defaults to None.
dtypedtypefloat64
inplace_in_referenceboolFalseif calculate the fragment mz
inplace in the reference_fragment_df (default: False)
Returnspd.DataFramezero fragment_df with given charged_frag_types columns
-
-

source

-
-
-

init_fragment_dataframe_from_other

-
-
 init_fragment_dataframe_from_other
-                                     (reference_fragment_df:pandas.core.fr
-                                     ame.DataFrame, dtype=<class
-                                     'numpy.float64'>)
-
-

Init zero fragment dataframe from the reference_fragment_df (same rows and same columns)

-
-

source

-
-
-

init_zero_fragment_dataframe

-
-
 init_zero_fragment_dataframe (peplen_array:numpy.ndarray,
-                               charged_frag_types:List[str], dtype=<class
-                               'numpy.float64'>)
-
-

Initialize a zero dataframe based on peptide length (nAA) array (peplen_array) and charge_frag_types (column number). The row number of returned dataframe is np.sum(peplen_array-1).

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
peplen_arrayndarraypeptide lengths for the fragment dataframe
charged_frag_typestyping.List[str]['b_z1','b_z2','y_z1','y_z2','b_modloss_z1','y_H2O_z1'...]
dtypetypefloat64
Returnstyping.Tuple[pandas.core.frame.DataFrame, numpy.ndarray, numpy.ndarray]pd.DataFrame, fragment_df with zero values

np.ndarray (int64), the start indices point to the fragment_df for each peptide

np.ndarray (int64), the end indices point to the fragment_df for each peptide
-

For a subset of the precursor dataframe, we need to set or get fragment values for the slicing (by frag_start_idx and frag_end_idxin precursor_df) of the fragment dataframe. We use update_sliced_fragment_dataframe to set the values, and get_sliced_fragment_dataframe to get values.

-
-

source

-
-
-

get_sliced_fragment_dataframe

-
-
 get_sliced_fragment_dataframe (fragment_df:pandas.core.frame.DataFrame,
-                                frag_start_end_list:Union[List,numpy.ndarr
-                                ay], charged_frag_types:List=None)
-
-

Get the sliced fragment_df from frag_start_end_list=[(start,end),(start,end),...].

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
fragment_dfDataFramefragment dataframe to get values
frag_start_end_listtyping.Union[typing.List, numpy.ndarray]List[Tuple[int,int]], e.g. [(start,end),(start,end),...] or np.ndarray
charged_frag_typestyping.ListNonee.g. ['b_z1','b_z2','y_z1','y_z2'].
if None, all columns will be considered
ReturnsDataFramesliced fragment_df. If charged_frag_types is None,
return fragment_df with all columns
-
-

source

-
-
-

update_sliced_fragment_dataframe

-
-
 update_sliced_fragment_dataframe
-                                   (fragment_df:pandas.core.frame.DataFram
-                                   e, values:numpy.ndarray, frag_start_end
-                                   _list:List[Tuple[int,int]],
-                                   charged_frag_types:List[str]=None)
-
-

Set the values of the slices frag_start_end_list=[(start,end),(start,end),...] of fragment_df.

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
fragment_dfDataFramefragment dataframe to set the values
valuesndarrayvalues to set
frag_start_end_listtyping.List[typing.Tuple[int, int]]e.g. [(start,end),(start,end),...]
charged_frag_typestyping.List[str]Nonee.g. ['b_z1','b_z2','y_z1','y_z2'].
If None, the columns of values should be the same as fragment_df’s columns.
It is much faster if charged_frag_types is None as we use numpy slicing,
otherwise we use pd.loc (much slower).
Defaults to None.
ReturnsDataFramefragment_df after the values are set into slices
-

For some search engines, it reports different result files for different raw files. After load them separately, we concatenate precursor_df_list and fragment_df_list into single dataframes respectively. The main processing here is to cumulate frag_start_idx and frag_end_idx for different precursor_dfs.

-
-

source

-
-
-

concat_precursor_fragment_dataframes

-
-
 concat_precursor_fragment_dataframes
-                                       (precursor_df_list:List[pandas.core
-                                       .frame.DataFrame], fragment_df_list
-                                       :List[pandas.core.frame.DataFrame],
-                                       *other_fragment_df_lists)
-
-

Since fragment_df is indexed by precursor_df, when we concatenate multiple fragment_df, the indexed positions will change for in precursor_dfs,
-this function keeps the correct indexed positions of precursor_df when concatenating multiple fragment_df dataframes.

- ----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDetails
precursor_df_listtyping.List[pandas.core.frame.DataFrame]precursor dataframe list to concatenate
fragment_df_listtyping.List[pandas.core.frame.DataFrame]fragment dataframe list to concatenate
other_fragment_df_lists
Returnstyping.Tuple[pandas.core.frame.DataFrame, …]**concatenated precursor_df, fragment_df, *other_fragment_df …**
-
-

source

-
-
-

calc_fragment_mz_values_for_same_nAA

-
-
 calc_fragment_mz_values_for_same_nAA
-                                       (df_group:pandas.core.frame.DataFra
-                                       me, nAA:int,
-                                       charged_frag_types:list)
-
-
-

source

-
-
-

mask_fragments_for_charge_greater_than_precursor_charge

-
-
 mask_fragments_for_charge_greater_than_precursor_charge
-                                                          (fragment_df:pan
-                                                          das.core.frame.D
-                                                          ataFrame, precur
-                                                          sor_charge_array
-                                                          :numpy.ndarray, 
-                                                          nAA_array:numpy.
-                                                          ndarray, candida
-                                                          te_fragment_char
-                                                          ges:list=[2, 3,
-                                                          4])
-
-

Mask the fragment dataframe when the fragment charge is larger than the precursor charge

-
-
-
-

Create fragment mz dataframe

-

This is one of the most important functions in alphabase. For a given precursor_df, it calculates the fragment ion dataframe, and also set the frag_start_idx and frag_end_idx column values to connect the precursor_df and fragment_mz_df.

-

When creating a new fragment mz/intensity dataframes for a precursor, alphabase will check if frag_start_idx exists. As the frag_start_idx points to an existing fragment dataframe (refers to reference_frag_df), so we have to provide the reference_frag_df to make sure that reference_frag_df and newly created fragment_df are consisitent.

-

For the more convenient and faster calculation, we should do as follows: - Sort precursor_df by ‘nAA’ (precursor_df.sort_values('nAA', inplace=True)) to make sure groupby(‘nAA’) will not change the order of the precursor_df. - Reset index (precursor_df.reset_index(drop=True, inplace=True)) to make sure iloc and loc will index the same dataframe subset. - Delete frag_start_idx and frag_end_idx columns if they exist, otherwise the creation speed wil be slower. - Call create_fragment_mz_dataframe_by_sort_precursor(precursor_df, charged_frag_types) or create_fragment_mz_dataframe(precursor_df, charged_frag_types). create_fragment_mz_dataframe will also call create_fragment_mz_dataframe_by_sort_precursor if there is no frag_start_idx column. - If we need to predict/calculate fragment_intensity_df, we can redo step 3 (delete frag idxes columns) and then call ‘intensity prediction’ or ‘intensity calculation’.

-
-

source

-
-

create_fragment_mz_dataframe

-
-
 create_fragment_mz_dataframe (precursor_df:pandas.core.frame.DataFrame,
-                               charged_frag_types:List, reference_fragment
-                               _df:pandas.core.frame.DataFrame=None,
-                               inplace_in_reference:bool=False,
-                               batch_size:int=500000)
-
-

Generate fragment mass dataframe for the precursor_df. If the reference_fragment_df is provided and precursor_df contains frag_start_idx, it will generate the mz dataframe based on the reference. Otherwise it generates the mz dataframe from scratch.

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
precursor_dfDataFrameprecursors to generate fragment masses,
if precursor_df contains the ‘frag_start_idx’ column,
reference_fragment_df must be provided
charged_frag_typestyping.List['b_z1','b_z2','y_z1','y_z2','b_modloss_1','y_H2O_z1'...]
reference_fragment_dfDataFrameNonekwargs only. Generate fragment_mz_df based on this reference,
as precursor_df.frag_start_idx and
precursor.frag_end_idx point to the indices in
reference_fragment_df.
Defaults to None
inplace_in_referenceboolFalsekwargs only. Change values in place in the reference_fragment_df.
Defaults to False
batch_sizeint500000
ReturnsDataFramefragment_mz_df with given charged_frag_types
-
-

source

-
-
-

create_fragment_mz_dataframe_by_sort_precursor

-
-
 create_fragment_mz_dataframe_by_sort_precursor
-                                                 (precursor_df:pandas.core
-                                                 .frame.DataFrame,
-                                                 charged_frag_types:List,
-                                                 batch_size:int=500000)
-
-

Sort nAA in precursor_df for faster fragment mz dataframe creation.

-

Because the fragment mz values are continous in memory, so it is faster when setting values in pandas.

-

Note that this function will change the order and index of precursor_df

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
precursor_dfDataFrameprecursor dataframe
charged_frag_typestyping.Listfragment types list
batch_sizeint500000Calculate fragment mz values in batch.
Defaults to 500000.
ReturnsDataFrame
-
-
-

Examples and unittests:

-

Test create_fragment_mz_dataframe_by_sort_precursor

-

create_fragment_mz_dataframe_by_sort_precursor will sort nAA columns in precursor_df.

-
-
repeat = 2
-peptides = ['AGHCEWQMKAADER']*repeat
-mods = ['Acetyl@Protein N-term;Carbamidomethyl@C;Oxidation@M']*repeat
-sites = ['0;4;8']*repeat
-peptides += ['AGHCEWQMK']*repeat
-mods += ['']*repeat
-sites += ['']*repeat
-
-precursor_df = pd.DataFrame({
-    'sequence': peptides,
-    'mods': mods,
-    'mod_sites': sites
-})
-precursor_df['nAA'] = precursor_df['sequence'].str.len()
-precursor_df['charge'] = [1,1,2,2]
-precursor_df = update_precursor_mz(precursor_df)
-
-fragment_mz_df = create_fragment_mz_dataframe_by_sort_precursor(
-    precursor_df,
-    get_charged_frag_types(['b','y','b_modloss','y_modloss'],2)
-)
-assert precursor_df.nAA.is_monotonic
-assert np.allclose(precursor_df.precursor_mz.values, [545.233862, 545.233862, 1746.732265, 1746.732265])
-ith_pep = 0
-frag_start, frag_end = precursor_df[['frag_start_idx','frag_end_idx']].values[ith_pep]
-assert np.allclose(fragment_mz_df.iloc[frag_start:frag_end]['b_z1'].values, 
-        [ 72.04439025,  129.06585397,  266.12476583,  369.13395079,
-        498.17654388,  684.25585683,  812.31443434,  943.35491942]
-    )
-ith_pep = 2
-frag_start, frag_end = precursor_df[['frag_start_idx','frag_end_idx']].values[ith_pep]
-assert (fragment_mz_df.iloc[frag_start:frag_end]['b_z2'].values==0).all()
-precursor_df
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sequencemodsmod_sitesnAAchargeprecursor_mzfrag_start_idxfrag_end_idx
0AGHCEWQMK92545.23386208
1AGHCEWQMK92545.233862816
2AGHCEWQMKAADERAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;81411746.7322651629
3AGHCEWQMKAADERAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;81411746.7322652942
-
-
-
-

Test get_sliced_fragment_dataframe and update_sliced_fragment_dataframe

-
-
sliced_frag_df = get_sliced_fragment_dataframe(
-    fragment_mz_df, 
-    precursor_df.loc[:0,['frag_start_idx','frag_end_idx']].values,
-    fragment_mz_df.columns.values
-)
-assert np.allclose(fragment_mz_df.iloc[
-        precursor_df['frag_start_idx'].values[0]:precursor_df['frag_end_idx'].values[0],:
-    ].values, sliced_frag_df.values
-)
-sliced_frag_df = get_sliced_fragment_dataframe(
-    fragment_mz_df, 
-    precursor_df.loc[:0,['frag_start_idx','frag_end_idx']].values,
-)
-assert np.allclose(fragment_mz_df.iloc[
-        precursor_df['frag_start_idx'].values[0]:precursor_df['frag_end_idx'].values[0],:
-    ].values, sliced_frag_df.values
-)
-
-ith_pep = 1
-update_sliced_fragment_dataframe(
-    fragment_mz_df, 
-    -np.ones((precursor_df.nAA.values[ith_pep]-1,len(fragment_mz_df.columns))),
-    [(precursor_df['frag_start_idx'].values[ith_pep],precursor_df['frag_end_idx'].values[ith_pep])]
-)
-sliced_frag_df = get_sliced_fragment_dataframe(
-    fragment_mz_df, 
-    precursor_df.loc[ith_pep:ith_pep,['frag_start_idx','frag_end_idx']].values,
-    fragment_mz_df.columns.values
-)
-assert np.allclose(
-    -np.ones((precursor_df.nAA.values[ith_pep]-1,len(fragment_mz_df.columns))), 
-    sliced_frag_df.values
-)
-
-ith_pep = 2
-update_sliced_fragment_dataframe(
-    fragment_mz_df, 
-    -2*np.ones((precursor_df.nAA.values[ith_pep]-1,len(fragment_mz_df.columns))),
-    [(precursor_df['frag_start_idx'].values[ith_pep],precursor_df['frag_end_idx'].values[ith_pep])],
-    charged_frag_types=fragment_mz_df.columns.values
-)
-sliced_frag_df = get_sliced_fragment_dataframe(
-    fragment_mz_df, 
-    precursor_df.loc[ith_pep:ith_pep,['frag_start_idx','frag_end_idx']].values,
-    fragment_mz_df.columns.values
-)
-assert np.allclose(
-    -2*np.ones((precursor_df.nAA.values[ith_pep]-1,len(fragment_mz_df.columns))), 
-    sliced_frag_df.values
-)
-
-

Test create_fragment_mz_dataframe

-

If nAA column is not sorted, create_fragment_mz_dataframe also works. But it would be much slower for large peptide sets.

-
-
repeat = 2
-peptides = ['AGHCEWQMKAADER']*repeat
-mods = ['Acetyl@Protein N-term;Carbamidomethyl@C;Oxidation@M']*repeat
-sites = ['0;4;8']*repeat
-peptides += ['AGHCEWQMK']*repeat
-mods += ['']*repeat
-sites += ['']*repeat
-
-precursor_df = pd.DataFrame({
-    'sequence': peptides,
-    'mods': mods,
-    'mod_sites': sites
-})
-precursor_df['nAA'] = precursor_df['sequence'].str.len()
-precursor_df['charge'] = 2
-assert not precursor_df.nAA.is_monotonic_increasing
-fragment_mz_df = create_fragment_mz_dataframe_by_sort_precursor(
-    precursor_df,
-    get_charged_frag_types(['b','y','b_modloss','y_modloss'],2)
-)
-precursor_df = precursor_df.sort_values('nAA', ascending=False)
-fragment_mz_df1 = create_fragment_mz_dataframe(
-    precursor_df,
-    get_charged_frag_types(['b','y','b_modloss','y_modloss'],2),
-    reference_fragment_df=fragment_mz_df
-)
-ith_pep = 2
-frag_start, frag_end = precursor_df[['frag_start_idx','frag_end_idx']].values[ith_pep]
-assert np.allclose(fragment_mz_df.values, fragment_mz_df1.values)
-assert np.allclose(fragment_mz_df.iloc[frag_start:frag_end]['b_z1'].values, 
-        [ 72.04439025,  129.06585397,  266.12476583,  369.13395079,
-        498.17654388,  684.25585683,  812.31443434,  943.35491942]
-    )
-ith_pep = 0
-frag_start, frag_end = precursor_df[['frag_start_idx','frag_end_idx']].values[ith_pep]
-assert np.allclose(fragment_mz_df.iloc[frag_start:frag_end]['b_z2'].values, 
-        [ 57.5311157 ,  86.04184756, 154.57130349, 234.58662783,
-            299.10792438, 392.14758085, 456.1768696 , 529.69456946,
-            593.74205097, 629.26060786, 664.77916475, 722.29263626,
-            786.81393281]
-    )
-precursor_df
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sequencemodsmod_sitesnAAchargefrag_start_idxfrag_end_idx
2AGHCEWQMKAADERAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;81421629
3AGHCEWQMKAADERAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;81422942
0AGHCEWQMK9208
1AGHCEWQMK92816
-
-
-
-
-
_reference_frag_df = fragment_mz_df
-fragment_mz_df = create_fragment_mz_dataframe(
-    precursor_df,
-    ['b_z1','y_z1'],
-    reference_fragment_df=_reference_frag_df
-)
-assert np.allclose(fragment_mz_df.values, _reference_frag_df[fragment_mz_df.columns])
-
-
-
-

Test mod deltas

-
-
repeat = 1
-peptides = ['AGHCEWQMK']*repeat
-mods = ['Acetyl@Protein N-term;Carbamidomethyl@C;Oxidation@M']*repeat
-sites = ['0;4;8']*repeat
-peptides += ['AGHCEWQMK']*repeat
-mods += ['Acetyl@Protein N-term;Carbamidomethyl@C;Oxidation@M']*repeat
-sites += ['0;4;8']*repeat
-
-precursor_df = pd.DataFrame({
-    'sequence': peptides,
-    'mods': mods,
-    'mod_sites': sites
-})
-precursor_df['nAA'] = precursor_df['sequence'].str.len()
-precursor_df['charge'] = 2
-mod_deltas = ['']*len(precursor_df)
-mod_delta_sites = ['']*len(precursor_df)
-mod_deltas[0],mod_delta_sites[0] = '100;200','0;-1'
-precursor_df['mod_deltas'] = mod_deltas
-precursor_df['mod_delta_sites'] = mod_delta_sites
-update_precursor_mz(precursor_df)
-assert np.allclose(precursor_df.precursor_mz.values, [752.747333, 602.747333])
-fragment_mz_df = create_fragment_mz_dataframe(precursor_df, charged_frag_types=fragment_mz_df.columns.values)
-assert np.allclose(fragment_mz_df['y_z1'].values[precursor_df.frag_start_idx[0]:precursor_df.frag_end_idx[0]], 
-    [1291.43971168, 1234.41824796, 1097.3593361 ,  937.32868742,
-        808.28609433,  622.20678138,  494.14820387,  347.11280417]
-),  f'200 Da must be added to all y-ions'
-assert np.allclose(fragment_mz_df['b_z1'].values[precursor_df.frag_start_idx[0]:precursor_df.frag_end_idx[0]], 
-    [214.05495494,  271.07641866,  408.13533052,  568.1659792 ,
-        697.20857228,  883.28788524, 1011.34646274, 1158.38186245]
-),  f'100 Da must be added to all b-ions'
-precursor_df
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sequencemodsmod_sitesnAAchargemod_deltasmod_delta_sitesprecursor_mzfrag_start_idxfrag_end_idx
0AGHCEWQMKAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;892100;2000;-1752.74733308
1AGHCEWQMKAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;892602.747333816
-
-
-
- - -
-
- -
- -
- - - - \ No newline at end of file diff --git a/docs/peptide/fragment.rst b/docs/peptide/fragment.rst new file mode 100644 index 00000000..b4c1ef8e --- /dev/null +++ b/docs/peptide/fragment.rst @@ -0,0 +1,7 @@ +alphabase.peptide.fragment +========================== + +.. automodule:: alphabase.peptide.fragment + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/peptide/mass_calc.html b/docs/peptide/mass_calc.html deleted file mode 100644 index a581be70..00000000 --- a/docs/peptide/mass_calc.html +++ /dev/null @@ -1,755 +0,0 @@ - - - - - - - - - -alphabase - Mass Calculation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- -
- - - - - -
- -
-
-

Mass Calculation

-
- - - -
- - - -
- - -
- - -
-

it should be only called by alphabase.peptide.fragment.

-
-

source

-
-
-

calc_b_y_and_peptide_mass

-
-
 calc_b_y_and_peptide_mass (sequence:str, mod_names:List[str],
-                            mod_sites:List[int],
-                            mod_deltas:List[float]=None,
-                            mod_delta_sites:List[int]=None)
-
-

It is highly recommend to use calc_b_y_and_peptide_masses_for_same_len_seqs as it is much faster

-
-

source

-
-
-

calc_mod_delta_masses_for_same_len_seqs

-
-
 calc_mod_delta_masses_for_same_len_seqs (nAA:int,
-                                          mod_deltas_list:List[List[float]
-                                          ],
-                                          mod_sites_list:List[List[int]])
-
-

Calculate delta modification masses for the given peptide length (nAA), For open-search, we may also get modification mass deltas other than mod names. This function calculate modification masses from these delta masses.

- ----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDetails
nAAintpeptide length
mod_deltas_listtyping.List[typing.List[float]]
mod_sites_listtyping.List[typing.List[int]]list of modification site list corresponding
to mod_names_list.
* site=0 refers to an N-term modification
* site=-1 refers to a C-term modification
* 1<=site<=peplen refers to a normal modification
Returnsndarray2-D array with shape=(nAA, pep_count or len(mod_names_list))).
Masses of modifications through all the peptides,
0 if sites has no modifications
-
-

source

-
-
-

calc_delta_modification_mass

-
-
 calc_delta_modification_mass (pep_len:int, mass_deltas:List[float],
-                               mass_delta_sites:List[int])
-
-

For open-search, we may also get modification mass deltas other than mod names. This function calculate modification masses from these delta masses.

- ----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDetails
pep_lenintnAA
mass_deltastyping.List[float]mass deltas on the peptide
mass_delta_sitestyping.List[int]localized sites of corresponding mass deltas
Returnsndarray1-D array with length=peplen.
Masses of modifications (mass deltas) through the peptide,
0 if sites has no modifications
-
-
-

calc_peptide_masses_for_same_len_seqs and calc_b_y_and_peptide_masses_for_same_len_seqs are key functions for mass calculation in this module.

-

calc_peptide_masses_for_same_len_seqs calculates the peptide masses for the given sequence array and modification lists.

-

calc_b_y_and_peptide_masses_for_same_len_seqs calculates b/y neutral masses and peptide masses for the given sequence array and modification lists. Note that all a/b/c neutral masses can be calculated from b fragment masses, and x/y/z from y masses. So the key are b/y masses.

-
-

source

-
-
-

calc_b_y_and_peptide_masses_for_same_len_seqs

-
-
 calc_b_y_and_peptide_masses_for_same_len_seqs (sequences:numpy.ndarray,
-                                                mod_list:List[List[str]],
-                                                site_list:List[List[int]],
-                                                mod_delta_list:List[List[f
-                                                loat]]=None, mod_delta_sit
-                                                e_list:List[List[int]]=Non
-                                                e)
-
-

Calculate b/y fragment masses and peptide masses for peptide sequences with same lengths. We need ‘same_len’ here because numpy can process AA sequences with same length very fast.

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
sequencesndarray
mod_listtyping.List[typing.List[str]]list of modifications ,
e.g. [['Oxidation@M','Phospho@S'],['Phospho@S','Deamidated@N']]
site_listtyping.List[typing.List[int]]list of modification sites
corresponding to mod_list, e.g. [[3,6],[4,17]]
mod_delta_listtyping.List[typing.List[float]]Nonelist of modifications,
e.g. [[15.994915,79.966331],[79.966331,0.984016]]
mod_delta_site_listtyping.List[typing.List[int]]Nonelist of modification mass delta sites
corresponding to mod_list, e.g. [[3,6],[4,17]]
Returnstyping.Tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray]neutral b fragment masses (2-D array)
-
-

source

-
-
-

calc_peptide_masses_for_same_len_seqs

-
-
 calc_peptide_masses_for_same_len_seqs (sequences:numpy.ndarray,
-                                        mod_list:List[str],
-                                        mod_delta_list:List[str]=None)
-
-

Calculate peptide masses for peptide sequences with same lengths. We need ‘same_len’ here because numpy can process AA sequences with same length very fast. See alphabase.aa.calc_sequence_masses_for_same_len_seqs

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
sequencesndarray
mod_listtyping.List[str]list of modifications,
e.g. ['Oxidation@M;Phospho@S','Phospho@S;Deamidated@N']
mod_delta_listtyping.List[str]None
Returnsndarraypeptide masses (1-D array, H2O already added)
-
-
-

Testing

-
-
seq, mods, mod_sites = 'AGHCEWQMK', ['Carbamidomethyl@C', 'Oxidation@M'], [4, 8]
-b,y,pepmass = calc_b_y_and_peptide_mass(seq, mods, mod_sites)
-assert np.allclose(b, [  71.03711379,  128.05857751,  265.11748936,  425.14813804,
-         554.19073113,  740.27004408,  868.32862159, 1015.3640213 ]
-)
-assert np.allclose(y, [  [1090.43243521, 1033.41097149,  896.35205963,  736.32141095,
-         607.27881786,  421.19950491,  293.14092741,  146.1055277 ] ]
-)
-assert np.allclose(pepmass, 1161.46954899713)
-
-
-
b_frags,y_frags,pepmasses=calc_b_y_and_peptide_masses_for_same_len_seqs([seq]*2, [mods,[]], [mod_sites,[]])
-assert np.allclose(b_frags[0], [  71.03711379,  128.05857751,  265.11748936,  425.14813804,
-         554.19073113,  740.27004408,  868.32862159, 1015.3640213 ]
-)
-assert np.allclose(y_frags[0], [  [1090.43243521, 1033.41097149,  896.35205963,  736.32141095,
-         607.27881786,  421.19950491,  293.14092741,  146.1055277 ] ]
-)
-assert np.allclose(pepmasses[0], 1161.46954899713)
-
-
-
assert np.allclose(calc_peptide_masses_for_same_len_seqs([seq]*2, [';'.join(mods),""]), [1161.469549  , 1088.45317066])
-
- - -
- -
- -
- - - - \ No newline at end of file diff --git a/docs/peptide/mass_calc.rst b/docs/peptide/mass_calc.rst new file mode 100644 index 00000000..d7bb1c46 --- /dev/null +++ b/docs/peptide/mass_calc.rst @@ -0,0 +1,7 @@ +alphabase.peptide.mass_calc +=========================== + +.. automodule:: alphabase.peptide.mass_calc + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/peptide/mobility.html b/docs/peptide/mobility.html deleted file mode 100644 index f20f1cc7..00000000 --- a/docs/peptide/mobility.html +++ /dev/null @@ -1,557 +0,0 @@ - - - - - - - - - -alphabase - CCS/Mobility Functionalities - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- -
- - - - - -
- -
-
-

CCS/Mobility Functionalities

-
- - - -
- - - -
- - -
- - -
-

source

-
-

mobility_to_ccs_for_df

-
-
 mobility_to_ccs_for_df (precursor_df:pandas.core.frame.DataFrame,
-                         mobility_column:str, vendor='bruker')
-
- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
precursor_dfDataFrameprecursor_df
mobility_columnstrmobility column name in precursor_df
vendorstrbrukerDifferent vender may have different IM calculation.
Defaults to “bruker”.
Note that other vendors are not implemented currently.
ReturnsndarrayCCS values
-
-

source

-
-
-

ccs_to_mobility_for_df

-
-
 ccs_to_mobility_for_df (precursor_df:pandas.core.frame.DataFrame,
-                         ccs_column:str, vendor='bruker')
-
- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
precursor_dfDataFrameprecursor_df
ccs_columnstrCCS column name in precursor_df
vendorstrbrukerDifferent vender may have different IM calculation.
Defaults to “bruker”.
Note that other vendors are not implemented currently.
Returnsndarraymobility values
-
-

source

-
-
-

mobility_to_ccs_bruker

-
-
 mobility_to_ccs_bruker (im_values:numpy.ndarray, charges:numpy.ndarray,
-                         precursor_mzs:numpy.ndarray)
-
-

Convert mobility to CCS for Bruker (timsTOF)

-
-

source

-
-
-

ccs_to_mobility_bruker

-
-
 ccs_to_mobility_bruker (ccs_values:numpy.ndarray, charges:numpy.ndarray,
-                         precursor_mzs:numpy.ndarray)
-
-

Convert CCS to mobility for Bruker (timsTOF)

-
-

source

-
-
-

get_reduced_mass

-
-
 get_reduced_mass (precursor_mzs:numpy.ndarray, charges:numpy.ndarray)
-
-

Reduced mass for CCS and mobility calculation

- - -
- -
- -
- - - - \ No newline at end of file diff --git a/docs/peptide/mobility.rst b/docs/peptide/mobility.rst new file mode 100644 index 00000000..5965599e --- /dev/null +++ b/docs/peptide/mobility.rst @@ -0,0 +1,7 @@ +alphabase.peptide.mobility +========================== + +.. automodule:: alphabase.peptide.mobility + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/peptide/precursor.html b/docs/peptide/precursor.html deleted file mode 100644 index 10aa23d7..00000000 --- a/docs/peptide/precursor.html +++ /dev/null @@ -1,975 +0,0 @@ - - - - - - - - - -alphabase - Precursor Functionalities - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- -
- - - - - -
- -
-
-

Precursor Functionalities

-
- - - -
- - - -
- - -
- - -
-

source

-
-

update_precursor_mz

-
-
 update_precursor_mz (precursor_df:pandas.core.frame.DataFrame,
-                      batch_size=500000)
-
-

Calculate precursor_mz inplace in the precursor_df

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
precursor_dfDataFrameprecursor_df with the ‘charge’ column
batch_sizeint500000
ReturnsDataFrameprecursor_df with ‘precursor_mz’
-
-

source

-
-
-

is_precursor_refined

-
-
 is_precursor_refined (precursor_df:pandas.core.frame.DataFrame)
-
-
-

source

-
-
-

refine_precursor_df

-
-
 refine_precursor_df (df:pandas.core.frame.DataFrame, drop_frag_idx=True,
-                      ensure_data_validity=False)
-
-

Refine df inplace for faster precursor/fragment calculation.

-
-

source

-
-
-

hash_precursor_df

-
-
 hash_precursor_df (precursor_df:pandas.core.frame.DataFrame, seed:int=0)
-
-

Add columns ‘mod_seq_hash’ and ‘mod_seq_charge_hash’ into precursor_df (inplace). The 64-bit hash function is from mmh3 (mmh3.hash64).

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
precursor_dfDataFrameprecursor_df
seedint0
ReturnsDataFrameDataFrame with columns ‘mod_seq_hash’ and ‘mod_seq_charge_hash’
-
-

source

-
-
-

hash_mod_seq_charge_df

-
-
 hash_mod_seq_charge_df (precursor_df:pandas.core.frame.DataFrame, seed=0)
-
-

Internal function

-
-

source

-
-
-

hash_mod_seq_df

-
-
 hash_mod_seq_df (precursor_df:pandas.core.frame.DataFrame, seed=0)
-
-

Internal function

-
-

source

-
-
-

get_mod_seq_charge_hash

-
-
 get_mod_seq_charge_hash (sequence:str, mods:str, mod_sites:str,
-                          charge:int, seed=0)
-
-

Get hash code value for a precursor: (sequence, mods, mod_sites, charge)

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
sequencestrAmino acid sequence
modsstrModification names in AlphaBase format
mod_sitesstrModification sites in AlphaBase format
chargeintPrecursor charge state
seedint0Seed for hashing.
Optional, by default 0
Returnsnp.int6464-bit hash code value
-
-

source

-
-
-

get_mod_seq_hash

-
-
 get_mod_seq_hash (sequence:str, mods:str, mod_sites:str, seed:int=0)
-
-

Get hash code value for a peptide: (sequence, mods, mod_sites)

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
sequencestrAmino acid sequence
modsstrModification names in AlphaBase format
mod_sitesstrModification sites in AlphaBase format
seedint0Seed for hashing.
Optional, by default 0
Returnsint6464-bit hash code value
-
-

source

-
-
-

calc_precursor_isotope_mp

-
-
 calc_precursor_isotope_mp (precursor_df:pandas.core.frame.DataFrame,
-                            processes:int=8, mp_batch_size:int=100000,
-                            process_bar=None,
-                            min_right_most_intensity:float=0.2)
-
-

calc_precursor_isotope is not that fast for large dataframes, so here we use multiprocessing for faster isotope pattern calculation. The speed is acceptable with multiprocessing (3.8 min for 21M precursors, 8 processes).

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
precursor_dfDataFramePrecursor_df to calculate
processesint8Process number. Optional, by default 8
mp_batch_sizeint100000Multiprocessing batch size. Optional, by default 100000.
process_barNoneTypeNoneThe tqdm-based callback function
to check multiprocessing. Defaults to None.
min_right_most_intensityfloat0.2The minimal intensity value of the right-most peak relative to apex peak.
Optional, by default 0.2
ReturnsDataFrameprecursor_df with additional columns:
- isotope_m1_intensity
- isotope_m1_mz
- isotope_apex_intensity
- isotope_apex_mz
- isotope_apex_index
- isotope_right_most_intensity
- isotope_right_most_mz
- isotope_right_most_index
-
-

source

-
-
-

calc_precursor_isotope

-
-
 calc_precursor_isotope (precursor_df:pandas.core.frame.DataFrame,
-                         min_right_most_intensity:float=0.2)
-
-

Calculate isotope mz values and relative (to M0) intensity values for precursor_df inplace.

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
precursor_dfDataFrameprecursor_df to calculate
min_right_most_intensityfloat0.2The minimal intensity value of the right-most peak relative to apex peak.
Optional, by default 0.2
Returnspd.DataFrameprecursor_df with additional columns:
- isotope_m1_intensity
- isotope_m1_mz
- isotope_apex_intensity
- isotope_apex_mz
- isotope_apex_index
- isotope_right_most_intensity
- isotope_right_most_mz
- isotope_right_most_index
-
-

source

-
-
-

get_mod_seq_isotope_distribution

-
-
 get_mod_seq_isotope_distribution (seq_mods:tuple,
-                                   isotope_dist:alphabase.constants.isotop
-                                   e.IsotopeDistribution,
-                                   min_right_most_intensity:float=0.2)
-
-

Get isotope abundance distribution by IsotopeDistribution. This function is designed for multiprocessing.

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
seq_modstuple(sequence, mods)
isotope_distIsotopeDistributionSee IsotopeDistribution in alphabase.constants.isotope
min_right_most_intensityfloat0.2The minimal intensity value of the right-most peak relative to apex peak.
Optional, by default 0.2
Returnstuplefloat - Abundance of mono+1 / mono
float - Abundance of apex / mono
int - Apex isotope position relative to mono,
i.e. apex index - mono index and
0 refers to the position of mono itself
float - Abundance of right-most peak which has at least min_right_most_intensity
intensity relative to the apex peak
int - Right-most position relative to mono,
i.e. right-most index - mono index
-
-

source

-
-
-

get_right_most_isotope_index

-
-
 get_right_most_isotope_index (intensities:numpy.ndarray, apex_idx:int,
-                               min_right_most_intensity:float)
-
-

Get right-most isotope index

- ----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDetails
intensitiesndarrayIsotope intensities
apex_idxintThe index or position of apex peak
min_right_most_intensityfloatMinimal intensity to consider for right-most peak relative to apex
ReturnsintIndex or position of the right-most peak
-
-

source

-
-
-

get_mod_seq_formula

-
-
 get_mod_seq_formula (seq:str, mods:str)
-
-

‘PEPTIDE’,‘Acetyl@Any N-term’ –> [(‘C’,n), (‘H’,m), …]

-
-
-

Testing

-
-
repeat = 2
-peptides = ['AGHCEWQMKAADER']*repeat
-mods = ['Acetyl@Protein N-term;Carbamidomethyl@C;Oxidation@M']*repeat
-sites = ['0;4;8']*repeat
-peptides += ['AGHCEWQMK']*repeat
-mods += ['']*repeat
-sites += ['']*repeat
-
-precursor_df = pd.DataFrame({
-    'sequence': peptides,
-    'mods': mods,
-    'mod_sites': sites
-})
-precursor_df['nAA'] = precursor_df['sequence'].str.len()
-precursor_df['charge'] = 2
-
- - -
- -
- -
- - - - \ No newline at end of file diff --git a/docs/peptide/precursor.rst b/docs/peptide/precursor.rst new file mode 100644 index 00000000..4794fddd --- /dev/null +++ b/docs/peptide/precursor.rst @@ -0,0 +1,7 @@ +alphabase.peptide.precursor +=========================== + +.. automodule:: alphabase.peptide.precursor + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/protein/fasta.html b/docs/protein/fasta.html deleted file mode 100644 index 4892f583..00000000 --- a/docs/protein/fasta.html +++ /dev/null @@ -1,3311 +0,0 @@ - - - - - - - - - -alphabase - Protein and Peptide Processing - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- -
- - - - - -
- -
-
-

Protein and Peptide Processing

-
- - - -
- - - -
- - -
- - -
-

source

-
-

concat_proteins

-
-
 concat_proteins (protein_dict:dict, sep='$')
-
-

Concatenate all protein sequences into a single sequence, seperated by sep ($ by default).

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
protein_dictdictprotein_dict by read_fasta_file()
sepstr$
Returnsstrconcatenated sequence seperated by sep.
-
-

source

-
-
-

load_all_proteins

-
-
 load_all_proteins (fasta_file_list:list)
-
-
/Users/zengwenfeng/opt/anaconda3/lib/python3.8/site-packages/fastcore/docscrape.py:225: UserWarning: Unknown section Yields
-  else: warn(msg)
-
-

source

-
-
-

read_fasta_file

-
-
 read_fasta_file (fasta_filename:str='')
-
-

Read a FASTA file line by line

- - - - - - - - - - - - - - - - - -
TypeDefaultDetails
fasta_filenamestrfasta.
-
-

source

-
-
-

get_uniprot_gene_name

-
-
 get_uniprot_gene_name (description:str)
-
-
-

source

-
-
-

Digest

-
-
 Digest (protease:str='trypsin/P', max_missed_cleavages:int=2,
-         peptide_length_min:int=6, peptide_length_max:int=45)
-
-

Digest a protein sequence

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
proteasestrtrypsin/Pprotease name, could be pre-defined name defined in protease_dict
or a regular expression. By default ‘trypsin/P’
max_missed_cleavagesint2Max number of misses cleavage sites.
By default 2
peptide_length_minint6Minimal cleaved peptide length, by default 6
peptide_length_maxint45Maximal cleaved peptide length, by default 45
-
-

source

-
-
-

cleave_sequence_with_cut_pos

-
-
 cleave_sequence_with_cut_pos (sequence:str, cut_pos:numpy.ndarray,
-                               n_missed_cleavages:int=2,
-                               pep_length_min:int=6,
-                               pep_length_max:int=45)
-
-

Cleave a sequence with cut postions (cut_pos). Filters to have a minimum and maximum length.

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
sequencestrprotein sequence
cut_posndarraycut postions determined by a given protease.
n_missed_cleavagesint2the number of max missed cleavages.
pep_length_minint6min peptide length.
pep_length_maxint45max peptide length.
ReturnstupleList[str]. Cleaved peptide sequences with missed cleavages.

List[int]. Number of miss cleavage of each peptide.

List[bool]. If N-term peptide

List[bool]. If C-term pepetide
-
-

source

-
-
-

Digest.cleave_sequence

-
-
 Digest.cleave_sequence (sequence:str)
-
-

Cleave a sequence.

- ----- - - - - - - - - - - - - - - - - - - - -
TypeDetails
sequencestrthe given (protein) sequence.
Returnstuplelist[str]: cleaved peptide sequences with missed cleavages
list[int]: miss cleavage list
list[bool]: is protein N-term
list[bool]: is protein C-term
-
-

source

-
-
-

get_fix_mods

-
-
 get_fix_mods (sequence:str, fix_mod_aas:str, fix_mod_dict:dict)
-
-

Generate fix modifications for the sequence

-
-
seq = 'ACBCDCK'
-_fix_mod_dict = {}
-_fix_mod_dict['C'] = 'mod@C'
-mods, mod_sites = get_fix_mods(seq, 'C', _fix_mod_dict)
-assert mods==';'.join(['mod@C']*3)
-assert mod_sites=='2;4;6'
-get_fix_mods(seq, 'C', _fix_mod_dict)
-
-
('mod@C;mod@C;mod@C', '2;4;6')
-
-
-
-

source

-
-
-

get_var_mod_sites

-
-
 get_var_mod_sites (sequence:str, target_mod_aas:str, max_var_mod:int,
-                    max_combs:int)
-
-

get all combinations of variable modification sites

- ----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDetails
sequencestrpeptide sequence
target_mod_aasstrAAs that may have modifications
max_var_modintmax number of mods in a sequence
max_combsintmax number of combinations for a sequence
Returnslistlist of combinations (tuple) of modification sites
-
-

source

-
-
-

get_candidate_sites

-
-
 get_candidate_sites (sequence:str, target_mod_aas:str)
-
-

get candidate modification sites

- ----- - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDetails
sequencestrpeptide sequence
target_mod_aasstrAAs that may have modifications
Returnslistcandiadte mod sites in alphabase format (0: N-term, -1: C-term, 1-n:others)
-
-
seq = 'AMCMSTYK'
-candidate_sites = get_candidate_sites(seq, 'MSTY')
-assert np.all(np.array(candidate_sites)==np.array([2,4,5,6,7]))
-get_var_mod_sites(seq, 'MSTY', 3, 20)
-
-
[(2,),
- (4,),
- (5,),
- (6,),
- (7,),
- (2, 4),
- (2, 5),
- (2, 6),
- (2, 7),
- (4, 5),
- (4, 6),
- (4, 7),
- (5, 6),
- (5, 7),
- (6, 7),
- (2, 4, 5),
- (2, 4, 6),
- (2, 4, 7),
- (2, 5, 6),
- (2, 5, 7)]
-
-
-
-

source

-
-
-

get_var_mods

-
-
 get_var_mods (sequence:str, var_mod_aas:str, mod_dict:dict,
-               max_var_mod:int, max_combs:int, keep_unmodified:bool=False)
-
-

Generate all modification combinations and associated sites for the sequence.

-
-

source

-
-
-

get_var_mods_per_sites_single_mod_on_aa

-
-
 get_var_mods_per_sites_single_mod_on_aa (sequence:str, mod_sites:tuple,
-                                          var_mod_dict:dict)
-
-

Used when the var mod list contains only one mods on the each AA, for example: Mod1@A, Mod2@D …

-
-

source

-
-
-

get_var_mods_per_sites_multi_mods_on_aa

-
-
 get_var_mods_per_sites_multi_mods_on_aa (sequence:str, mod_sites:tuple,
-                                          var_mod_dict:dict)
-
-

Used only when the var mod list contains more than one mods on the same AA, for example: Mod1@A, Mod2@A …

-
-

source

-
-
-

parse_term_mod

-
-
 parse_term_mod (term_mod_name:str)
-
-
-

source

-
-
-

create_labeling_peptide_df

-
-
 create_labeling_peptide_df (peptide_df:pandas.core.frame.DataFrame,
-                             labels:list)
-
-
-

source

-
-
-

parse_labels

-
-
 parse_labels (labels:list)
-
-
-

source

-
-
-

add_single_peptide_labeling

-
-
 add_single_peptide_labeling (seq:str, mods:str, mod_sites:str,
-                              label_aas:str, label_mod_dict:dict,
-                              nterm_label_mod:str, cterm_label_mod:str)
-
-
-

source

-
-
-

protein_idxes_to_names

-
-
 protein_idxes_to_names (protein_idxes:str, protein_names:list)
-
-
-

source

-
-
-

append_regular_modifications

-
-
 append_regular_modifications (df:pandas.core.frame.DataFrame,
-                               var_mods=['Phospho@S', 'Phospho@T',
-                               'Phospho@Y'], max_mod_num=1, max_combs=100,
-                               keep_unmodified=True,
-                               cannot_modify_pep_nterm_aa:bool=False,
-                               cannot_modify_pep_cterm_aa:bool=False)
-
-

Append regular (not N/C-term) variable modifications to the exsiting modifications of each sequence in df.

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
dfDataFramePrecursor dataframe
var_modslist[‘Phospho@S’, ‘Phospho@T’, ‘Phospho@Y’]Considered varialbe modification list.
Defaults to [‘Phospho@S’,‘Phospho@T’,‘Phospho@Y’].
max_mod_numint1Maximal modification number for
each sequence of the var_mods. Defaults to 1.
max_combsint100One sequence is only allowed to explode
to max_combs number of modified peptides. Defaults to 100.
keep_unmodifiedboolTrueIf unmodified (only refered to var_mods)
peptides are also remained in the returned dataframe. Defaults to True.
cannot_modify_pep_nterm_aaboolFalseSimilar to cannot_modify_pep_cterm_aa, by default False
cannot_modify_pep_cterm_aaboolFalseIf the modified AA is at C-term, then the modification cannot modified it.
For example GlyGly@K, for a peptide ACDKEFGK, if GlyGly is at the C-term,
trypsin cannot cleave the C-term K, hence there will be no such a modified peptide ACDKEFGK(GlyGly).
by default False
ReturnsDataFrameThe precursor_df with new modification added.
-
-

source

-
-
-

FastaLib

-
-
 FastaLib (charged_frag_types:list=['b_z1', 'b_z2', 'y_z1', 'y_z2'],
-           protease:str='trypsin/P', max_missed_cleavages:int=2,
-           peptide_length_min:int=7, peptide_length_max:int=35,
-           precursor_charge_min:int=2, precursor_charge_max:int=4,
-           precursor_mz_min:float=200.0, precursor_mz_max:float=2000.0,
-           var_mods:list=['Acetyl@Protein N-term', 'Oxidation@M'],
-           max_var_mod_num:int=2, fix_mods:list=['Carbamidomethyl@C'],
-           decoy:str=None, I_to_L=False)
-
-

Class to process fasta files and generate libraries, including: - Digest protein sequences - Add fixed, variable or labeling modifications to the peptide sequences - Add charge states - Append decoy peptides - Save libraries into hdf file

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
charged_frag_typeslist[‘b_z1’, ‘b_z2’, ‘y_z1’, ‘y_z2’]Fragment types with charge,
by default [ ‘b_z1’,‘b_z2’,‘y_z1’, ‘y_z2’ ]
proteasestrtrypsin/PCould be pre-defined protease name defined in protease_dict,
or a regular expression.
By default ‘trypsin/P’
max_missed_cleavagesint2Maximal missed cleavages, by default 2
peptide_length_minint7Minimal cleaved peptide length, by default 7
peptide_length_maxint35Maximal cleaved peptide length, by default 35
precursor_charge_minint2Minimal precursor charge, by default 2
precursor_charge_maxint4Maximal precursor charge, by default 4
precursor_mz_minfloat200.0Minimal precursor mz, by default 200.0
precursor_mz_maxfloat2000.0Maximal precursor mz, by default 2000.0
var_modslist[‘Acetyl@Protein N-term’, ‘Oxidation@M’]list of variable modifications,
by default [‘Acetyl@Protein N-term’,‘Oxidation@M’]
max_var_mod_numint2Maximal number of variable modifications on a peptide sequence,
by default 2
fix_modslist[‘Carbamidomethyl@C’]list of fixed modifications, by default [‘Carbamidomethyl@C’]
decoystrNoneor pseudo_reverse or diann
I_to_LboolFalse
-
-

source

-
-
-

FastaLib.add_modifications

-
-
 FastaLib.add_modifications ()
-
-

Add fixed and variable modifications to all peptide sequences in self.precursor_df

-
-

source

-
-
-

FastaLib.add_additional_modifications

-
-
 FastaLib.add_additional_modifications (var_mods=['Phospho@S',
-                                        'Phospho@T', 'Phospho@Y'],
-                                        max_mod_num:int=1,
-                                        max_combs:int=100,
-                                        keep_unmodified:bool=True, cannot_
-                                        modify_pep_nterm_aa:bool=False, ca
-                                        nnot_modify_pep_cterm_aa:bool=Fals
-                                        e)
-
-

Add external defined variable modifications to all peptide sequences in self.precursor_df. See append_regular_modifications for details

-
-

source

-
-
-

FastaLib.add_mods_for_one_seq

-
-
 FastaLib.add_mods_for_one_seq (sequence:str, is_prot_nterm,
-                                is_prot_cterm)
-
-

Add fixed and variable modifications to a sequence

- ----- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDetails
sequencestrPeptide sequence
is_prot_ntermboolif protein N-term
is_prot_ctermboolif protein C-term
Returnstuplelist[str]: list of modification names
list[str]: list of modification sites
-
-

source

-
-
-

FastaLib.add_peptide_labeling

-
-
 FastaLib.add_peptide_labeling (labeling_channel_dict:dict)
-
-

Add labeling onto peptides inplace of self._precursor_df

- ----- - - - - - - - - - - - - - - -
TypeDetails
labeling_channel_dictdictFor example:
{
‘reference’: [], # not labelled for reference
‘0’: [‘Dimethyl@Any N-term’,‘Dimethyl@K’],
‘4’: [‘Dimethyl:2H(4)@Any N-term’,‘Dimethyl:2H(4)@K’],
‘8’: [‘Dimethyl:2H(6)13C(2)@Any N-term’,‘Dimethyl:2H(6)13C(2)@K’],
}.
The key name could be arbitrary distinguished strings for channel name,
and value must be a list of modification names (str) in alphabase format.
-
-

source

-
-
-

SpecLibBase.append_decoy_sequence

-
-
 SpecLibBase.append_decoy_sequence ()
-
-

Append decoy sequence into precursor_df. Decoy method is based on self.decoy(str).

-
decoy_lib = (
-    decoy_lib_provider.get_decoy_lib(
-        self.decoy, self
-    )
-)
-decoy_lib.decoy_sequence()
-...
-
-

source

-
-
-

FastaLib.get_peptides_from_fasta

-
-
 FastaLib.get_peptides_from_fasta (fasta_file:Union[str,list])
-
-

Load peptide sequences from fasta files.

- ----- - - - - - - - - - - - - - - -
TypeDetails
fasta_filetyping.Union[str, list]Could be a fasta file (str) or a list of fasta files (list[str])
-
-

source

-
-
-

FastaLib.get_peptides_from_protein_dict

-
-
 FastaLib.get_peptides_from_protein_dict (protein_dict:dict)
-
-

Cleave the protein sequences in protein_dict.

- ----- - - - - - - - - - - - - - - -
TypeDetails
protein_dictdictFormat:
{
‘prot_id1’:
‘protein_id’: ‘prot_id1’
‘sequence’: string
‘gene_name’: string
‘description’: string
‘prot_id2’:

}
-
-

source

-
-
-

FastaLib.get_peptides_from_peptide_sequence_list

-
-
 FastaLib.get_peptides_from_peptide_sequence_list (pep_seq_list:list,
-                                                   protein_list:list=None)
-
-
-

source

-
-
-

FastaLib.import_and_process_fasta

-
-
 FastaLib.import_and_process_fasta (fasta_files:Union[str,list])
-
-

Import and process a fasta file or a list of fasta files. It includes: - Load the fasta file(s) - Append decoy peptide sequences - Add modifications to peptides - Add charge

- ----- - - - - - - - - - - - - - - -
TypeDetails
fasta_filestyping.Union[str, list]A fasta file or a list of fasta files
-
-

source

-
-
-

FastaLib.import_and_process_protein_dict

-
-
 FastaLib.import_and_process_protein_dict (protein_dict:dict)
-
-

Import the protein_dict instead of fasta files.

-
protein_dict = load_all_proteins(fasta_files)
- ----- - - - - - - - - - - - - - - -
TypeDetails
protein_dictdictFormat:
{
‘prot_id1’:
‘protein_id’: ‘prot_id1’
‘sequence’: string
‘gene_name’: string
‘description’: string
‘prot_id2’:

}
-
-

source

-
-
-

FastaLib.import_and_process_peptide_sequences

-
-
 FastaLib.import_and_process_peptide_sequences (pep_seq_list:list,
-                                                protein_list:list=None)
-
-

Importing peptide sequences instead of proteins

- ------ - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
pep_seq_listlistPeptide sequence list
protein_listlistNoneProtein id list which maps to pep_seq_list one-by-one,
by default None
-
-

source

-
-
-

FastaLib.save_hdf

-
-
 FastaLib.save_hdf (hdf_file:str)
-
-

Save the contents into hdf file (attribute -> hdf_file): - self.precursor_df -> library/precursor_df - self.protein_df -> library/protein_df - self.fragment_mz_df -> library/fragment_mz_df - self.fragment_intensity_df -> library/fragment_intensity_df

- - - - - - - - - - - - - - - -
TypeDetails
hdf_filestrThe hdf file path
-
-

source

-
-
-

FastaLib.load_hdf

-
-
 FastaLib.load_hdf (hdf_file:str, load_mod_seq:bool=False)
-
-

Load contents from hdf file: - self.precursor_df <- library/precursor_df - self.precursor_df <- library/mod_seq_df if load_mod_seq is True - self.protein_df <- library/protein_df - self.fragment_mz_df <- library/fragment_mz_df - self.fragment_intensity_df <- library/fragment_intensity_df

- ------ - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
hdf_filestrhdf file path
load_mod_seqboolFalseAfter library is generated with hash values (int64) for sequences (str) and modifications (str),
we don’t need sequence information for searching.
So we can skip loading sequences to make the loading much faster.
By default False
-
-
-

Testing

-
-
df = pd.DataFrame(
-    {
-        'sequence': ['ABSTY','ACXSX','ACDEFG'],
-        'mods': ['', 'Acetyl@Protein N-term', ''],
-        'mod_sites': ['', '0', '']
-    }
-)
-df = append_regular_modifications(df, keep_unmodified=True)
-assert np.sum(df.sequence=='ABSTY')==4
-assert np.sum(df.sequence=='ACXSX')==2
-assert np.sum(df.sequence=='ACDEFG')==1
-assert all(df[df.sequence=='ABSTY'].mods.values == np.array(['Phospho@S','Phospho@T','Phospho@Y','']))
-assert all(df[df.sequence=='ABSTY'].mod_sites.values == np.array(['3','4','5','']))
-assert all(df[df.sequence=='ACXSX'].mods.values == np.array(['Acetyl@Protein N-term;Phospho@S','Acetyl@Protein N-term']))
-assert all(df[df.sequence=='ACXSX'].mod_sites.values == np.array(['0;4','0']))
-df
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sequencemodsmod_sites
0ABSTYPhospho@S3
1ABSTYPhospho@T4
2ABSTYPhospho@Y5
3ABSTY
4ACXSXAcetyl@Protein N-term;Phospho@S0;4
5ACXSXAcetyl@Protein N-term0
6ACDEFG
-
-
-
-
-
df = pd.DataFrame(
-    {
-        'sequence': ['ABSTY','ACXSX','ACDEFG'],
-        'mods': ['', 'Acetyl@Protein N-term', ''],
-        'mod_sites': ['', '0', '']
-    }
-)
-df = append_regular_modifications(df, keep_unmodified=False)
-assert np.sum(df.sequence=='ABSTY')==3
-assert np.sum(df.sequence=='ACXSX')==1
-assert np.sum(df.sequence=='ACDEFG')==0
-df
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sequencemodsmod_sites
0ABSTYPhospho@S3
1ABSTYPhospho@T4
2ABSTYPhospho@Y5
3ACXSXAcetyl@Protein N-term;Phospho@S0;4
-
-
-
-
-
_lib = FastaLib(None, I_to_L=False, decoy='pseudo_reverse')
-prot1 = 'MABCDESTKAFGHIJKLMNOPQRAFGHIJK'
-prot2 = 'AFGHIJKLMNOPQR'
-protein_dict = {
-    'xx': {
-        'protein_id': 'xx',
-        'gene_name': '',
-        'sequence': prot1
-    },
-    'yy': {
-        'protein_id': 'yy',
-        'gene_name': 'gene',
-        'sequence': prot2
-    }
-}
-_lib.get_peptides_from_protein_dict(protein_dict)
-_lib.precursor_df
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sequenceprotein_idxesmiss_cleavageis_prot_ntermis_prot_ctermmodsmod_sitesnAA
0AFGHIJK0;10TrueTrue7
1LMNOPQR0;10FalseTrue7
2ABCDESTK00TrueFalse8
3MABCDESTK00TrueFalse9
4AFGHIJKLMNOPQR0;11TrueTrue14
5LMNOPQRAFGHIJK01FalseTrue14
6ABCDESTKAFGHIJK01TrueFalse15
7MABCDESTKAFGHIJK01TrueFalse16
8AFGHIJKLMNOPQRAFGHIJK02FalseTrue21
9ABCDESTKAFGHIJKLMNOPQR02TrueFalse22
10MABCDESTKAFGHIJKLMNOPQR02TrueFalse23
-
-
-
-
-
_lib.protein_df
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - -
protein_idgene_namesequence
0xxMABCDESTKAFGHIJKLMNOPQRAFGHIJK
1yygeneAFGHIJKLMNOPQR
-
-
-
-
-
_lib.append_protein_name()
-assert 'proteins' in _lib.precursor_df.columns
-_lib.precursor_df
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sequenceprotein_idxesmiss_cleavageis_prot_ntermis_prot_ctermmodsmod_sitesnAAproteinsgenes
0AFGHIJK0;10TrueTrue7xx;yygene
1LMNOPQR0;10FalseTrue7xx;yygene
2ABCDESTK00TrueFalse8xx
3MABCDESTK00TrueFalse9xx
4AFGHIJKLMNOPQR0;11TrueTrue14xx;yygene
5LMNOPQRAFGHIJK01FalseTrue14xx
6ABCDESTKAFGHIJK01TrueFalse15xx
7MABCDESTKAFGHIJK01TrueFalse16xx
8AFGHIJKLMNOPQRAFGHIJK02FalseTrue21xx
9ABCDESTKAFGHIJKLMNOPQR02TrueFalse22xx
10MABCDESTKAFGHIJKLMNOPQR02TrueFalse23xx
-
-
-
-
-
_lib.add_modifications()
-_lib.precursor_df
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sequenceprotein_idxesmiss_cleavageis_prot_ntermis_prot_ctermmodsmod_sitesnAAproteinsgenes
0AFGHIJK0;10TrueTrue7xx;yygene
1AFGHIJK0;10TrueTrueAcetyl@Protein N-term07xx;yygene
2LMNOPQR0;10FalseTrueOxidation@M27xx;yygene
3LMNOPQR0;10FalseTrue7xx;yygene
4ABCDESTK00TrueFalseCarbamidomethyl@C38xx
5ABCDESTK00TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term3;08xx
6MABCDESTK00TrueFalseCarbamidomethyl@C;Oxidation@M4;19xx
7MABCDESTK00TrueFalseCarbamidomethyl@C49xx
8MABCDESTK00TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term;Oxidat...4;0;19xx
9MABCDESTK00TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term4;09xx
10AFGHIJKLMNOPQR0;11TrueTrueOxidation@M914xx;yygene
11AFGHIJKLMNOPQR0;11TrueTrue14xx;yygene
12AFGHIJKLMNOPQR0;11TrueTrueAcetyl@Protein N-term;Oxidation@M0;914xx;yygene
13AFGHIJKLMNOPQR0;11TrueTrueAcetyl@Protein N-term014xx;yygene
14LMNOPQRAFGHIJK01FalseTrueOxidation@M214xx
15LMNOPQRAFGHIJK01FalseTrue14xx
16ABCDESTKAFGHIJK01TrueFalseCarbamidomethyl@C315xx
17ABCDESTKAFGHIJK01TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term3;015xx
18MABCDESTKAFGHIJK01TrueFalseCarbamidomethyl@C;Oxidation@M4;116xx
19MABCDESTKAFGHIJK01TrueFalseCarbamidomethyl@C416xx
20MABCDESTKAFGHIJK01TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term;Oxidat...4;0;116xx
21MABCDESTKAFGHIJK01TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term4;016xx
22AFGHIJKLMNOPQRAFGHIJK02FalseTrueOxidation@M921xx
23AFGHIJKLMNOPQRAFGHIJK02FalseTrue21xx
24ABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Oxidation@M3;1722xx
25ABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C322xx
26ABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term;Oxidat...3;0;1722xx
27ABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term3;022xx
28MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Oxidation@M4;123xx
29MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Oxidation@M4;1823xx
30MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Oxidation@M;Oxidation@M4;1;1823xx
31MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C423xx
32MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term;Oxidat...4;0;123xx
33MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term;Oxidat...4;0;1823xx
34MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term;Oxidat...4;0;1;1823xx
35MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term4;023xx
-
-
-
-
-
_lib.add_additional_modifications(['Phospho@S','Phospho@T'])
-assert _lib.precursor_df.mods.str.contains('Phospho').any()
-_lib.precursor_df
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sequenceprotein_idxesmiss_cleavageis_prot_ntermis_prot_ctermmodsmod_sitesnAAproteinsgenes
0AFGHIJK0;10TrueTrue7xx;yygene
1AFGHIJK0;10TrueTrueAcetyl@Protein N-term07xx;yygene
2LMNOPQR0;10FalseTrueOxidation@M27xx;yygene
3LMNOPQR0;10FalseTrue7xx;yygene
4ABCDESTK00TrueFalseCarbamidomethyl@C;Phospho@S3;68xx
.................................
79MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term;Oxidat...4;0;1;18;823xx
80MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term;Oxidat...4;0;1;1823xx
81MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term;Phospho@S4;0;723xx
82MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term;Phospho@T4;0;823xx
83MABCDESTKAFGHIJKLMNOPQR02TrueFalseCarbamidomethyl@C;Acetyl@Protein N-term4;023xx
-

84 rows × 10 columns

-
-
-
-
-
_lib = FastaLib(
-    ['b_z1','y_z1'], I_to_L=False, 
-    decoy='pseudo_reverse'
-)
-prot1 = 'MACDESTYKBKFGHIKLMNPQRST'
-prot2 = 'FGHIKLMNPQR'
-protein_dict = {
-    'xx': {
-        'protein_id': 'xx',
-        'sequence': prot1
-    },
-    'yy': {
-        'protein_id': 'yy',
-        'sequence': prot2
-    }
-}
-_lib.import_and_process_protein_dict(protein_dict)
-_lib.calc_precursor_isotope()
-assert (_lib.precursor_df.charge == _lib.min_precursor_charge).any()
-assert (_lib.precursor_df.charge == _lib.max_precursor_charge).any()
-assert (_lib.precursor_df.decoy==1).any()
-assert ('MACDESTY'[::-1]+'K') in _lib.precursor_df.sequence.values
-assert 'isotope_apex_index' in _lib.precursor_df.columns
-assert 'isotope_apex_intensity' in _lib.precursor_df.columns
-assert ~_lib.precursor_df.sequence.str.contains('B').any()
-_lib.precursor_df
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sequenceprotein_idxesmiss_cleavageis_prot_ntermis_prot_ctermmodsmod_sitesnAAdecoychargeprecursor_mzisotope_m1_intensityisotope_apex_intensityisotope_apex_indexisotope_right_most_intensityisotope_right_most_indexisotope_m1_mzisotope_apex_mzisotope_right_most_mz
0LMNPQRST01FalseTrueOxidation@M2802481.7398340.4788141.000.4788141482.241484481.739834482.241484
1LMNPQRST01FalseTrueOxidation@M2803321.4956480.4788141.000.4788141321.830081321.495648321.830081
2LMNPQRST01FalseTrueOxidation@M2804241.3735550.4788141.000.4788141241.624380241.373555241.624380
3LMNPQRST01FalseTrue802473.7423770.4784331.000.4784331474.244027473.742377474.244027
4LMNPQRST01FalseTrue803316.1640100.4784331.000.4784331316.498443316.164010316.498443
............................................................
79FGHIKLMNPQRST02FalseTrueOxidation@M71303515.6049200.8284321.000.4207892515.939354515.604920516.273787
80FGHIKLMNPQRST02FalseTrueOxidation@M71304386.9555090.8284321.000.4207892387.206334386.955509387.457159
81FGHIKLMNPQRST02FalseTrue1302764.9062850.8280511.000.4184182765.407935764.906285765.909585
82FGHIKLMNPQRST02FalseTrue1303510.2732820.8280511.000.4184182510.607715510.273282510.942149
83FGHIKLMNPQRST02FalseTrue1304382.9567810.8280511.000.4184182383.207606382.956781383.458431
-

84 rows × 19 columns

-
-
-
-
-
_lib.import_and_process_protein_dict(protein_dict)
-_lib.add_peptide_labeling({
-    'light': ['Dimethyl@Any N-term','Dimethyl@K'],
-    'heavy': ['Dimethyl:2H(6)13C(2)@Any N-term','Dimethyl:2H(6)13C(2)@K'],
-})
-_lib.calc_precursor_isotope()
-assert (_lib.precursor_df.decoy==1).any()
-assert ('MACDESTY'[::-1]+'K') in _lib.precursor_df.sequence.values
-assert 'isotope_apex_index' in _lib.precursor_df.columns
-assert 'isotope_apex_intensity' in _lib.precursor_df.columns
-assert ~_lib.precursor_df.sequence.str.contains('B').any()
-_lib.precursor_df
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sequenceprotein_idxesmiss_cleavageis_prot_ntermis_prot_ctermmodsmod_sitesnAAdecoychargelabel_channelprecursor_mzisotope_m1_intensityisotope_apex_intensityisotope_apex_indexisotope_right_most_intensityisotope_right_most_indexisotope_m1_mzisotope_apex_mzisotope_right_most_mz
0LMNPQRST01FalseTrueOxidation@M;Dimethyl@Any N-term2;0802light495.7554840.5009061.000.5009061496.257134495.755484496.257134
1LMNPQRST01FalseTrueOxidation@M;Dimethyl@Any N-term2;0803light330.8394150.5009061.000.5009061331.173848330.839415331.173848
2LMNPQRST01FalseTrueOxidation@M;Dimethyl@Any N-term2;0804light248.3813800.5009061.000.5009061248.632205248.381380248.632205
3LMNPQRST01FalseTrueDimethyl@Any N-term0802light487.7580270.5005251.000.5005251488.259677487.758027488.259677
4LMNPQRST01FalseTrueDimethyl@Any N-term0803light325.5077770.5005251.000.5005251325.842210325.507777325.842210
...............................................................
163FGHIKLMNPQRST02FalseTrueOxidation@M;Dimethyl:2H(6)13C(2)@Any N-term;Di...7;0;51303heavy539.6553670.7882731.000.3921032539.989801539.655367540.324234
164FGHIKLMNPQRST02FalseTrueOxidation@M;Dimethyl:2H(6)13C(2)@Any N-term;Di...7;0;51304heavy404.9933440.7882731.000.3921032405.244169404.993344405.494994
165FGHIKLMNPQRST02FalseTrueDimethyl:2H(6)13C(2)@Any N-term;Dimethyl:2H(6)...0;51302heavy800.9819550.7876461.000.3897792801.483605800.981955801.985255
166FGHIKLMNPQRST02FalseTrueDimethyl:2H(6)13C(2)@Any N-term;Dimethyl:2H(6)...0;51303heavy534.3237290.7876461.000.3897792534.658162534.323729534.992596
167FGHIKLMNPQRST02FalseTrueDimethyl:2H(6)13C(2)@Any N-term;Dimethyl:2H(6)...0;51304heavy400.9946160.7876461.000.3897792401.245441400.994616401.496266
-

168 rows × 20 columns

-
-
-
- - -
- -
- -
- - - - \ No newline at end of file diff --git a/docs/protein/fasta.rst b/docs/protein/fasta.rst new file mode 100644 index 00000000..7389a2aa --- /dev/null +++ b/docs/protein/fasta.rst @@ -0,0 +1,13 @@ +alphabase.protein.fasta +=========================== + +The :obj:`FastaLib ` +provides the highest level APIs based on all other +functionalities in AlphaBase. + +See examples in :doc:`library_from_fasta notebook <../nbs/library_from_fasta>`. + +.. automodule:: alphabase.protein.fasta + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/protein/test_fasta.html b/docs/protein/test_fasta.html deleted file mode 100644 index 70b86f90..00000000 --- a/docs/protein/test_fasta.html +++ /dev/null @@ -1,572 +0,0 @@ - - - - - - - - - -alphabase - Testing fasta - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- -
- - - - - -
- -
-
-

Testing fasta

-
- - - -
- - - -
- - -
- - -

Use FastaLib to build a library (database)

-
-

Init fasta lib

-
-
from alphabase.protein.fasta import FastaLib
-
-protein_dict = {
-    'xx': {
-        'protein_id': 'xx',
-        'sequence': 'MACDESTYKBKFGHIKLMNPQRST'
-    },
-    'yy': {
-        'protein_id': 'yy',
-        'sequence': 'FGHIKLMNPQR'
-    }
-}
-
-fastalib = FastaLib(
-    ['b_z1','b_z2','y_z1','y_z2'], 
-    var_mods=['Oxidation@M','Acetyl@Protein N-term'],
-    fix_mods=['Carbamidomethyl@C'],
-    decoy='pseudo_reverse',
-    I_to_L=False, 
-)
-
-

Call import_protein_dict or import_fasta to load proteins, append decoys, add modifications and add charge states.

-
fastalib.import_fasta([fasta1, fasta2])
-
-
fastalib.import_and_process_protein_dict(protein_dict)
-fastalib.protein_df
-
- -
- - - - - - - - - - - - - - - - - - - - - -
protein_idsequence
0xxMACDESTYKBKFGHIKLMNPQRST
1yyFGHIKLMNPQR
-
-
-
-
-
assert 'decoy' in fastalib.precursor_df.columns
-assert 'mods' in fastalib.precursor_df.columns
-assert 'mod_sites' in fastalib.precursor_df.columns
-assert 'charge' in fastalib.precursor_df.columns
-
-

Call calc_precursor_isotope to calculate the precursor_mz, and M1/M2 isotope mz and intensity.

-
-
fastalib.calc_precursor_isotope()
-assert 'precursor_mz' in fastalib.precursor_df.columns
-assert 'isotope_apex_mz' in fastalib.precursor_df.columns
-assert 'isotope_apex_intensity' in fastalib.precursor_df.columns
-assert 'isotope_apex_index' in fastalib.precursor_df.columns
-assert 'isotope_right_most_mz' in fastalib.precursor_df.columns
-assert 'isotope_right_most_intensity' in fastalib.precursor_df.columns
-assert 'isotope_right_most_index' in fastalib.precursor_df.columns
-assert 'isotope_m1_mz' in fastalib.precursor_df.columns
-assert 'isotope_m1_intensity' in fastalib.precursor_df.columns
-
-

Call calc_fragment_mz_df to calculate the fragment dataframe

-
-
fastalib.calc_fragment_mz_df()
-assert 'frag_start_idx' in fastalib.precursor_df.columns
-assert 'frag_end_idx' in fastalib.precursor_df.columns
-import numpy as np
-assert len(fastalib.fragment_mz_df) == (fastalib.precursor_df.nAA.values-1).sum()
-
-

Use save_hdf to save as hdf file:

-
fastalib.save_hdf(hdf_file_path)
-

Then use load_hdf to load precursor and fragment dataframes:

-
fastalib.load_df(hdf_file_path, load_mod_seq=True)
- - -
- -
- -
- - - - \ No newline at end of file diff --git a/docs/psm_reader/alphapept_reader.html b/docs/psm_reader/alphapept_reader.html deleted file mode 100644 index 92db61b2..00000000 --- a/docs/psm_reader/alphapept_reader.html +++ /dev/null @@ -1,547 +0,0 @@ - - - - - - - - - -alphabase - AlphaPept PSM Reader - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- -
- - - - - -
- -
-
-

AlphaPept PSM Reader

-
- - - -
- - - -
- - -
- - -
-

source

-
-

AlphaPeptReader

-
-
 AlphaPeptReader (column_mapping:dict=None,
-                  modification_mapping:dict=None, fdr=0.01,
-                  keep_decoy=False, **kwargs)
-
-

Reading PSMs from alphapept’s *.ms_data.hdf

-
-

source

-
-
-

get_x_tandem_score

-
-
 get_x_tandem_score (df:pandas.core.frame.DataFrame)
-
-
-

source

-
-
-

parse_ap

-
-
 parse_ap (precursor)
-
-

Parser to parse peptide strings

-
-
-

Column and modification mapping from alphabase to MaxQuant

-
-
psm_reader_yaml['alphapept']['column_mapping']
-
-
{'rt': 'rt',
- 'scan_num': 'scan_no',
- 'spec_idx': 'raw_idx',
- 'query_id': 'query_idx',
- 'mobility': 'mobility',
- 'score': 'score',
- 'precursor_mz': 'mz',
- 'charge': 'charge',
- 'raw_name': 'raw_name',
- 'fdr': 'q_value',
- 'decoy': 'decoy'}
-
-
-
-
psm_reader_yaml['alphapept']['modification_mapping']
-
-
{'Carbamidomethyl@C': 'cC',
- 'Oxidation@M': 'oxM',
- 'Phospho@S': 'pS',
- 'Phospho@T': 'pT',
- 'Phospho@Y': 'pY',
- 'Acetyl@Protein N-term': 'a'}
-
-
-

The modified sequence column is precursor column

- - -
- -
- -
- - - - \ No newline at end of file diff --git a/docs/psm_reader/alphapept_reader.rst b/docs/psm_reader/alphapept_reader.rst new file mode 100644 index 00000000..4f38c69b --- /dev/null +++ b/docs/psm_reader/alphapept_reader.rst @@ -0,0 +1,7 @@ +alphabase.psm_reader.alphapept_reader +===================================== + +.. automodule:: alphabase.psm_reader.alphapept_reader + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/psm_reader/dia_psm_reader.html b/docs/psm_reader/dia_psm_reader.html deleted file mode 100644 index 58729b76..00000000 --- a/docs/psm_reader/dia_psm_reader.html +++ /dev/null @@ -1,1530 +0,0 @@ - - - - - - - - - -alphabase - DIA PSM reader - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- -
- - - - - -
- -
-
-

DIA PSM reader

-
- - - -
- - - -
- - -
- - -

This module includes:

- -

As we know so far, all DIA search engines have similar tabular files to MaxQaunt, so here, all DIAReaders are inherited from MaxQauntReader.

-
-

source

-
-

SwathReader

-
-
 SwathReader (column_mapping:dict=None, modification_mapping:dict=None,
-              fdr=0.01, keep_decoy=False, mod_sep='()',
-              underscore_for_ncterm=False, fixed_C57=False,
-              mod_seq_columns=['ModifiedPeptide', 'ModifiedSequence',
-              'FullUniModPeptideName', 'ModifiedPeptideSequence',
-              'LabeledSequence', 'FullUniModPeptideName'], csv_sep='\t',
-              **kwargs)
-
-

Reader for Spectronaut’s output library TSV/CSV.

-

Other parameters, please see MaxQuantReader in alphabase.psm_reader.maxquant_reader

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
column_mappingdictNone
modification_mappingdictNone
fdrfloat0.01
keep_decoyboolFalse
mod_sepstr()
underscore_for_nctermboolFalse
fixed_C57boolFalse
mod_seq_columnslist[‘ModifiedPeptide’, ‘ModifiedSequence’, ‘FullUniModPeptideName’, ‘ModifiedPeptideSequence’, ‘LabeledSequence’, ‘FullUniModPeptideName’]
csv_sepstrDelimiter for TSV/CSV, by default ’ ’
kwargs
-
-

source

-
-
-

SpectronautReader

-
-
 SpectronautReader (column_mapping:dict=None,
-                    modification_mapping:dict=None, fdr=0.01,
-                    keep_decoy=False, mod_sep='[]',
-                    underscore_for_ncterm=True, fixed_C57=False,
-                    mod_seq_columns=['ModifiedPeptide',
-                    'ModifiedSequence', 'FullUniModPeptideName',
-                    'ModifiedPeptideSequence', 'LabeledSequence',
-                    'FullUniModPeptideName'], csv_sep='\t',
-                    rt_unit='minute', **kwargs)
-
-

Reader for Spectronaut’s output library TSV/CSV.

-

Other parameters, please see MaxQuantReader in alphabase.psm_reader.maxquant_reader

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
column_mappingdictNone
modification_mappingdictNone
fdrfloat0.01
keep_decoyboolFalse
mod_sepstr[]
underscore_for_nctermboolTrue
fixed_C57boolFalse
mod_seq_columnslist[‘ModifiedPeptide’, ‘ModifiedSequence’, ‘FullUniModPeptideName’, ‘ModifiedPeptideSequence’, ‘LabeledSequence’, ‘FullUniModPeptideName’]
csv_sepstrDelimiter for TSV/CSV, by default ’ ’
rt_unitstrminute
kwargs
-
-
-

Column and modification mapping from alphabase to Spectronaut

-
-
psm_reader_yaml['spectronaut']['column_mapping']
-
-
{'raw_name': 'ReferenceRun',
- 'sequence': ['StrippedPeptide', 'PeptideSequence'],
- 'charge': 'PrecursorCharge',
- 'rt': ['RT',
-  'iRT',
-  'Tr_recalibrated',
-  'RetentionTime',
-  'NormalizedRetentionTime'],
- 'ccs': 'CCS',
- 'precursor_mz': 'PrecursorMz',
- 'mobility': ['Mobility', 'IonMobility', 'PrecursorIonMobility'],
- 'proteins': ['Protein Name', 'ProteinId', 'ProteinID', 'ProteinName'],
- 'uniprot_ids': ['UniProtIds', 'UniProtID', 'UniprotId'],
- 'genes': ['Genes', 'Gene', 'GeneName']}
-
-
-

modification_mapping is the same as MaxQuantReader

-

And alphabase will look for columns containing modified sequence on:

-
-
psm_reader_yaml['spectronaut']['mod_seq_columns']
-
-
['ModifiedPeptide',
- 'ModifiedSequence',
- 'FullUniModPeptideName',
- 'ModifiedPeptideSequence',
- 'LabeledSequence',
- 'FullUniModPeptideName']
-
-
-
-

source

-
-
-

DiannReader

-
-
 DiannReader (column_mapping:dict=None, modification_mapping:dict=None,
-              fdr=0.01, keep_decoy=False, mod_sep='()',
-              underscore_for_ncterm=False, fixed_C57=False, csv_sep='\t',
-              rt_unit='minute', **kwargs)
-
-

Reader for Spectronaut’s output library TSV/CSV.

-

Other parameters, please see MaxQuantReader in alphabase.psm_reader.maxquant_reader

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
column_mappingdictNone
modification_mappingdictNone
fdrfloat0.01
keep_decoyboolFalse
mod_sepstr()
underscore_for_nctermboolFalse
fixed_C57boolFalse
csv_sepstrDelimiter for TSV/CSV, by default ’ ’
rt_unitstrminute
kwargs
-
-

source

-
-
-

SpectronautReportReader

-
-
 SpectronautReportReader (column_mapping:dict=None,
-                          modification_mapping:dict=None, fdr=0.01,
-                          keep_decoy=False, mod_sep='[]',
-                          underscore_for_ncterm=True, fixed_C57=False,
-                          csv_sep=',', rt_unit='minute', **kwargs)
-
-

Reader for Spectronaut’s report TSV/CSV.

-

Other parameters, please see MaxQuantReader in alphabase.psm_reader.maxquant_reader

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
column_mappingdictNone
modification_mappingdictNone
fdrfloat0.01
keep_decoyboolFalse
mod_sepstr[]
underscore_for_nctermboolTrue
fixed_C57boolFalse
csv_sepstr,Delimiter for TSV/CSV, by default ‘,’
rt_unitstrminute
kwargs
-
-
-

Column and modification mapping from alphabase to DiaNN

-
-
psm_reader_yaml['diann']['column_mapping']
-
-
{'raw_name': 'Run',
- 'sequence': 'Stripped.Sequence',
- 'charge': 'Precursor.Charge',
- 'rt': 'RT',
- 'ccs': 'CCS',
- 'mobility': ['IM', 'IonMobility'],
- 'proteins': 'Protein.Names',
- 'uniprot_ids': 'Protein.Ids',
- 'genes': 'Genes',
- 'scan_num': 'MS2.Scan',
- 'score': 'CScore'}
-
-
-

The modified sequence column in DiaNN is Modified.Sequence

-
-
-

Testing

-
-
from io import StringIO
-
-
-
tsv = StringIO('''R.FileName,R.Replicate,EG.PrecursorId,EG.ApexRT,FG.CalibratedMassAccuracy (PPM),FG.CalibratedMz
-20211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_01,1,_VIETPENDFK_.2,40.826847076416,-0.6350307649846,596.298998773218
-20211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_01,1,_GFSNEVSSK_.2,19.1254806518555,-1.54873822486555,477.730400257423
-20211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_01,1,_HLLNQAVGEEEVPK_.3,42.0593299865723,-0.309173676987587,521.611288926824
-20211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_01,1,_DATM[Oxidation (M)]EVQR_.2,12.8398199081421,-3.31103772642203,483.222124398527
-''')
-
-spn_reader = psm_reader_provider.get_reader('spectronaut_report')
-spn_reader.import_file(tsv)
-assert len(spn_reader.psm_df) == 4
-assert (spn_reader.psm_df.mods=='Oxidation@M').sum()==1
-assert (spn_reader.psm_df.mod_sites=='4').sum()==1
-spn_reader.psm_df
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
raw_namertchargemodsmod_sitessequencenAArt_normprecursor_mz
020211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_0112.8398202Oxidation@M4DATMEVQR80.305279483.221474
120211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_0119.1254812GFSNEVSSK90.454726477.729989
220211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_0140.8268472VIETPENDFK100.970697596.298236
320211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_0142.0593303HLLNQAVGEEEVPK141.000000521.610617
-
-
-
-
-
tsv = StringIO('''ReferenceRun  PrecursorCharge Workflow    IntModifiedPeptide  CV  AllowForNormalization   ModifiedPeptide StrippedPeptide iRT IonMobility iRTSourceSpecific   BGSInferenceId  IsProteotypic   IntLabeledPeptide   LabeledPeptide  PrecursorMz ReferenceRunQvalue  ReferenceRunMS1Response FragmentLossType    FragmentNumber  FragmentType    FragmentCharge  FragmentMz  RelativeIntensity   ExcludeFromAssay    Database    ProteinGroups   UniProtIds  Protein Name    ProteinDescription  Organisms   OrganismId  Genes   Protein Existence   Sequence Version    FASTAName
-202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843    2       _ALVAT[+80]PGK_     True    _ALVAT[Phospho (STY)]PGK_   ALVATPGK    -5.032703   0.758   -5.032703   P19338  False   _ALVAT[+80]PGK_ _ALVAT[Phospho (STY)]PGK_   418.717511324722    0   10352   noloss  3   y   1   301.187031733932    53.1991 False   sp  P19338  P19338  NUCL_HUMAN  Nucleolin   Homo sapiens        NCL 1   3   MCT_human_UP000005640_9606
-202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843    2       _ALVAT[+80]PGK_     True    _ALVAT[Phospho (STY)]PGK_   ALVATPGK    -5.032703   0.758   -5.032703   P19338  False   _ALVAT[+80]PGK_ _ALVAT[Phospho (STY)]PGK_   418.717511324722    0   10352   H3PO4   4   y   1   384.224142529733    26.31595    False   sp  P19338  P19338  NUCL_HUMAN  Nucleolin   Homo sapiens        NCL 1   3   MCT_human_UP000005640_9606
-202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843    2       _TLT[+80]PCPLR_     True    _TLT[Phospho (STY)]PC[Carbamidomethyl (C)]PLR_  TLTPCPLR    27.71659    0.818   27.71659    Q5T200  False   _TLT[+80]PPLR_  _TLT[Phospho (STY)]PPLR_    439.230785875227    0.000138389150379226    23117   noloss  3   b   1   396.153027901512    6.3264  False   sp  Q5T200  Q5T200  ZC3HD_HUMAN Zinc finger CCCH domain-containing protein 13   Homo sapiens        ZC3H13  1   1   MCT_human_UP000005640_9606
-202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843    2       _TLT[+80]PCPLR_     True    _TLT[Phospho (STY)]PC[Carbamidomethyl (C)]PLR_  TLTPCPLR    27.71659    0.818   27.71659    Q5T200  False   _TLT[+80]PPLR_  _TLT[Phospho (STY)]PPLR_    439.230785875227    0.000138389150379226    23117   noloss  3   y   1   385.255780000092    29.70625    False   sp  Q5T200  Q5T200  ZC3HD_HUMAN Zinc finger CCCH domain-containing protein 13   Homo sapiens        ZC3H13  1   1   MCT_human_UP000005640_9606
-202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library25_S4-C1_1_25867 2       _LFVT[+80]PPEGSSR_      True    _[Acetyl (Protein N-term)]LFVS[Phospho (STY)]PPEGSSR_   LFVSPPEGSSR 38.05031    0.917   38.05031    Q14244;Q14244-6;Q14244-7    False   _LFVT[+80]PPEGSSR_  _LFVT[Phospho (STY)]PPEGSSR_    635.297385373987    0   14164   H3PO4   4   b   1   443.265279065723    12.24525    False   sp  Q14244;Q14244-6;Q14244-7    Q14244;Q14244-6;Q14244-7    MAP7_HUMAN  Ensconsin;Isoform of Q14244, Isoform 6 of Ensconsin;Isoform of Q14244, Isoform 7 of Ensconsin   Homo sapiens        MAP7    1;; 1;; MCT_human_UP000005640_9606;MCT_human2_UP000005640_9606_additional;MCT_human2_UP000005640_9606_additional
-202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library25_S4-C1_1_25867 2       _LFVT[+80]PPEGSSR_      True    _[Acetyl (Protein N-term)]LFVS[Phospho (STY)]PPEGSSR_   LFVSPPEGSSR 38.05031    0.917   38.05031    Q14244;Q14244-6;Q14244-7    False   _LFVT[+80]PPEGSSR_  _LFVT[Phospho (STY)]PPEGSSR_    635.297385373987    0   14164   noloss  6   y   1   632.299829640042    46.07855    False   sp  Q14244;Q14244-6;Q14244-7    Q14244;Q14244-6;Q14244-7    MAP7_HUMAN  Ensconsin;Isoform of Q14244, Isoform 6 of Ensconsin;Isoform of Q14244, Isoform 7 of Ensconsin   Homo sapiens        MAP7    1;; 1;; MCT_human_UP000005640_9606;MCT_human2_UP000005640_9606_additional;MCT_human2_UP000005640_9606_additional
-202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library25_S4-C1_1_25867 2       _LFVT[+80]PPEGSSR_      True    _[Acetyl (Protein N-term)]LFVS[Phospho (STY)]PPEGSSR_   LFVSPPEGSSR 38.05031    0.917   38.05031    Q14244;Q14244-6;Q14244-7    False   _LFVT[+80]PPEGSSR_  _LFVT[Phospho (STY)]PPEGSSR_    635.297385373987    0   14164   noloss  7   y   1   729.352593488892    100 False   sp  Q14244;Q14244-6;Q14244-7    Q14244;Q14244-6;Q14244-7    MAP7_HUMAN  Ensconsin;Isoform of Q14244, Isoform 6 of Ensconsin;Isoform of Q14244, Isoform 7 of Ensconsin   Homo sapiens        MAP7    1;; 1;; MCT_human_UP000005640_9606;MCT_human2_UP000005640_9606_additional;MCT_human2_UP000005640_9606_additional
-''')
-
-spn_reader = psm_reader_provider.get_reader('spectronaut')
-spn_reader.import_file(tsv)
-assert len(spn_reader.psm_df) == 3
-assert spn_reader.psm_df.mods.values[0] == 'Phospho@T'
-assert spn_reader.psm_df.mod_sites.values[0] == '5'
-assert spn_reader.psm_df.mods.values[1] == 'Phospho@T;Carbamidomethyl@C'
-assert spn_reader.psm_df.mod_sites.values[1] == '3;5'
-assert spn_reader.psm_df.mods.values[2] == 'Acetyl@Protein N-term;Phospho@S'
-assert spn_reader.psm_df.mod_sites.values[2] == '0;4'
-spn_reader.psm_df
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
raw_namesequencechargertprecursor_mzmobilityproteinsuniprot_idsgenesmodsmod_sitesnAArt_normccs
0202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph...ALVATPGK2-5.032703418.7175110.758NUCL_HUMANP19338NCLPhospho@T580.0308.612143
1202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph...TLTPCPLR227.716590439.2307860.818ZC3HD_HUMANQ5T200ZC3H13Phospho@T;Carbamidomethyl@C3;581.0332.788837
2202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph...LFVSPPEGSSR238.050310635.2973850.917MAP7_HUMANQ14244;Q14244-6;Q14244-7MAP7Acetyl@Protein N-term;Phospho@S0;4111.0371.282739
-
-
-
-
-
tsv = StringIO('''PrecursorMz   ProductMz   Tr_recalibrated transition_name CE  LibraryIntensity    transition_group_id decoy   PeptideSequence ProteinName Annotation  FullUniModPeptideName   PrecursorCharge GroupLabel  UniprotID   FragmentType    FragmentCharge  FragmentSeriesNumber
-685.732240417   886.020494795   -10 255_AAAAAAAAAASGAAIPPLIPPRR_3   -1  5257.9  13_AAAAAAAAAASGAAIPPLIPPRR_3    0   AAAAAAAAAASGAAIPPLIPPRR 1/O14654    y19^2/0.002 AAAAAAAAAASGAAIPPLIPPRR 3   light   1/O14654    y   2   19
-514.550999438   473.303261576   59.2    268_AAAAAAAAAASGAAIPPLIPPRR_4   -1  10000.0 14_AAAAAAAAAASGAAIPPLIPPRR_4    0   AAAAAAAAAASGAAIPPLIPPRR 1/O14654    y8^2/0.002  AAAAAAAAAASGAAIPPLIPPRR 4   light   1/O14654    y   2   8
-514.550999438   629.39313922    59.2    276_AAAAAAAAAASGAAIPPLIPPRR_4   -1  5923.1  14_AAAAAAAAAASGAAIPPLIPPRR_4    0   AAAAAAAAAASGAAIPPLIPPRR 1/O14654    y12^2/0.001 AAAAAAAAAASGAAIPPLIPPRR 4   light   1/O14654    y   2   12
-514.550999438   672.909153425   59.2    279_AAAAAAAAAASGAAIPPLIPPRR_4   -1  5249.8  14_AAAAAAAAAASGAAIPPLIPPRR_4    0   AAAAAAAAAASGAAIPPLIPPRR 1/O14654    y13^2/0.001 AAAAAAAAAASGAAIPPLIPPRR 4   light   1/O14654    y   2   13
-514.550999438   356.19284545    59.2    262_AAAAAAAAAASGAAIPPLIPPRR_4   -1  5233.6  14_AAAAAAAAAASGAAIPPLIPPRR_4    0   AAAAAAAAAASGAAIPPLIPPRR 1/O14654    b5/0.001,b10^2/0.001,m6:10/0.001    AAAAAAAAAASGAAIPPLIPPRR 4   light   1/O14654    b   1   5
-514.550999438   498.26707303    59.2    269_AAAAAAAAAASGAAIPPLIPPRR_4   -1  4976.0  14_AAAAAAAAAASGAAIPPLIPPRR_4    0   AAAAAAAAAASGAAIPPLIPPRR 1/O14654    b7/0.001,m4:10/0.001    AAAAAAAAAASGAAIPPLIPPRR 4   light   1/O14654    b   1   7
-514.550999438   427.22995924    59.2    265_AAAAAAAAAASGAAIPPLIPPRR_4   -1  4859.4  14_AAAAAAAAAASGAAIPPLIPPRR_4    0   AAAAAAAAAASGAAIPPLIPPRR 1/O14654    b6/0.002,m5:10/0.002    AAAAAAAAAASGAAIPPLIPPRR 4   light   1/O14654    b   1   6
-728.201724416   356.19284545    101.8   292_AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR_5    -1  10000.0 15_AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR_5 0   AAAAAAAAAASGAAIPPLIPPRRVITLYQCFSVSQR    1/O14654    b5/0.003,b10^2/0.003,m6:10/0.003    AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR  5   light   1/O14654    b   1   5
-728.201724416   576.310000482   101.8   297_AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR_5    -1  7611.0  15_AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR_5 0   AAAAAAAAAASGAAIPPLIPPRRVITLYQCFSVSQR    1/O14654    y5/0.002    AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR  5   light   1/O14654    y   1   5
-728.201724416   427.22995924    101.8   293_AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR_5    -1  6805.1  15_AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR_5 0   AAAAAAAAAASGAAIPPLIPPRRVITLYQCFSVSQR    1/O14654    b6/-0.002,m5:10/-0.002  AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR  5   light   1/O14654    b   1   6
-728.201724416   569.30418682    101.8   296_AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR_5    -1  6312.7  15_AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR_5 0   AAAAAAAAAASGAAIPPLIPPRRVITLYQCFSVSQR    1/O14654    b8/0.009,m3:10/0.009    AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR  5   light   1/O14654    b   1   8
-''')
-
-
-osw_reader = psm_reader_provider.get_reader('openswath')
-psm_df = osw_reader.import_file(tsv)
-assert psm_df.loc[2,'mod_sites'] == '30'
-assert psm_df.loc[2,'mods'] == 'Carbamidomethyl@C'
-
-
-
tsv = StringIO('''File.Name Run Protein.Group   Protein.Ids Protein.Names   Genes   PG.Quantity PG.Normalised   PG.MaxLFQ   Genes.Quantity  Genes.Normalised    Genes.MaxLFQ    Genes.MaxLFQ.Unique Modified.Sequence   Stripped.Sequence   Precursor.Id    Precursor.Charge    Q.Value Global.Q.Value  Protein.Q.Value PG.Q.Value  Global.PG.Q.Value   GG.Q.Value  Translated.Q.Value  Proteotypic Precursor.Quantity  Precursor.Normalised    Precursor.Translated    Quantity.Quality    RT  RT.Start    RT.Stop iRT Predicted.RT    Predicted.iRT   Lib.Q.Value Ms1.Profile.Corr    Ms1.Area    Evidence    Spectrum.Similarity Mass.Evidence   CScore  Decoy.Evidence  Decoy.CScore    Fragment.Quant.Raw  Fragment.Quant.Corrected    Fragment.Correlations   MS2.Scan    IM  iIM Predicted.IM    Predicted.iIM
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636   Q9UH36  Q9UH36      SRRD    3296.49 3428.89 3428.89 3296.49 3428.89 3428.89 3428.89 (UniMod:1)AAAAAAALESWQAAAPR AAAAAAALESWQAAAPR   (UniMod:1)AAAAAAALESWQAAAPR2    2   3.99074e-05 1.96448e-05 0.000159821 0.000159821 0.000146135 0.000161212 0   1   3296.49 3428.89 3296.49 0.852479    19.9208 19.8731 19.9685 123.9   19.8266 128.292 0   0.960106    5308.05 1.96902 0.683134    0.362287    0.999997    1.23691 3.43242e-05 1212.01;2178.03;1390.01;1020.01;714.008;778.008;    1212.01;1351.73;887.591;432.92;216.728;732.751; 0.956668;0.757581;0.670497;0.592489;0.47072;0.855203;   30053   1.19708 1.19328 1.19453 1.19469
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642   Q9UH36  Q9UH36      SRRD    2365    2334.05 2334.05 2365    2334.05 2334.05 2334.05 (UniMod:1)AAAAAAALESWQAAAPR AAAAAAALESWQAAAPR   (UniMod:1)AAAAAAALESWQAAAPR2    2   0.000184434 1.96448e-05 0.000596659 0.000596659 0.000146135 0.000604961 0   1   2365    2334.05 2365    0.922581    19.905  19.8573 19.9527 123.9   19.782  128.535 0   0.940191    4594.04 1.31068 0.758988    0   0.995505    0.28633 2.12584e-06 1209.02;1210.02;1414.02;1051.01;236.003;130.002;    1209.02;1109.89;732.154;735.384;0;46.0967;  0.919244;0.937624;0.436748;0.639369;0.296736;0.647924;  30029   1.195   1.19328 1.19381 1.19339
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648   Q9UH36  Q9UH36      SRRD    1664.51 1635.46 1635.47 1664.51 1635.46 1635.47 1635.47 (UniMod:1)AAAAAAALESWQAAAPR AAAAAAALESWQAAAPR   (UniMod:1)AAAAAAALESWQAAAPR2    2   0.000185123 1.96448e-05 0.000307409 0.000307409 0.000146135 0.000311332 0   1   1664.51 1635.46 1664.51 0.811147    19.8893 19.8416 19.937  123.9   19.7567 128.896 0   0.458773    6614.06 1.7503  0.491071    0.00111683  0.997286    1.92753 2.80543e-05 744.01;1708.02;1630.02;1475.02;0;533.006;   322.907;808.594;577.15;536.033;0;533.006;   0.760181;0.764072;0.542005;0.415779;0;0.913438; 30005   1.19409 1.19328 1.19323 1.19308
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654   Q9UH36  Q9UH36      SRRD    3369.91 3343.38 3343.38 3369.91 3343.38 3343.38 3343.38 (UniMod:1)AAAAAAALESWQAAAPR AAAAAAALESWQAAAPR   (UniMod:1)AAAAAAALESWQAAAPR2    2   0.000153377 1.96448e-05 0.000298151 0.000298151 0.000146135 0.000302297 0   1   3369.91 3343.38 3369.91 0.798104    19.872  19.8243 19.9196 123.9   19.7347 128.576 0   0.892774    5026.05 1.01465 0.704953    0   0.996593    0.476378    7.76581e-06 1654.02;1286.02;1894.02;993.011;778.008;1190.01;    1638.42;1286.02;1293.97;466.705;292.465;445.475;    0.854908;0.860012;0.708773;0.584142;0.716032;0.410465;  29981   1.19136 1.19328 1.19169 1.1919
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636   P51608-2    P51608-2        MECP2   1585.53 1649.21 7673.34 1585.53 1649.21 7673.34 7673.34 AAAAAAAPSGGGGGGEEERLEEK AAAAAAAPSGGGGGGEEERLEEK (UniMod:1)AAAAAAAPSGGGGGGEEERLEEK3  3   0.00014185  5.69066e-05 0.000159821 0.000159821 0.000146135 0.000161212 0   1   861.509 896.11  861.509 0.530747    7.34894 7.30125 7.39665 14.6582 7.35635 14.5905 0   0.85024 2010.02 1.27844 0.470734    0.117495    0.998266    0.848349    0.0613877   905.008;1021.01;1179.01;419.003;753.005;638.006;    422.004;0;439.505;419.003;325.502;119.251;  0.626628;-0.441015;0.438684;0.800641;0.794403;0.458813; 11077   1.01    1.01225 1.01075 1.01099
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642   P51608-2    P51608-2        MECP2   16870.2 16649.4 7963.26 16870.2 16649.4 7963.26 7963.26 AAAAAAAPSGGGGGGEEERLEEK AAAAAAAPSGGGGGGEEERLEEK (UniMod:1)AAAAAAAPSGGGGGGEEERLEEK3  3   0.000200767 5.69066e-05 0.000152765 0.000152765 0.000146135 0.000154631 0   1   1832.12 1808.14 1832.12 0.438822    7.3176  7.26989 7.36527 14.6582 7.29706 14.8141 0   0.814702    3622.03 0.571375    0.278903    0.971334    0.994097    0.779006    0.0590956   1430.01;946.009;804.008;260.002;710.006;232.002;    886.115;946.009;0;0;431.102;0;  -0.0551893;0.901557;0.0979035;-0.326533;0.334642;-0.120337; 11029   1.01417 1.01225 1.01136 1.01447
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648   P51608-2    P51608-2        MECP2   16242.7 15959.3 13129.8 16242.7 15959.3 13129.8 13129.8 AAAAAAAPSGGGGGGEEERLEEK AAAAAAAPSGGGGGGEEERLEEK (UniMod:1)AAAAAAAPSGGGGGGEEERLEEK3  3   6.98405e-05 5.69066e-05 0.000168492 0.000168492 0.000146135 0.000169578 0   1   2765.24 2716.99 2765.24 0.619188    7.28562 7.23794 7.33338 14.6582 7.22243 15.2233 0   0.859167    2180.02 1.50997 0.43755 0.191245    0.999939    0.420023    0.00548723  1807.01;1018.01;1230.01;554.005;1216.01;276.002;    954.327;1006.89;804.021;554.005;0;143.651;  0.483734;0.907585;0.418797;0.61368;-0.523993;0.70046;   10981   1.015   1.01225 1.01115 1.01558
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654   P51608-2    P51608-2        MECP2   20914.7 20750   16106   20914.7 20750   16106   16106   AAAAAAAPSGGGGGGEEERLEEK AAAAAAAPSGGGGGGEEERLEEK (UniMod:1)AAAAAAAPSGGGGGGEEERLEEK3  3   0.000603914 5.69066e-05 0.000153516 0.000153516 0.000146135 0.000155304 0   1   4556.58 4520.72 4556.58 0.620251    7.26825 7.22055 7.31601 14.6582 7.18207 15.448  0   0.79218 3193.03 0.113147    0.344593    0.144439    0.971834    1.05178 0.112962    2855.02;1760.01;830.007;116.001;564.005;751.006;    2266.46;1760.01;530.111;0;0;317.258;    0.430169;0.867218;0.612985;-0.310664;-0.386197;0.286451;    10957   1.01208 1.01225 1.00965 1.01449
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636   Q96P70  Q96P70      IPO9    155722  161976  160062  155722  161976  160062  160062  (UniMod:1)AAAAAAGAASGLPGPVAQGLK AAAAAAGAASGLPGPVAQGLK   (UniMod:1)AAAAAAGAASGLPGPVAQGLK2    2   3.99074e-05 1.96448e-05 0.000159821 0.000159821 0.000146135 0.000161212 0   1   44791.6 46590.6 44791.6 0.903543    14.709  14.6614 14.7567 77.7384 14.7374 77.4968 0   0.962703    395646  1.16168 0.790083    0   0.999999    0.491003    0.00391533  17738.2;18223.2;16218.2;17747.2;14484.2;12569.2;    17738.2;18223.2;16150;16115.2;14484.2;12569.2;  0.879361;0.89314;0.807683;0.73629;0.863152;0.984215;    22187   1.225   1.23344 1.23458 1.22263
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642   Q96P70  Q96P70      IPO9    172360  170104  155889  172360  170104  155889  155889  (UniMod:1)AAAAAAGAASGLPGPVAQGLK AAAAAAGAASGLPGPVAQGLK   (UniMod:1)AAAAAAGAASGLPGPVAQGLK2    2   4.98766e-05 1.96448e-05 0.000152765 0.000152765 0.000146135 0.000154631 0   1   44700.5 44115.4 44700.5 0.615196    14.6456 14.5979 14.6933 77.7384 14.6419 77.8394 0   0.9107  553292  0.747052    0.814842    0   0.999996    0.830219    0.0331339   19349.2;20154.2;20586.2;20040.3;13620.2;12105.1;    19349.2;19014.1;19329.7;18862.6;13404.2;11947.1;    0.862894;0.42962;0.293099;0.655948;0.517625;0.323501;   22091   1.22042 1.23344 1.23392 1.21891
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648   Q96P70  Q96P70      IPO9    153712  151030  152845  153712  151030  152845  152845  (UniMod:1)AAAAAAGAASGLPGPVAQGLK AAAAAAGAASGLPGPVAQGLK   (UniMod:1)AAAAAAGAASGLPGPVAQGLK2    2   6.08421e-05 1.96448e-05 0.000168492 0.000168492 0.000146135 0.000169578 0   1   40439.4 39733.8 40439.4 0.833327    14.6301 14.5824 14.6777 77.7384 14.5747 78.2527 0   0.989019    1.0768e+06  1.68843 0.759575    0   0.999999    0.674737    0.0631384   17597.2;19526.2;16647.2;16204.2;12871.2;11069.2;    17377.7;19526.2;16647.2;16204.2;12871.2;10190.5;    0.828262;0.979726;0.827511;0.9628;0.90466;0.751867; 22067   1.22708 1.23344 1.23332 1.2261
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654   Q96P70  Q96P70      IPO9    147008  145850  159209  147008  145850  159209  159209  (UniMod:1)AAAAAAGAASGLPGPVAQGLK AAAAAAGAASGLPGPVAQGLK   (UniMod:1)AAAAAAGAASGLPGPVAQGLK2    2   4.42595e-05 1.96448e-05 0.000153516 0.000153516 0.000146135 0.000155304 0   1   41861.6 41532.1 41861.6 0.752921    14.549  14.5013 14.5967 77.7384 14.5155 78.0748 0   0.877873    939172  1.59762 0.821027    0   0.999997    0.397952    1.22212e-05 18143.2;19574.2;17444.2;17956.2;11427.2;13025.2;    17409.2;18432.7;16706.7;10820.4;11427.2;13025.2;    0.625292;0.399297;0.717726;0.321047;0.864595;0.825535;  21947   1.2275  1.23344 1.23199 1.2281
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636   P28482  P28482      MAPK1   72652.7 75570.7 78604.9 72652.7 75570.7 78604.9 78604.9 (UniMod:1)AAAAAAGAGPEM(UniMod:35)VR AAAAAAGAGPEMVR  (UniMod:1)AAAAAAGAGPEM(UniMod:35)VR2    2   0.00693727  0.000834654 0.000159821 0.000159821 0.000146135 0.000161212 0   1   192.198 199.917 192.198 0.0197094   7.4249  7.37721 7.4726  15.9025 7.49813 15.2482 0   0.754191    8842.06 1.19725 0.470393    0.086229    0.843331    2.80548 0.384248    897.008;1032.01;279.002;377.003;440.004;286.003;    0;137.786;54.4117;0;89.692;286.003; -0.20379;-0.0679789;0.241761;-0.388501;-0.0459688;0.973644; 11191   1.01917 1.0262  1.02479 1.02031
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642   P28482  P28482      MAPK1   69911.3 68996.2 63388.2 69911.3 68996.2 63388.2 63388.2 (UniMod:1)AAAAAAGAGPEM(UniMod:35)VR AAAAAAGAGPEMVR  (UniMod:1)AAAAAAGAGPEM(UniMod:35)VR2    2   0.00122498  0.000834654 0.000152765 0.000152765 0.000146135 0.000154631 0   1   1572.67 1552.08 1572.67 0.906427    7.45711 7.40943 7.50482 15.9025 7.43922 16.0749 0   0.371998    5937.05 0.30888 0.510876    0.72688 0.95182 1.96259 0.65474 1320.01;838.009;638.006;827.009;562.005;339.003;    1320.01;252.656;0;213.073;330.325;0;    0.976001;0.542934;0.346963;0.38014;0.442774;-0.259898;  11239   1.01773 1.0262  1.02509 1.01834
-''')
-diann_reader = psm_reader_provider.get_reader('diann')
-_df = diann_reader.import_file(tsv)
-assert 'ccs' in diann_reader.psm_df.columns
-assert len(diann_reader.psm_df) == 14
-assert np.sum(diann_reader.psm_df.mods.str.contains('Acetyl@Protein N-term')) == 10
-assert np.sum(~diann_reader.psm_df.mods.str.contains('Acetyl@Protein N-term')) == 4
-assert np.sum(diann_reader.psm_df.mods.str.contains('Oxidation@M')) == 2
-assert np.all(np.array(diann_reader.modification_mapping['Phospho@S'])==np.array([
-    'S(Phospho (S))',
-    'S(Phospho (ST))',
-    'S(Phospho (STY))',
-    'S(ph)',
-    'S(UniMod:21)',
-    'pS',
-    'S[Phospho (S)]',
-    'S[Phospho (ST)]',
-    'S[Phospho (STY)]',
-    'S[ph]',
-    'S[UniMod:21]'])
-)
-_df
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
raw_namesequencechargertmobilityproteinsuniprot_idsgenesscan_numscorespec_idxmodsmod_sitesnAArt_normprecursor_mzccs
020201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...AAAAAAGAGPEMVR27.424901.01917NaNP28482MAPK1111910.84333111190Acetyl@Protein N-term;Oxidation@M0;12140.372721650.819344412.544080
120201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...AAAAAAGAGPEMVR27.457111.01773NaNP28482MAPK1112390.95182011238Acetyl@Protein N-term;Oxidation@M0;12140.374635650.819344411.961191
220201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...AAAAAAALESWQAAAPR219.920801.19708NaNQ9UH36SRRD300530.99999730052Acetyl@Protein N-term0171.000000834.428635483.435307
320201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...AAAAAAALESWQAAAPR219.905001.19500NaNQ9UH36SRRD300290.99550530028Acetyl@Protein N-term0171.000000834.428635482.595308
420201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...AAAAAAALESWQAAAPR219.889301.19409NaNQ9UH36SRRD300050.99728630004Acetyl@Protein N-term0171.000000834.428635482.227809
520201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...AAAAAAALESWQAAAPR219.872001.19136NaNQ9UH36SRRD299810.99659329980Acetyl@Protein N-term0171.000000834.428635481.125311
620201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...AAAAAAGAASGLPGPVAQGLK214.709001.22500NaNQ96P70IPO9221870.99999922186Acetyl@Protein N-term0210.738374895.991600494.430146
720201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...AAAAAAGAASGLPGPVAQGLK214.645601.22042NaNQ96P70IPO9220910.99999622090Acetyl@Protein N-term0210.735775895.991600492.581583
820201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...AAAAAAGAASGLPGPVAQGLK214.630101.22708NaNQ96P70IPO9220670.99999922066Acetyl@Protein N-term0210.735576895.991600495.269668
920201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...AAAAAAGAASGLPGPVAQGLK214.549001.22750NaNQ96P70IPO9219470.99999721946Acetyl@Protein N-term0210.732136895.991600495.439187
1020201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...AAAAAAAPSGGGGGGEEERLEEK37.348941.01000NaNP51608-2MECP2110770.99826611076230.368908695.666290610.813640
1120201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...AAAAAAAPSGGGGGGEEERLEEK37.317601.01417NaNP51608-2MECP2110290.99409711028230.367626695.666290613.335514
1220201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...AAAAAAAPSGGGGGGEEERLEEK37.285621.01500NaNP51608-2MECP2109810.99993910980230.366309695.666290613.837470
1320201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...AAAAAAAPSGGGGGGEEERLEEK37.268251.01208NaNP51608-2MECP2109570.97183410956230.365753695.666290612.071553
-
-
-
-
-
tsv = StringIO('''File.Name Run Protein.Group   Protein.Ids Protein.Names   Genes   PG.Quantity PG.Normalised   PG.MaxLFQ   Genes.Quantity  Genes.Normalised    Genes.MaxLFQ    Genes.MaxLFQ.Unique Modified.Sequence   Stripped.Sequence   Precursor.Id    Precursor.Charge    Q.Value Global.Q.Value  Protein.Q.Value PG.Q.Value  Global.PG.Q.Value   GG.Q.Value  Translated.Q.Value  Proteotypic Precursor.Quantity  Precursor.Normalised    Precursor.Translated    Quantity.Quality    RT  RT.Start    RT.Stop iRT Predicted.RT    Predicted.iRT   Lib.Q.Value Ms1.Profile.Corr    Ms1.Area    Evidence    Spectrum.Similarity Mass.Evidence   CScore  Decoy.Evidence  Decoy.CScore    Fragment.Quant.Raw  Fragment.Quant.Corrected    Fragment.Correlations   MS2.Scan    IM  iIM Predicted.IM    Predicted.iIM
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636   Q9UH36  Q9UH36      SRRD    3296.49 3428.89 3428.89 3296.49 3428.89 3428.89 3428.89 (UniMod:1)AAAAAAALESWQAAAPR AAAAAAALESWQAAAPR   (UniMod:1)AAAAAAALESWQAAAPR2    2   3.99074e-05 1.96448e-05 0.000159821 0.000159821 0.000146135 0.000161212 0   1   3296.49 3428.89 3296.49 0.852479    19.9208 19.8731 19.9685 123.9   19.8266 128.292 0   0.960106    5308.05 1.96902 0.683134    0.362287    0.999997    1.23691 3.43242e-05 1212.01;2178.03;1390.01;1020.01;714.008;778.008;    1212.01;1351.73;887.591;432.92;216.728;732.751; 0.956668;0.757581;0.670497;0.592489;0.47072;0.855203;   30053   1.19708 1.19328 1.19453 1.19469
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642   Q9UH36  Q9UH36      SRRD    2365    2334.05 2334.05 2365    2334.05 2334.05 2334.05 (UniMod:1)AAAAAAALESWQAAAPR AAAAAAALESWQAAAPR   (UniMod:1)AAAAAAALESWQAAAPR2    2   0.000184434 1.96448e-05 0.000596659 0.000596659 0.000146135 0.000604961 0   1   2365    2334.05 2365    0.922581    19.905  19.8573 19.9527 123.9   19.782  128.535 0   0.940191    4594.04 1.31068 0.758988    0   0.995505    0.28633 2.12584e-06 1209.02;1210.02;1414.02;1051.01;236.003;130.002;    1209.02;1109.89;732.154;735.384;0;46.0967;  0.919244;0.937624;0.436748;0.639369;0.296736;0.647924;  30029   1.195   1.19328 1.19381 1.19339
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648   Q9UH36  Q9UH36      SRRD    1664.51 1635.46 1635.47 1664.51 1635.46 1635.47 1635.47 (UniMod:1)AAAAAAALESWQAAAPR AAAAAAALESWQAAAPR   (UniMod:1)AAAAAAALESWQAAAPR2    2   0.000185123 1.96448e-05 0.000307409 0.000307409 0.000146135 0.000311332 0   1   1664.51 1635.46 1664.51 0.811147    19.8893 19.8416 19.937  123.9   19.7567 128.896 0   0.458773    6614.06 1.7503  0.491071    0.00111683  0.997286    1.92753 2.80543e-05 744.01;1708.02;1630.02;1475.02;0;533.006;   322.907;808.594;577.15;536.033;0;533.006;   0.760181;0.764072;0.542005;0.415779;0;0.913438; 30005   1.19409 1.19328 1.19323 1.19308
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654   Q9UH36  Q9UH36      SRRD    3369.91 3343.38 3343.38 3369.91 3343.38 3343.38 3343.38 (UniMod:1)AAAAAAALESWQAAAPR AAAAAAALESWQAAAPR   (UniMod:1)AAAAAAALESWQAAAPR2    2   0.000153377 1.96448e-05 0.000298151 0.000298151 0.000146135 0.000302297 0   1   3369.91 3343.38 3369.91 0.798104    19.872  19.8243 19.9196 123.9   19.7347 128.576 0   0.892774    5026.05 1.01465 0.704953    0   0.996593    0.476378    7.76581e-06 1654.02;1286.02;1894.02;993.011;778.008;1190.01;    1638.42;1286.02;1293.97;466.705;292.465;445.475;    0.854908;0.860012;0.708773;0.584142;0.716032;0.410465;  29981   1.19136 1.19328 1.19169 1.1919
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636   P51608-2    P51608-2        MECP2   1585.53 1649.21 7673.34 1585.53 1649.21 7673.34 7673.34 AAAAAAAPSGGGGGGEEERLEEK AAAAAAAPSGGGGGGEEERLEEK (UniMod:1)AAAAAAAPSGGGGGGEEERLEEK3  3   0.00014185  5.69066e-05 0.000159821 0.000159821 0.000146135 0.000161212 0   1   861.509 896.11  861.509 0.530747    7.34894 7.30125 7.39665 14.6582 7.35635 14.5905 0   0.85024 2010.02 1.27844 0.470734    0.117495    0.998266    0.848349    0.0613877   905.008;1021.01;1179.01;419.003;753.005;638.006;    422.004;0;439.505;419.003;325.502;119.251;  0.626628;-0.441015;0.438684;0.800641;0.794403;0.458813; 11077   1.01    1.01225 1.01075 1.01099
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642   P51608-2    P51608-2        MECP2   16870.2 16649.4 7963.26 16870.2 16649.4 7963.26 7963.26 AAAAAAAPSGGGGGGEEERLEEK AAAAAAAPSGGGGGGEEERLEEK (UniMod:1)AAAAAAAPSGGGGGGEEERLEEK3  3   0.000200767 5.69066e-05 0.000152765 0.000152765 0.000146135 0.000154631 0   1   1832.12 1808.14 1832.12 0.438822    7.3176  7.26989 7.36527 14.6582 7.29706 14.8141 0   0.814702    3622.03 0.571375    0.278903    0.971334    0.994097    0.779006    0.0590956   1430.01;946.009;804.008;260.002;710.006;232.002;    886.115;946.009;0;0;431.102;0;  -0.0551893;0.901557;0.0979035;-0.326533;0.334642;-0.120337; 11029   1.01417 1.01225 1.01136 1.01447
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648   P51608-2    P51608-2        MECP2   16242.7 15959.3 13129.8 16242.7 15959.3 13129.8 13129.8 AAAAAAAPSGGGGGGEEERLEEK AAAAAAAPSGGGGGGEEERLEEK (UniMod:1)AAAAAAAPSGGGGGGEEERLEEK3  3   6.98405e-05 5.69066e-05 0.000168492 0.000168492 0.000146135 0.000169578 0   1   2765.24 2716.99 2765.24 0.619188    7.28562 7.23794 7.33338 14.6582 7.22243 15.2233 0   0.859167    2180.02 1.50997 0.43755 0.191245    0.999939    0.420023    0.00548723  1807.01;1018.01;1230.01;554.005;1216.01;276.002;    954.327;1006.89;804.021;554.005;0;143.651;  0.483734;0.907585;0.418797;0.61368;-0.523993;0.70046;   10981   1.015   1.01225 1.01115 1.01558
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654   P51608-2    P51608-2        MECP2   20914.7 20750   16106   20914.7 20750   16106   16106   AAAAAAAPSGGGGGGEEERLEEK AAAAAAAPSGGGGGGEEERLEEK (UniMod:1)AAAAAAAPSGGGGGGEEERLEEK3  3   0.000603914 5.69066e-05 0.000153516 0.000153516 0.000146135 0.000155304 0   1   4556.58 4520.72 4556.58 0.620251    7.26825 7.22055 7.31601 14.6582 7.18207 15.448  0   0.79218 3193.03 0.113147    0.344593    0.144439    0.971834    1.05178 0.112962    2855.02;1760.01;830.007;116.001;564.005;751.006;    2266.46;1760.01;530.111;0;0;317.258;    0.430169;0.867218;0.612985;-0.310664;-0.386197;0.286451;    10957   1.01208 1.01225 1.00965 1.01449
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636   Q96P70  Q96P70      IPO9    155722  161976  160062  155722  161976  160062  160062  (UniMod:1)AAAAAAGAASGLPGPVAQGLK AAAAAAGAASGLPGPVAQGLK   (UniMod:1)AAAAAAGAASGLPGPVAQGLK2    2   3.99074e-05 1.96448e-05 0.000159821 0.000159821 0.000146135 0.000161212 0   1   44791.6 46590.6 44791.6 0.903543    14.709  14.6614 14.7567 77.7384 14.7374 77.4968 0   0.962703    395646  1.16168 0.790083    0   0.999999    0.491003    0.00391533  17738.2;18223.2;16218.2;17747.2;14484.2;12569.2;    17738.2;18223.2;16150;16115.2;14484.2;12569.2;  0.879361;0.89314;0.807683;0.73629;0.863152;0.984215;    22187   1.225   1.23344 1.23458 1.22263
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642   Q96P70  Q96P70      IPO9    172360  170104  155889  172360  170104  155889  155889  (UniMod:1)AAAAAAGAASGLPGPVAQGLK AAAAAAGAASGLPGPVAQGLK   (UniMod:1)AAAAAAGAASGLPGPVAQGLK2    2   4.98766e-05 1.96448e-05 0.000152765 0.000152765 0.000146135 0.000154631 0   1   44700.5 44115.4 44700.5 0.615196    14.6456 14.5979 14.6933 77.7384 14.6419 77.8394 0   0.9107  553292  0.747052    0.814842    0   0.999996    0.830219    0.0331339   19349.2;20154.2;20586.2;20040.3;13620.2;12105.1;    19349.2;19014.1;19329.7;18862.6;13404.2;11947.1;    0.862894;0.42962;0.293099;0.655948;0.517625;0.323501;   22091   1.22042 1.23344 1.23392 1.21891
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648   Q96P70  Q96P70      IPO9    153712  151030  152845  153712  151030  152845  152845  (UniMod:1)AAAAAAGAASGLPGPVAQGLK AAAAAAGAASGLPGPVAQGLK   (UniMod:1)AAAAAAGAASGLPGPVAQGLK2    2   6.08421e-05 1.96448e-05 0.000168492 0.000168492 0.000146135 0.000169578 0   1   40439.4 39733.8 40439.4 0.833327    14.6301 14.5824 14.6777 77.7384 14.5747 78.2527 0   0.989019    1.0768e+06  1.68843 0.759575    0   0.999999    0.674737    0.0631384   17597.2;19526.2;16647.2;16204.2;12871.2;11069.2;    17377.7;19526.2;16647.2;16204.2;12871.2;10190.5;    0.828262;0.979726;0.827511;0.9628;0.90466;0.751867; 22067   1.22708 1.23344 1.23332 1.2261
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654   Q96P70  Q96P70      IPO9    147008  145850  159209  147008  145850  159209  159209  (UniMod:1)AAAAAAGAASGLPGPVAQGLK AAAAAAGAASGLPGPVAQGLK   (UniMod:1)AAAAAAGAASGLPGPVAQGLK2    2   4.42595e-05 1.96448e-05 0.000153516 0.000153516 0.000146135 0.000155304 0   1   41861.6 41532.1 41861.6 0.752921    14.549  14.5013 14.5967 77.7384 14.5155 78.0748 0   0.877873    939172  1.59762 0.821027    0   0.999997    0.397952    1.22212e-05 18143.2;19574.2;17444.2;17956.2;11427.2;13025.2;    17409.2;18432.7;16706.7;10820.4;11427.2;13025.2;    0.625292;0.399297;0.717726;0.321047;0.864595;0.825535;  21947   1.2275  1.23344 1.23199 1.2281
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636   P28482  P28482      MAPK1   72652.7 75570.7 78604.9 72652.7 75570.7 78604.9 78604.9 (UniMod:1)AAAAAAGAGPEM(UniMod:35)VR AAAAAAGAGPEMVR  (UniMod:1)AAAAAAGAGPEM(UniMod:35)VR2    2   0.00693727  0.000834654 0.000159821 0.000159821 0.000146135 0.000161212 0   1   192.198 199.917 192.198 0.0197094   7.4249  7.37721 7.4726  15.9025 7.49813 15.2482 0   0.754191    8842.06 1.19725 0.470393    0.086229    0.843331    2.80548 0.384248    897.008;1032.01;279.002;377.003;440.004;286.003;    0;137.786;54.4117;0;89.692;286.003; -0.20379;-0.0679789;0.241761;-0.388501;-0.0459688;0.973644; 11191   1.01917 1.0262  1.02479 1.02031
-F:\XXX\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642.d  20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642   P28482  P28482      MAPK1   69911.3 68996.2 63388.2 69911.3 68996.2 63388.2 63388.2 (UniMod:1)AAAAAAGAGPEM(UniMod:35)VR AAAAAAGAGPEMVR  (UniMod:1)AAAAAAGAGPEM(UniMod:35)VR2    2   0.00122498  0.000834654 0.000152765 0.000152765 0.000146135 0.000154631 0   1   1572.67 1552.08 1572.67 0.906427    7.45711 7.40943 7.50482 15.9025 7.43922 16.0749 0   0.371998    5937.05 0.30888 0.510876    0.72688 0.95182 1.96259 0.65474 1320.01;838.009;638.006;827.009;562.005;339.003;    1320.01;252.656;0;213.073;330.325;0;    0.976001;0.542934;0.346963;0.38014;0.442774;-0.259898;  11239   1.01773 1.0262  1.02509 1.01834
-''')
-diann_reader = psm_reader_provider.get_reader_by_yaml(psm_reader_yaml['diann'])
-diann_reader.import_file(tsv)
-
-assert 'ccs' in diann_reader.psm_df.columns
-assert len(diann_reader.psm_df) == 14
-assert np.sum(diann_reader.psm_df.mods.str.contains('Acetyl@Protein N-term')) == 10
-assert np.sum(~diann_reader.psm_df.mods.str.contains('Acetyl@Protein N-term')) == 4
-assert np.sum(diann_reader.psm_df.mods.str.contains('Oxidation@M')) == 2
-assert np.all(np.array(diann_reader.modification_mapping['Phospho@S'])==np.array([
-    'S(Phospho (S))',
-    'S(Phospho (ST))',
-    'S(Phospho (STY))',
-    'S(ph)',
-    'S(UniMod:21)',
-    'pS',
-    'S[Phospho (S)]',
-    'S[Phospho (ST)]',
-    'S[Phospho (STY)]',
-    'S[ph]',
-    'S[UniMod:21]'])
-)
-
- - -
- -
- -
- - - - \ No newline at end of file diff --git a/docs/psm_reader/dia_psm_reader.rst b/docs/psm_reader/dia_psm_reader.rst new file mode 100644 index 00000000..c18ea9f2 --- /dev/null +++ b/docs/psm_reader/dia_psm_reader.rst @@ -0,0 +1,7 @@ +alphabase.psm_reader.dia_psm_reader +=================================== + +.. automodule:: alphabase.psm_reader.dia_psm_reader + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/psm_reader/maxquant_reader.html b/docs/psm_reader/maxquant_reader.html deleted file mode 100644 index b68a0465..00000000 --- a/docs/psm_reader/maxquant_reader.html +++ /dev/null @@ -1,799 +0,0 @@ - - - - - - - - - -alphabase - MaxQuant PSM reader - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- -
- - - - - -
- -
-
-

MaxQuant PSM reader

-
- - - -
- - - -
- - -
- - -
-

source

-
-

MaxQuantReader

-
-
 MaxQuantReader (column_mapping:dict=None, modification_mapping:dict=None,
-                 fdr=0.01, keep_decoy=False, mod_sep='()',
-                 underscore_for_ncterm=True, fixed_C57=True,
-                 mod_seq_columns=['Modified sequence'], **kwargs)
-
-

Reader for MaxQuant msms.txt and evidence.txt

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
column_mappingdictNoneBy default None. If None, use
psm_reader_yaml['maxquant']['column_mapping']
(alphabase.psm_reader.psm_reader_yaml).
modification_mappingdictNoneBy default None. If None, use
psm_reader_yaml['maxquant']['modification_mapping']
(alphabase.psm_reader.psm_reader_yaml).
fdrfloat0.01Load PSMs with FDR < this fdr, by default 0.01
keep_decoyboolFalseIf keep decoy PSMs, by default False
mod_sepstr()Symbols to separate modified sequences,
e.g. AM(Oxidation)PIC(+57)QMK.
By default ‘()’
underscore_for_nctermboolTrueIf search engine uses an under score in N- and C-term,
_(Acetyl)AM(Oxidation)PIC(+57)QMK_.
by default True
fixed_C57boolTrueIf true, the search engine will not show Carbamidomethyl
in the modified sequences.
by default True
mod_seq_columnslist[‘Modified sequence’]The columns to find modified sequences,
by default [‘Modified sequence’]
kwargs
-
-

source

-
-
-

parse_mod_seq

-
-
 parse_mod_seq (modseq:str, mod_sep:str='()', fixed_C57:bool=True,
-                underscore_for_ncterm:bool=True)
-
-

Extract modifications and sites from the modified sequence (modseq)

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
modseqstrmodified sequence to extract modifications.
mod_sepstr()separator to indicate the modification section.
Defaults to ‘()’
fixed_C57boolTrue
underscore_for_nctermboolTrueIf modseq starts and ends with underscores.
Defaults to True.
Returnstuplestr: modification names, separated by ‘;’

str: modification sites, separated by ‘;’.
0 for N-term; -1 for C-term; 1 to N for normal modifications.
-
-
-

Column and modification mapping from alphabase to MaxQuant

-
-
psm_reader_yaml['maxquant']['column_mapping']
-
-
{'sequence': 'Sequence',
- 'charge': 'Charge',
- 'rt': 'Retention time',
- 'ccs': 'CCS',
- 'mobility': ['Mobility', 'IonMobility', 'K0', '1/K0'],
- 'scan_num': ['Scan number', 'MS/MS scan number', 'Scan index'],
- 'raw_name': 'Raw file',
- 'precursor_mz': 'm/z',
- 'score': 'Score',
- 'proteins': 'Proteins',
- 'genes': ['Gene Names', 'Gene names'],
- 'decoy': 'Reverse'}
-
-
-
-
psm_reader_yaml['maxquant']['modification_mapping']
-
-
{'Acetyl@Protein N-term': ['_(Acetyl (Protein N-term))',
-  '_(ac)',
-  '_(UniMod:1)'],
- 'Carbamidomethyl@C': ['C(Carbamidomethyl (C))', 'C(UniMod:4)'],
- 'Oxidation@M': ['M(Oxidation (M))', 'M(ox)', 'M(UniMod:35)'],
- 'Phospho@S': ['S(Phospho (S))',
-  'S(Phospho (ST))',
-  'S(Phospho (STY))',
-  'S(ph)',
-  'S(UniMod:21)',
-  'pS'],
- 'Phospho@T': ['T(Phospho (T))',
-  'T(Phospho (ST))',
-  'T(Phospho (STY))',
-  'T(ph)',
-  'T(UniMod:21)',
-  'pT'],
- 'Phospho@Y': ['Y(Phospho (Y))',
-  'Y(Phospho (STY))',
-  'Y(ph)',
-  'Y(UniMod:21)',
-  'pY'],
- 'Deamidated@N': ['N(Deamidation (NQ))', 'N(de)'],
- 'Deamidated@Q': ['Q(Deamidation (NQ))', 'Q(de)'],
- 'GlyGly@K': ['K(GlyGly (K))', 'K(gl)']}
-
-
-
-
-

Testing

-
-
import io
-import numpy as np
-
-
-
mq_tsv = io.StringIO('''Raw file    Scan number Scan index  Sequence    Length  Missed cleavages    Modifications   Modified sequence   Oxidation (M) Probabilities Oxidation (M) Score diffs   Acetyl (Protein N-term) Oxidation (M)   Proteins    Charge  Fragmentation   Mass analyzer   Type    Scan event number   Isotope index   m/z Mass    Mass error [ppm]    Mass error [Da] Simple mass error [ppm] Retention time  PEP Score   Delta score Score diff  Localization prob   Combinatorics   PIF Fraction of total spectrum  Base peak fraction  Precursor full scan number  Precursor Intensity Precursor apex fraction Precursor apex offset   Precursor apex offset time  Matches Intensities Mass deviations [Da]    Mass deviations [ppm]   Masses  Number of matches   Intensity coverage  Peak coverage   Neutral loss level  ETD identification type Reverse All scores  All sequences   All modified sequences  Reporter PIF    Reporter fraction   id  Protein group IDs   Peptide ID  Mod. peptide ID Evidence ID Oxidation (M) site IDs
-20190402_QX1_SeVW_MA_HeLa_500ng_LC11    81358   73979   AAAAAAAAAPAAAATAPTTAATTAATAAQ   29  0   Unmodified  _(Acetyl (Protein N-term))AAAAAAAAM(Oxidation (M))PAAAATAPTTAATTAATAAQ_         0   0   sp|P37108|SRP14_HUMAN   3   HCD FTMS    MULTI-MSMS  13  1   790.07495   2367.203    0.35311 0.00027898  -0.061634807    70.261  0.012774    41.423  36.666  NaN NaN 1   0   0   0   81345   10653955    0.0338597821787898  -11 0.139877319335938   y1;y2;y3;y4;y11;y1-NH3;y2-NH3;a2;b2;b3;b4;b5;b6;b7;b8;b9;b11;b12;b6(2+);b8(2+);b13(2+);b18(2+)  2000000;2000000;300000;400000;200000;1000000;400000;300000;600000;1000000;2000000;3000000;3000000;3000000;3000000;2000000;600000;500000;1000000;2000000;300000;200000   5.2861228709844E-06;-6.86980268369553E-05;-0.00238178789771837;0.000624715964988809;-0.0145624692099773;-0.000143471782706683;-0.000609501446461991;-0.000524972720768346;0.00010190530804266;5.8620815195809E-05;0.000229901232955854;-0.000108750048696038;-0.000229593152369034;0.00183148682538103;0.00276641182404092;0.000193118923334623;0.00200988580445483;0.000102216846016745;5.86208151389656E-05;0.000229901232955854;-0.00104559184393338;0.00525030008475369 0.0359413365445091;-0.314964433555295;-8.23711898839045;1.60102421155213;-14.8975999917227;-1.10320467763838;-3.03102462870716;-4.56152475051625;0.712219104095465;0.273777366204575;0.806231096969562;-0.305312183824154;-0.537399178230218;3.67572664689217;4.85930954169285;0.301587577451224;2.48616190909398;0.116225745519871;0.273777365939099;0.806231096969562;-2.19774169175011;7.53961026980589  147.076413378177;218.113601150127;289.153028027798;390.197699998035;977.50437775671;130.050013034583;201.087592852046;115.087114392821;143.081402136892;214.118559209185;285.155501716567;356.192954155649;427.230188786552;498.265241494374;569.301420357176;640.341107437877;808.429168310795;879.468189767554;214.118559209185;285.155501716567;475.757386711244;696.362265007215    22  0.262893575628735   0.0826446280991736  None    Unknown     41.4230894199432;4.75668724862449;3.9515580701967   AAAAAAAAAPAAAATAPTTAATTAATAAQ;FHRGPPDKDDMVSVTQILQGK;PVTLWITVTHMQADEVSVWR    _AAAAAAAAAPAAAATAPTTAATTAATAAQ_;_FHRGPPDKDDMVSVTQILQGK_;_PVTLWITVTHMQADEVSVWR_          0   1443    0   0   0   
-20190402_QX1_SeVW_MA_HeLa_500ng_LC11    81391   74010   AAAAAAAAAAPAAAATAPTTAATTAATAAQ  29  0   Unmodified  _AAAAAAAAAPAAAATAPTTAATTAATAAQ_         0   0   sp|P37108|SRP14_HUMAN   2   HCD FTMS    MULTI-MSMS  14  0   1184.6088   2367.203    0.037108    4.3959E-05  1.7026696   70.287  7.1474E-09  118.21  100.52  NaN NaN 1   0   0   0   81377   9347701 0.166790347889974   -10 0.12664794921875    y1;y2;y3;y4;y5;y9;y12;y13;y14;y20;y13-H2O;y20-H2O;y1-NH3;y20-NH3;b3;b4;b5;b6;b7;b8;b9;b11;b12;b13;b14;b15;b16;b19;b15-H2O;b16-H2O   500000;600000;200000;400000;200000;100000;200000;1000000;200000;300000;200000;100000;100000;70000;300000;900000;2000000;3000000;5000000;8000000;6000000;600000;800000;600000;200000;300000;200000;300000;300000;1000000 -0.000194444760495571;0.000149986878682284;0.000774202587820128;-0.0002445094036716;0.000374520568641401;-0.00694293246522193;-0.0109837291331587;-0.0037745820627606;-0.000945546471939451;0.00152326440706929;0.00506054832726477;0.00996886361417637;6.25847393393997E-05;-0.024881067836759;-3.11821549132674E-05;-0.000183099230639527;0.000161332473453513;0.000265434980121881;0.000747070697229901;0.000975534518261156;0.00101513939785036;0.00651913000274362;0.0058584595163893;0.00579536744021425;0.00131097834105276;-0.0131378531671089;0.00472955218901916;-0.00161006322559842;-0.00201443239325272;0.0227149399370319 -1.32206444236914;0.687655553213019;2.6775131607882;-0.626628140021726;0.811995006209331;-8.6203492854282;-10.1838066275079;-3.21078702288986;-0.758483069159249;0.881072738747222;4.37168212373889;5.82682888353564;0.481236695337485;-14.5343986203644;-0.145630261806375;-0.642102166533079;0.452935954800214;0.621293379181583;1.49934012872483;1.71355878380837;1.58531240493271;8.06399202403175;6.6614096214532;6.09718023739784;1.28333378040908;-11.7030234519348;3.96235146626144;-1.07856912288932;-1.82370619437775;19.3220953109188    147.07661310906;218.113382465221;289.149872037312;390.198569223404;461.235063981231;805.411965958065;1078.54847749073;1175.59403219566;1246.62831694787;1728.87474561429;1157.57463237897;1710.85573532879;130.049806978061;1711.87460084504;214.118649012155;285.155914717031;356.192684073126;427.22969375842;498.266325910503;569.303211234482;640.340285417402;808.424659066597;879.462433524883;950.49961040476;1021.54120858166;1122.60333588727;1193.62258226971;1492.77704268533;1104.58164778019;1175.59403219566  30  0.474003002083763   0.167630057803468   None    Unknown     118.209976573419;17.6937689289157;17.2534171481793  AAAAAAAAAPAAAATAPTTAATTAATAAQ;SELKQEAMQSEQLQSVLYLK;VGSSVPSKASELVVMGDHDAARR  _AAAAAAAAAPAAAATAPTTAATTAATAAQ_;_SELKQEAM(Oxidation (M))QSEQLQSVLYLK_;_VGSSVPSKASELVVMGDHDAARR_         1   1443    0   0   1   
-20190402_QX1_SeVW_MA_HeLa_500ng_LC11    107307  98306   AAAAAAAGDSDSWDADAFSVEDPVRK  26  1   Acetyl (Protein N-term) _(Acetyl (Protein N-term))AAAAAAAGDSDSWDADAFSVEDPVRK_           1   0   sp|O75822|EIF3J_HUMAN   3   HCD FTMS    MULTI-MSMS  10  2   879.06841   2634.1834   -0.93926    -0.00082567 -3.2012471  90.978  2.1945E-12  148.95  141.24  NaN NaN 1   0   0   0   107297  10193939    0.267970762043589   -8  0.10211181640625    y1;y2;y4;y5;y6;y7;y8;y9;y10;y11;y12;y13;y14;y15;y17;y18;y19;y20;y21;y23;y21-H2O;y1-NH3;y19-NH3;y14(2+);y16(2+);y22(2+);a2;b2;b3;b4;b5;b6;b7 300000;200000;3000000;600000;1000000;500000;2000000;1000000;1000000;1000000;90000;1000000;400000;900000;1000000;400000;3000000;2000000;1000000;400000;100000;200000;200000;80000;100000;200000;200000;2000000;5000000;5000000;5000000;2000000;300000    1.34859050149316E-07;-6.05140996867704E-06;2.27812602133781E-05;0.00128986659160546;-0.00934536073077652;0.000941953783126337;-0.00160424237344614;-0.00239257341399934;-0.00111053968612396;-0.00331340710044969;0.00330702864630439;0.000963683996815234;0.00596290290945944;-0.00662057038289277;-0.0117122701335575;0.00777853472800416;0.0021841542961738;0.000144322111736983;-0.00087403893667215;0.0197121595674616;-0.021204007680808;-0.000308954599830713;-0.026636719419912;-0.0137790992353075;0.00596067266928912;-0.0077053835773313;9.11402199221811E-06;-0.000142539300128419;-0.000251999832926231;1.90791054137662E-05;-0.00236430185879044;-9.54583337602344E-05;-0.000556959493223985  0.000916705048437201;-0.0199575598103408;0.0456231928690862;2.09952637717462;-12.5708704058425;1.11808305811426;-1.72590731777249;-2.22239181008062;-0.967696370445928;-2.62418809422166;2.47964286628144;0.665205752892023;3.64753748704453;-3.84510115530963;-6.08782672045773;3.81508105974837;1.04209904973991;0.0666012719936656;-0.390545453668809;8.28224925531311;-9.55133250134922;-2.37499239179248;-12.8127653858411;-16.846761946123;6.48662354975264;-6.67117082062383;0.0580151981289049;-0.770098855873447;-0.983876895688683;0.0583162347158579;-5.93738717724506;-0.203431522818505;-1.03087538746314  147.112804035741;303.21392125011;499.33507018564;614.360746132308;743.413974455831;842.472101057517;929.506675663573;1076.57587791081;1147.61170966489;1262.6408555643;1333.67134891635;1448.700635293;1634.77494902759;1721.81956091078;1923.88362405243;2038.89107627957;2095.9181343836;2166.95728800359;2237.99542015244;2380.04906152953;2220.00518543488;130.0865640237;2078.92040615582;817.907873297785;918.917619246831;1155.02717356753;157.097144992378;185.0922112678;256.129434516133;327.166277224995;398.205774393759;469.240619338034;540.278194626993  33  0.574496146107112   0.14410480349345    None    Unknown     148.951235201399;7.71201258444522;7.36039532447559  AAAAAAAGDSDSWDADAFSVEDPVRK;PSRQESELMWQWVDQRSDGER;HTLTSFWNFKAGCEEKCYSNR  _(Acetyl (Protein N-term))AAAAAAAGDSDSWDADAFSVEDPVRK_;_PSRQESELM(Oxidation (M))WQWVDQRSDGER_;_HTLTSFWNFKAGCEEKCYSNR_            2   625 1   1   2   '''
-)
-
-mq_reader = psm_reader_provider.get_reader('maxquant')
-mq_reader.import_file(mq_tsv)
-assert len(mq_reader.psm_df) == 3
-assert mq_reader.psm_df.mods.values[1] == 'Acetyl@Protein N-term;Oxidation@M'
-assert mq_reader.psm_df.mod_sites.values[1] == '0;9'
-assert mq_reader.psm_df.mods.values[2] == ''
-assert mq_reader.psm_df.mod_sites.values[2] == ''
-assert np.all(np.array(mq_reader.modification_mapping['Phospho@S'])==np.array([
-    'S(Phospho (S))',
-    'S(Phospho (ST))',
-    'S(Phospho (STY))',
-    'S(ph)',
-    'S(UniMod:21)',
-    'pS',
-    'S[Phospho (S)]',
-    'S[Phospho (ST)]',
-    'S[Phospho (STY)]',
-    'S[ph]',
-    'S[UniMod:21]'])
-)
-mq_reader.psm_df
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sequencechargertscan_numraw_nameprecursor_mzscoreproteinsdecoyspec_idxmodsmod_sitesnAArt_norm
0AAAAAAAGDSDSWDADAFSVEDPVRK390.97810730720190402_QX1_SeVW_MA_HeLa_500ng_LC11879.06841148.950sp|O75822|EIF3J_HUMAN0107306Acetyl@Protein N-term0261.000000
1AAAAAAAAAPAAAATAPTTAATTAATAAQ370.2618135820190402_QX1_SeVW_MA_HeLa_500ng_LC11790.0749541.423sp|P37108|SRP14_HUMAN081357Acetyl@Protein N-term;Oxidation@M0;9290.772286
2AAAAAAAAAAPAAAATAPTTAATTAATAAQ270.2878139120190402_QX1_SeVW_MA_HeLa_500ng_LC111184.60880118.210sp|P37108|SRP14_HUMAN081390300.772571
-
-
-
- - -
- -
- -
- - - - \ No newline at end of file diff --git a/docs/psm_reader/maxquant_reader.rst b/docs/psm_reader/maxquant_reader.rst new file mode 100644 index 00000000..c588e67e --- /dev/null +++ b/docs/psm_reader/maxquant_reader.rst @@ -0,0 +1,7 @@ +alphabase.psm_reader.maxquant_reader +=========================================== + +.. automodule:: alphabase.psm_reader.maxquant_reader + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/psm_reader/msfragger_reader.html b/docs/psm_reader/msfragger_reader.html deleted file mode 100644 index b7e94443..00000000 --- a/docs/psm_reader/msfragger_reader.html +++ /dev/null @@ -1,489 +0,0 @@ - - - - - - - - - -alphabase - MSFragger Reader - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- -
- - - - - -
- -
-
-

MSFragger Reader

-
- - - -
- - - -
- - -
- - -
/Users/zengwenfeng/opt/anaconda3/lib/python3.8/site-packages/fastcore/docscrape.py:225: UserWarning: Unknown section Attributes
-  else: warn(msg)
-
-

source

-
-

MSFragger_PSM_TSV_Reader

-
-
 MSFragger_PSM_TSV_Reader (column_mapping:dict=None,
-                           modification_mapping:dict=None, fdr=0.01,
-                           keep_decoy=False, rt_unit='second', **kwargs)
-
-

The Base class for all PSMReaders. The key of the sub-classes for different search engine format is to re-define column_mapping and modification_mapping.

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
column_mappingdictNoneA dict that maps alphabase’s columns to other search engine’s.
The key of the column_mapping is alphabase’s column name, and
the value could be the column name or a list of column names
in other engine’s result.
If it is None, this dict will be init by
self._init_column_mapping. The dict values could be
either str or list, for exaplme:
columns_mapping = {
‘sequence’: ‘NakedSequence’, #str
‘charge’: ‘Charge’, #str
‘proteins’:[‘Proteins’,‘UniprotIDs’], # list, this reader will automatically detect all of them.
}
Defaults to None.
modification_mappingdictNoneA dict that maps alphabase’s modifications to other engine’s.
If it is None, this dict will be init by
self._init_modification_mapping. The dict values could be
either str or list, for exaplme:
modification_mapping = {
‘Oxidation@M’: ‘Oxidation (M)’, # str
‘Phospho@S’: [‘S(Phospho (STY))’,‘S(ph)’,‘pS’], # list, this reader will automatically detect all of them.
}
Defaults to None.
fdrfloat0.01FDR level to keep PSMs.
Defaults to 0.01.
keep_decoyboolFalseIf keep decoy PSMs in self.psm_df.
Defautls to False.
rt_unitstrsecond
kwargs
- - -
- -
- -
- - - - \ No newline at end of file diff --git a/docs/psm_reader/msfragger_reader.rst b/docs/psm_reader/msfragger_reader.rst new file mode 100644 index 00000000..b1dcdea2 --- /dev/null +++ b/docs/psm_reader/msfragger_reader.rst @@ -0,0 +1,7 @@ +alphabase.psm_reader.msfragger_reader +=========================================== + +.. automodule:: alphabase.psm_reader.msfragger_reader + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/psm_reader/pfind_reader.html b/docs/psm_reader/pfind_reader.html deleted file mode 100644 index 011d3a92..00000000 --- a/docs/psm_reader/pfind_reader.html +++ /dev/null @@ -1,606 +0,0 @@ - - - - - - - - - -alphabase - pFind PSM Reader - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- -
- - - - - -
- -
-
-

pFind PSM Reader

-
- - - -
- - - -
- - -
- - -
-

source

-
-

parse_pfind_protein

-
-
 parse_pfind_protein (protein, keep_reverse=True)
-
-
-

source

-
-
-

get_pFind_mods

-
-
 get_pFind_mods (pfind_mod_str)
-
-
-

source

-
-
-

translate_pFind_mod

-
-
 translate_pFind_mod (mod_str)
-
-
-

source

-
-
-

convert_one_pFind_mod

-
-
 convert_one_pFind_mod (mod)
-
-
/Users/zengwenfeng/opt/anaconda3/lib/python3.8/site-packages/fastcore/docscrape.py:225: UserWarning: Unknown section Attributes
-  else: warn(msg)
-
-

source

-
-
-

pFindReader

-
-
 pFindReader (column_mapping:dict=None, modification_mapping:dict=None,
-              fdr=0.01, keep_decoy=False, **kwargs)
-
-

The Base class for all PSMReaders. The key of the sub-classes for different search engine format is to re-define column_mapping and modification_mapping.

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
column_mappingdictNoneA dict that maps alphabase’s columns to other search engine’s.
The key of the column_mapping is alphabase’s column name, and
the value could be the column name or a list of column names
in other engine’s result.
If it is None, this dict will be init by
self._init_column_mapping. The dict values could be
either str or list, for exaplme:
columns_mapping = {
‘sequence’: ‘NakedSequence’, #str
‘charge’: ‘Charge’, #str
‘proteins’:[‘Proteins’,‘UniprotIDs’], # list, this reader will automatically detect all of them.
}
Defaults to None.
modification_mappingdictNoneA dict that maps alphabase’s modifications to other engine’s.
If it is None, this dict will be init by
self._init_modification_mapping. The dict values could be
either str or list, for exaplme:
modification_mapping = {
‘Oxidation@M’: ‘Oxidation (M)’, # str
‘Phospho@S’: [‘S(Phospho (STY))’,‘S(ph)’,‘pS’], # list, this reader will automatically detect all of them.
}
Defaults to None.
fdrfloat0.01FDR level to keep PSMs.
Defaults to 0.01.
keep_decoyboolFalseIf keep decoy PSMs in self.psm_df.
Defautls to False.
kwargs
-
-
-

Column and modification mapping from alphabase to pFind

-
-
psm_reader_yaml['pfind']['column_mapping']
-
-
{'sequence': 'Sequence',
- 'charge': 'Charge',
- 'rt': 'RT',
- 'raw_name': 'raw_name',
- 'query_id': 'File_Name',
- 'scan_num': 'Scan_No',
- 'score': 'Final_Score',
- 'proteins': 'Proteins',
- 'uniprot_ids': 'Proteins',
- 'fdr': 'Q-value',
- 'decoy': ['Target/Decoy', 'Targe/Decoy']}
-
-
-

There is no modification mapping as pFind also uses unimod name for all modifications, we just need to convert the sites (AAs) accordingly.

-
-
-

Testing

- - -
- -
- -
- - - - \ No newline at end of file diff --git a/docs/psm_reader/pfind_reader.rst b/docs/psm_reader/pfind_reader.rst new file mode 100644 index 00000000..a1fab901 --- /dev/null +++ b/docs/psm_reader/pfind_reader.rst @@ -0,0 +1,7 @@ +alphabase.psm_reader.pfind_reader +=================================== + +.. automodule:: alphabase.psm_reader.pfind_reader + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/psm_reader/psm_reader.html b/docs/psm_reader/psm_reader.html deleted file mode 100644 index f6075814..00000000 --- a/docs/psm_reader/psm_reader.html +++ /dev/null @@ -1,790 +0,0 @@ - - - - - - - - - -alphabase - Base Class for PSM Readers - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- -
- - - - - -
- -
-
-

Base Class for PSM Readers

-
- - - -
- - - -
- - -
- - -
-

source

-
-

keep_modifications

-
-
 keep_modifications (mod_str:str, mod_set:set)
-
-

Check if modifications of mod_str are in mod_set.

- ----- - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDetails
mod_strstrmod list in str format, seperated by ‘;’,
e.g. Oxidation@M;Phospho@S.
mod_setsetmod set to check
Returnsstr
-
-

source

-
-
-

translate_other_modification

-
-
 translate_other_modification (mod_str:str, mod_dict:dict)
-
-

Translate modifications of mod_str to the AlphaBase format mapped by mod_dict.

- ----- - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDetails
mod_strstrmod list in str format, seperated by ‘;’,
e.g. ModA;ModB
mod_dict : dict
translate mod dict from others to AlphaBase,
e.g. for pFind, key=[‘Phospho[S]’,‘Oxidation[M]’],
value=[‘Phospho@S’,‘Oxidation@M’]
mod_dictdict
Returnsstr
-
-
-

PSMReaderBase

-

PSMReaderBase is the base abstract class for all readers. It defines the basic procedures for importing other search engine results into AlphaBase format.

-

The main entry method is import_file(filename), and it will generate self._psm_df (or property self.psm_df) after import_file.

-

In import_file method, we designed five steps to load result files in to AlphaBase format:

-
    -
  1. origin_df = self._load_file(filename). We load result files into a dataframe without doing any file conversion. As different search engines have different file format, some of them are not in the tabular format. All subclass of PSMReaderBase need to re-implement this method.

  2. -
  3. self._translate_columns(origin_df). We translate columns in origin_df into AlphaBase columns by self.column_mapping. self.column_mapping provides a flexible way for developers to extract their required columns.

  4. -
  5. self._load_modifications(origin_df). As different search engines have different representation of modifications. We use this method to extract the modifications into self._psm_df['mods'] and self._psm_df['mod_sites']. Note that the modification names are still in other search engines’ format. All subclass of PSMReaderBase need to re-implement this method.

  6. -
  7. self._translate_modifications. Convert modification names into AlphaBase names (unimod_name@AA). For most of the search engines, we need a dict (self.modification_mapping) to map search engine modification format into AlphaBase (unimod_name@AA, unimod_name is in the unimod xml file). All subclass of PSMReaderBase need to re-implement this method.

  8. -
  9. self._post_process(filename, origin_df). Any required post-processing steps. For example, we remove unknown modifications here.

  10. -
-
-

Other results must be converted into the alphabase dataframe with required columns:

-
    -
  1. sequence (str): AA sequence, for example, ‘ATMYPEDR’.
  2. -
  3. mods (str): modification names, separated by ‘;’. For example, ‘Oxidation@M’, ‘Acetyl@Protein N-term;Oxidation@M’.
  4. -
  5. mod_sites (str): modification sites, seperated by ‘;’. For example, ‘3’, ‘0;3’. The N-term site is 0, and the C-term site is -1, and all other modification sites start from 1.
  6. -
  7. nAA (int): number of AA in the sequence, could be set by df['nAA']=df.sequence.str.len.
  8. -
  9. charge (int): precursor charge states.
  10. -
  11. rt (float): retention time (RT) of peptides, in minutes by default.
  12. -
  13. rt_norm (float): RT normalized by the maximum value, could be set by df['rt_norm'] = df.rt/df.rt.max. ### and optional columns:
  14. -
  15. ccs (float): collisional cross section (CCS) value, requred for IM data.
  16. -
  17. mobility (float): precursor ion mobility value, requred for IM data.
  18. -
  19. precursor_mz (float): precursor m/z value.
  20. -
  21. proteins (str): protein names, separated by ‘;’.
  22. -
  23. genes (str): gene names, separated by ‘;’.
  24. -
  25. protein_ids (str): protein ids or uniprot ids, separated by ‘;’.
  26. -
  27. score (float): PSM score. The larger the better PSMs, meaning that E-value or P-value scores must be -log.
  28. -
  29. fdr (float): FDR or q-value.
  30. -
  31. raw_name (str): Raw file name.
  32. -
  33. spec_idx (int): spectrum index starting from 0 in RAW data. For thermo RAW, it is also Scan number - 1. We can use it to locate the MS2 spectrum for identification.
  34. -
  35. query_id (int or str): the unique id for not only inlucdes unique spectrum (spec_idx), but also the precursor or MS1 isotope index. It could be query_idx in alphapept.
  36. -
  37. decoy: 0 if the peptide is target match, otherwise 1.
  38. -
-
/Users/zengwenfeng/opt/anaconda3/lib/python3.8/site-packages/fastcore/docscrape.py:225: UserWarning: Unknown section Attributes
-  else: warn(msg)
-
-

source

-
-
-

PSMReaderBase

-
-
 PSMReaderBase (column_mapping:dict=None, modification_mapping:dict=None,
-                fdr=0.01, keep_decoy=False, rt_unit:str='minute',
-                **kwargs)
-
-

The Base class for all PSMReaders. The key of the sub-classes for different search engine format is to re-define column_mapping and modification_mapping.

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
column_mappingdictNoneA dict that maps alphabase’s columns to other search engine’s.
The key of the column_mapping is alphabase’s column name, and
the value could be the column name or a list of column names
in other engine’s result.
If it is None, this dict will be init by
self._init_column_mapping. The dict values could be
either str or list, for exaplme:
columns_mapping = {
‘sequence’: ‘NakedSequence’, #str
‘charge’: ‘Charge’, #str
‘proteins’:[‘Proteins’,‘UniprotIDs’], # list, this reader will automatically detect all of them.
}
Defaults to None.
modification_mappingdictNoneA dict that maps alphabase’s modifications to other engine’s.
If it is None, this dict will be init by
self._init_modification_mapping. The dict values could be
either str or list, for exaplme:
modification_mapping = {
‘Oxidation@M’: ‘Oxidation (M)’, # str
‘Phospho@S’: [‘S(Phospho (STY))’,‘S(ph)’,‘pS’], # list, this reader will automatically detect all of them.
}
Defaults to None.
fdrfloat0.01FDR level to keep PSMs.
Defaults to 0.01.
keep_decoyboolFalseIf keep decoy PSMs in self.psm_df.
Defautls to False.
rt_unitstrminute
kwargs
-
-

source

-
-
-

PSMReaderBase.add_modification_mapping

-
-
 PSMReaderBase.add_modification_mapping (modification_mapping:dict)
-
-

modification_mapping example (MaxQuant):

-
{
-  'Acetyl@Protein N-term': [
-    '_(Acetyl (Protein N-term))',
-    '_(ac)',
-    '_(UniMod:1)',
-  ]
-  'Carbamidomethyl@C': [
-    'C(Carbamidomethyl (C))',
-    'C(UniMod:4)',
-  ]
-  'Oxidation@M': [
-    'M(Oxidation (M))',
-    'M(ox)',
-    'M(UniMod:35)',
-  ]
-  'Phospho@S': [
-    'S(Phospho (S))',
-    'S(Phospho (ST))',
-    'S(Phospho (STY))',
-    'S(ph)',
-    'S(UniMod:21)',
-    'pS',
-  ]
-  'Phospho@T': [
-    'T(Phospho (T))',
-    'T(Phospho (ST))',
-    'T(Phospho (STY))',
-    'T(ph)',
-    'T(UniMod:21)',
-    'pT',
-  ]
-  'Phospho@Y': [
-    'Y(Phospho (Y))',
-    'Y(Phospho (STY))',
-    'Y(ph)',
-    'Y(UniMod:21)',
-    'pY',
-  ]
-  'Deamidated@N': ['N(Deamidation (NQ))','N(de)']
-  'Deamidated@Q': ['Q(Deamidation (NQ))','Q(de)']
-  'GlyGly@K': ['K(GlyGly (K))', 'K(gl)']
-}
-
-

source

-
-
-

PSMReaderBase.set_modification_mapping

-
-
 PSMReaderBase.set_modification_mapping (modification_mapping:dict)
-
-
-

source

-
-
-

PSMReaderBase.import_file

-
-
 PSMReaderBase.import_file (_file:str)
-
-

This is the main entry function of PSM readers, it imports the file with following steps:

-
origin_df = self._load_file(_file)
-self._translate_columns(origin_df)
-self._translate_decoy(origin_df)
-self._translate_score(origin_df)
-self._load_modifications(origin_df)
-self._translate_modifications()
-self._post_process(origin_df)
-
-

source

-
-
-

PSMReaderBase.normalize_rt

-
-
 PSMReaderBase.normalize_rt ()
-
-
-

source

-
-
-

PSMReaderBase.normalize_rt_by_raw_name

-
-
 PSMReaderBase.normalize_rt_by_raw_name ()
-
-
-
-
-

PSMReaderProvider

-

To make it easier to create different readers, we design a Provider or Factory called PSMReaderProvider to manage all reader classes. PSMReaderProvider is instantiated as a global object psm_reader_provider.

-

After a subclass of PSMReaderBase is defined, for example AlphaPeptReader, we can then register it in to psm_reader_provider by using psm_reader_provider.register_reader('alphapept', AlphaPeptReader). Once we are going to use it, we just need to create a AlphaPeptReader object with psm_reader_provider.get_reader('alphapept').

-
-

source

-
-

PSMReaderProvider

-
-
 PSMReaderProvider ()
-
-

Initialize self. See help(type(self)) for accurate signature.

-

As we have loaded all readers in psm_reader_provider within alphabase.psm_reader.__init__.py, we can easily access all registered readers by psm_reader_provider.

- - -
-
- -
- -
- - - - \ No newline at end of file diff --git a/docs/psm_reader/psm_reader.rst b/docs/psm_reader/psm_reader.rst new file mode 100644 index 00000000..7bd58aa8 --- /dev/null +++ b/docs/psm_reader/psm_reader.rst @@ -0,0 +1,9 @@ +alphabase.psm_reader.psm_reader +=================================== + +See examples in :doc:`psm_reader notebook <../nbs/psm_readers>`. + +.. automodule:: alphabase.psm_reader.psm_reader + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/robots.txt b/docs/robots.txt deleted file mode 100644 index e1b7f79a..00000000 --- a/docs/robots.txt +++ /dev/null @@ -1 +0,0 @@ -Sitemap: https://MannLabs.github.io/alphabase/sitemap.xml diff --git a/docs/scoring/fdr.rst b/docs/scoring/fdr.rst new file mode 100644 index 00000000..b469b06d --- /dev/null +++ b/docs/scoring/fdr.rst @@ -0,0 +1,7 @@ +alphabase.scoring.fdr +=========================== + +.. automodule:: alphabase.scoring.fdr + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/scoring/feature_extraction_base.rst b/docs/scoring/feature_extraction_base.rst new file mode 100644 index 00000000..03e73049 --- /dev/null +++ b/docs/scoring/feature_extraction_base.rst @@ -0,0 +1,7 @@ +alphabase.scoring.feature_extraction_base +=========================================== + +.. automodule:: alphabase.scoring.feature_extraction_base + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/scoring/ml_scoring_base.rst b/docs/scoring/ml_scoring_base.rst new file mode 100644 index 00000000..0efd281d --- /dev/null +++ b/docs/scoring/ml_scoring_base.rst @@ -0,0 +1,7 @@ +alphabase.scoring.ml_scoring_base +=================================== + +.. automodule:: alphabase.scoring.ml_scoring_base + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/search.json b/docs/search.json deleted file mode 100644 index 26705de7..00000000 --- a/docs/search.json +++ /dev/null @@ -1,233 +0,0 @@ -[ - { - "objectID": "utils.html", - "href": "utils.html", - "title": "Utils", - "section": "", - "text": "source\n\nexplode_multiple_columns\n\n explode_multiple_columns (df:pandas.core.frame.DataFrame, columns:list)\n\n\nsource\n\n\nprocess_bar\n\n process_bar (iterator, len_iter)" - }, - { - "objectID": "psm_reader/msfragger_reader.html", - "href": "psm_reader/msfragger_reader.html", - "title": "MSFragger Reader", - "section": "", - "text": "source\n\nMSFragger_PSM_TSV_Reader\n\n MSFragger_PSM_TSV_Reader (column_mapping:dict=None,\n modification_mapping:dict=None, fdr=0.01,\n keep_decoy=False, rt_unit='second', **kwargs)\n\nThe Base class for all PSMReaders. The key of the sub-classes for different search engine format is to re-define column_mapping and modification_mapping.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ncolumn_mapping\ndict\nNone\nA dict that maps alphabase’s columns to other search engine’s.The key of the column_mapping is alphabase’s column name, and the value could be the column name or a list of column namesin other engine’s result.If it is None, this dict will be init by self._init_column_mapping. The dict values could be either str or list, for exaplme:columns_mapping = { ‘sequence’: ‘NakedSequence’, #str ‘charge’: ‘Charge’, #str ‘proteins’:[‘Proteins’,‘UniprotIDs’], # list, this reader will automatically detect all of them.}Defaults to None.\n\n\nmodification_mapping\ndict\nNone\nA dict that maps alphabase’s modifications to other engine’s.If it is None, this dict will be init by self._init_modification_mapping. The dict values could be either str or list, for exaplme:modification_mapping = { ‘Oxidation@M’: ‘Oxidation (M)’, # str ‘Phospho@S’: [‘S(Phospho (STY))’,‘S(ph)’,‘pS’], # list, this reader will automatically detect all of them.}Defaults to None.\n\n\nfdr\nfloat\n0.01\nFDR level to keep PSMs.Defaults to 0.01.\n\n\nkeep_decoy\nbool\nFalse\nIf keep decoy PSMs in self.psm_df.Defautls to False.\n\n\nrt_unit\nstr\nsecond\n\n\n\nkwargs" - }, - { - "objectID": "psm_reader/maxquant_reader.html", - "href": "psm_reader/maxquant_reader.html", - "title": "MaxQuant PSM reader", - "section": "", - "text": "source\n\nMaxQuantReader\n\n MaxQuantReader (column_mapping:dict=None, modification_mapping:dict=None,\n fdr=0.01, keep_decoy=False, mod_sep='()',\n underscore_for_ncterm=True, fixed_C57=True,\n mod_seq_columns=['Modified sequence'], **kwargs)\n\nReader for MaxQuant msms.txt and evidence.txt\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ncolumn_mapping\ndict\nNone\nBy default None. If None, use psm_reader_yaml['maxquant']['column_mapping'] (alphabase.psm_reader.psm_reader_yaml).\n\n\nmodification_mapping\ndict\nNone\nBy default None. If None, use psm_reader_yaml['maxquant']['modification_mapping'] (alphabase.psm_reader.psm_reader_yaml).\n\n\nfdr\nfloat\n0.01\nLoad PSMs with FDR < this fdr, by default 0.01\n\n\nkeep_decoy\nbool\nFalse\nIf keep decoy PSMs, by default False\n\n\nmod_sep\nstr\n()\nSymbols to separate modified sequences,e.g. AM(Oxidation)PIC(+57)QMK.By default ‘()’\n\n\nunderscore_for_ncterm\nbool\nTrue\nIf search engine uses an under score in N- and C-term, _(Acetyl)AM(Oxidation)PIC(+57)QMK_.by default True\n\n\nfixed_C57\nbool\nTrue\nIf true, the search engine will not show Carbamidomethylin the modified sequences. by default True\n\n\nmod_seq_columns\nlist\n[‘Modified sequence’]\nThe columns to find modified sequences, by default [‘Modified sequence’]\n\n\nkwargs\n\n\n\n\n\n\n\nsource\n\n\nparse_mod_seq\n\n parse_mod_seq (modseq:str, mod_sep:str='()', fixed_C57:bool=True,\n underscore_for_ncterm:bool=True)\n\nExtract modifications and sites from the modified sequence (modseq)\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nmodseq\nstr\n\nmodified sequence to extract modifications.\n\n\nmod_sep\nstr\n()\nseparator to indicate the modification section. Defaults to ‘()’\n\n\nfixed_C57\nbool\nTrue\n\n\n\nunderscore_for_ncterm\nbool\nTrue\nIf modseq starts and ends with underscores. Defaults to True.\n\n\nReturns\ntuple\n\nstr: modification names, separated by ‘;’str: modification sites, separated by ‘;’. 0 for N-term; -1 for C-term; 1 to N for normal modifications.\n\n\n\n\n\nColumn and modification mapping from alphabase to MaxQuant\n\npsm_reader_yaml['maxquant']['column_mapping']\n\n{'sequence': 'Sequence',\n 'charge': 'Charge',\n 'rt': 'Retention time',\n 'ccs': 'CCS',\n 'mobility': ['Mobility', 'IonMobility', 'K0', '1/K0'],\n 'scan_num': ['Scan number', 'MS/MS scan number', 'Scan index'],\n 'raw_name': 'Raw file',\n 'precursor_mz': 'm/z',\n 'score': 'Score',\n 'proteins': 'Proteins',\n 'genes': ['Gene Names', 'Gene names'],\n 'decoy': 'Reverse'}\n\n\n\npsm_reader_yaml['maxquant']['modification_mapping']\n\n{'Acetyl@Protein N-term': ['_(Acetyl (Protein N-term))',\n '_(ac)',\n '_(UniMod:1)'],\n 'Carbamidomethyl@C': ['C(Carbamidomethyl (C))', 'C(UniMod:4)'],\n 'Oxidation@M': ['M(Oxidation (M))', 'M(ox)', 'M(UniMod:35)'],\n 'Phospho@S': ['S(Phospho (S))',\n 'S(Phospho (ST))',\n 'S(Phospho (STY))',\n 'S(ph)',\n 'S(UniMod:21)',\n 'pS'],\n 'Phospho@T': ['T(Phospho (T))',\n 'T(Phospho (ST))',\n 'T(Phospho (STY))',\n 'T(ph)',\n 'T(UniMod:21)',\n 'pT'],\n 'Phospho@Y': ['Y(Phospho (Y))',\n 'Y(Phospho (STY))',\n 'Y(ph)',\n 'Y(UniMod:21)',\n 'pY'],\n 'Deamidated@N': ['N(Deamidation (NQ))', 'N(de)'],\n 'Deamidated@Q': ['Q(Deamidation (NQ))', 'Q(de)'],\n 'GlyGly@K': ['K(GlyGly (K))', 'K(gl)']}\n\n\n\n\nTesting\n\nimport io\nimport numpy as np\n\n\nmq_tsv = io.StringIO('''Raw file Scan number Scan index Sequence Length Missed cleavages Modifications Modified sequence Oxidation (M) Probabilities Oxidation (M) Score diffs Acetyl (Protein N-term) Oxidation (M) Proteins Charge Fragmentation Mass analyzer Type Scan event number Isotope index m/z Mass Mass error [ppm] Mass error [Da] Simple mass error [ppm] Retention time PEP Score Delta score Score diff Localization prob Combinatorics PIF Fraction of total spectrum Base peak fraction Precursor full scan number Precursor Intensity Precursor apex fraction Precursor apex offset Precursor apex offset time Matches Intensities Mass deviations [Da] Mass deviations [ppm] Masses Number of matches Intensity coverage Peak coverage Neutral loss level ETD identification type Reverse All scores All sequences All modified sequences Reporter PIF Reporter fraction id Protein group IDs Peptide ID Mod. peptide ID Evidence ID Oxidation (M) site IDs\n20190402_QX1_SeVW_MA_HeLa_500ng_LC11 81358 73979 AAAAAAAAAPAAAATAPTTAATTAATAAQ 29 0 Unmodified _(Acetyl (Protein N-term))AAAAAAAAM(Oxidation (M))PAAAATAPTTAATTAATAAQ_ 0 0 sp|P37108|SRP14_HUMAN 3 HCD FTMS MULTI-MSMS 13 1 790.07495 2367.203 0.35311 0.00027898 -0.061634807 70.261 0.012774 41.423 36.666 NaN NaN 1 0 0 0 81345 10653955 0.0338597821787898 -11 0.139877319335938 y1;y2;y3;y4;y11;y1-NH3;y2-NH3;a2;b2;b3;b4;b5;b6;b7;b8;b9;b11;b12;b6(2+);b8(2+);b13(2+);b18(2+) 2000000;2000000;300000;400000;200000;1000000;400000;300000;600000;1000000;2000000;3000000;3000000;3000000;3000000;2000000;600000;500000;1000000;2000000;300000;200000 5.2861228709844E-06;-6.86980268369553E-05;-0.00238178789771837;0.000624715964988809;-0.0145624692099773;-0.000143471782706683;-0.000609501446461991;-0.000524972720768346;0.00010190530804266;5.8620815195809E-05;0.000229901232955854;-0.000108750048696038;-0.000229593152369034;0.00183148682538103;0.00276641182404092;0.000193118923334623;0.00200988580445483;0.000102216846016745;5.86208151389656E-05;0.000229901232955854;-0.00104559184393338;0.00525030008475369 0.0359413365445091;-0.314964433555295;-8.23711898839045;1.60102421155213;-14.8975999917227;-1.10320467763838;-3.03102462870716;-4.56152475051625;0.712219104095465;0.273777366204575;0.806231096969562;-0.305312183824154;-0.537399178230218;3.67572664689217;4.85930954169285;0.301587577451224;2.48616190909398;0.116225745519871;0.273777365939099;0.806231096969562;-2.19774169175011;7.53961026980589 147.076413378177;218.113601150127;289.153028027798;390.197699998035;977.50437775671;130.050013034583;201.087592852046;115.087114392821;143.081402136892;214.118559209185;285.155501716567;356.192954155649;427.230188786552;498.265241494374;569.301420357176;640.341107437877;808.429168310795;879.468189767554;214.118559209185;285.155501716567;475.757386711244;696.362265007215 22 0.262893575628735 0.0826446280991736 None Unknown 41.4230894199432;4.75668724862449;3.9515580701967 AAAAAAAAAPAAAATAPTTAATTAATAAQ;FHRGPPDKDDMVSVTQILQGK;PVTLWITVTHMQADEVSVWR _AAAAAAAAAPAAAATAPTTAATTAATAAQ_;_FHRGPPDKDDMVSVTQILQGK_;_PVTLWITVTHMQADEVSVWR_ 0 1443 0 0 0 \n20190402_QX1_SeVW_MA_HeLa_500ng_LC11 81391 74010 AAAAAAAAAAPAAAATAPTTAATTAATAAQ 29 0 Unmodified _AAAAAAAAAPAAAATAPTTAATTAATAAQ_ 0 0 sp|P37108|SRP14_HUMAN 2 HCD FTMS MULTI-MSMS 14 0 1184.6088 2367.203 0.037108 4.3959E-05 1.7026696 70.287 7.1474E-09 118.21 100.52 NaN NaN 1 0 0 0 81377 9347701 0.166790347889974 -10 0.12664794921875 y1;y2;y3;y4;y5;y9;y12;y13;y14;y20;y13-H2O;y20-H2O;y1-NH3;y20-NH3;b3;b4;b5;b6;b7;b8;b9;b11;b12;b13;b14;b15;b16;b19;b15-H2O;b16-H2O 500000;600000;200000;400000;200000;100000;200000;1000000;200000;300000;200000;100000;100000;70000;300000;900000;2000000;3000000;5000000;8000000;6000000;600000;800000;600000;200000;300000;200000;300000;300000;1000000 -0.000194444760495571;0.000149986878682284;0.000774202587820128;-0.0002445094036716;0.000374520568641401;-0.00694293246522193;-0.0109837291331587;-0.0037745820627606;-0.000945546471939451;0.00152326440706929;0.00506054832726477;0.00996886361417637;6.25847393393997E-05;-0.024881067836759;-3.11821549132674E-05;-0.000183099230639527;0.000161332473453513;0.000265434980121881;0.000747070697229901;0.000975534518261156;0.00101513939785036;0.00651913000274362;0.0058584595163893;0.00579536744021425;0.00131097834105276;-0.0131378531671089;0.00472955218901916;-0.00161006322559842;-0.00201443239325272;0.0227149399370319 -1.32206444236914;0.687655553213019;2.6775131607882;-0.626628140021726;0.811995006209331;-8.6203492854282;-10.1838066275079;-3.21078702288986;-0.758483069159249;0.881072738747222;4.37168212373889;5.82682888353564;0.481236695337485;-14.5343986203644;-0.145630261806375;-0.642102166533079;0.452935954800214;0.621293379181583;1.49934012872483;1.71355878380837;1.58531240493271;8.06399202403175;6.6614096214532;6.09718023739784;1.28333378040908;-11.7030234519348;3.96235146626144;-1.07856912288932;-1.82370619437775;19.3220953109188 147.07661310906;218.113382465221;289.149872037312;390.198569223404;461.235063981231;805.411965958065;1078.54847749073;1175.59403219566;1246.62831694787;1728.87474561429;1157.57463237897;1710.85573532879;130.049806978061;1711.87460084504;214.118649012155;285.155914717031;356.192684073126;427.22969375842;498.266325910503;569.303211234482;640.340285417402;808.424659066597;879.462433524883;950.49961040476;1021.54120858166;1122.60333588727;1193.62258226971;1492.77704268533;1104.58164778019;1175.59403219566 30 0.474003002083763 0.167630057803468 None Unknown 118.209976573419;17.6937689289157;17.2534171481793 AAAAAAAAAPAAAATAPTTAATTAATAAQ;SELKQEAMQSEQLQSVLYLK;VGSSVPSKASELVVMGDHDAARR _AAAAAAAAAPAAAATAPTTAATTAATAAQ_;_SELKQEAM(Oxidation (M))QSEQLQSVLYLK_;_VGSSVPSKASELVVMGDHDAARR_ 1 1443 0 0 1 \n20190402_QX1_SeVW_MA_HeLa_500ng_LC11 107307 98306 AAAAAAAGDSDSWDADAFSVEDPVRK 26 1 Acetyl (Protein N-term) _(Acetyl (Protein N-term))AAAAAAAGDSDSWDADAFSVEDPVRK_ 1 0 sp|O75822|EIF3J_HUMAN 3 HCD FTMS MULTI-MSMS 10 2 879.06841 2634.1834 -0.93926 -0.00082567 -3.2012471 90.978 2.1945E-12 148.95 141.24 NaN NaN 1 0 0 0 107297 10193939 0.267970762043589 -8 0.10211181640625 y1;y2;y4;y5;y6;y7;y8;y9;y10;y11;y12;y13;y14;y15;y17;y18;y19;y20;y21;y23;y21-H2O;y1-NH3;y19-NH3;y14(2+);y16(2+);y22(2+);a2;b2;b3;b4;b5;b6;b7 300000;200000;3000000;600000;1000000;500000;2000000;1000000;1000000;1000000;90000;1000000;400000;900000;1000000;400000;3000000;2000000;1000000;400000;100000;200000;200000;80000;100000;200000;200000;2000000;5000000;5000000;5000000;2000000;300000 1.34859050149316E-07;-6.05140996867704E-06;2.27812602133781E-05;0.00128986659160546;-0.00934536073077652;0.000941953783126337;-0.00160424237344614;-0.00239257341399934;-0.00111053968612396;-0.00331340710044969;0.00330702864630439;0.000963683996815234;0.00596290290945944;-0.00662057038289277;-0.0117122701335575;0.00777853472800416;0.0021841542961738;0.000144322111736983;-0.00087403893667215;0.0197121595674616;-0.021204007680808;-0.000308954599830713;-0.026636719419912;-0.0137790992353075;0.00596067266928912;-0.0077053835773313;9.11402199221811E-06;-0.000142539300128419;-0.000251999832926231;1.90791054137662E-05;-0.00236430185879044;-9.54583337602344E-05;-0.000556959493223985 0.000916705048437201;-0.0199575598103408;0.0456231928690862;2.09952637717462;-12.5708704058425;1.11808305811426;-1.72590731777249;-2.22239181008062;-0.967696370445928;-2.62418809422166;2.47964286628144;0.665205752892023;3.64753748704453;-3.84510115530963;-6.08782672045773;3.81508105974837;1.04209904973991;0.0666012719936656;-0.390545453668809;8.28224925531311;-9.55133250134922;-2.37499239179248;-12.8127653858411;-16.846761946123;6.48662354975264;-6.67117082062383;0.0580151981289049;-0.770098855873447;-0.983876895688683;0.0583162347158579;-5.93738717724506;-0.203431522818505;-1.03087538746314 147.112804035741;303.21392125011;499.33507018564;614.360746132308;743.413974455831;842.472101057517;929.506675663573;1076.57587791081;1147.61170966489;1262.6408555643;1333.67134891635;1448.700635293;1634.77494902759;1721.81956091078;1923.88362405243;2038.89107627957;2095.9181343836;2166.95728800359;2237.99542015244;2380.04906152953;2220.00518543488;130.0865640237;2078.92040615582;817.907873297785;918.917619246831;1155.02717356753;157.097144992378;185.0922112678;256.129434516133;327.166277224995;398.205774393759;469.240619338034;540.278194626993 33 0.574496146107112 0.14410480349345 None Unknown 148.951235201399;7.71201258444522;7.36039532447559 AAAAAAAGDSDSWDADAFSVEDPVRK;PSRQESELMWQWVDQRSDGER;HTLTSFWNFKAGCEEKCYSNR _(Acetyl (Protein N-term))AAAAAAAGDSDSWDADAFSVEDPVRK_;_PSRQESELM(Oxidation (M))WQWVDQRSDGER_;_HTLTSFWNFKAGCEEKCYSNR_ 2 625 1 1 2 '''\n)\n\nmq_reader = psm_reader_provider.get_reader('maxquant')\nmq_reader.import_file(mq_tsv)\nassert len(mq_reader.psm_df) == 3\nassert mq_reader.psm_df.mods.values[1] == 'Acetyl@Protein N-term;Oxidation@M'\nassert mq_reader.psm_df.mod_sites.values[1] == '0;9'\nassert mq_reader.psm_df.mods.values[2] == ''\nassert mq_reader.psm_df.mod_sites.values[2] == ''\nassert np.all(np.array(mq_reader.modification_mapping['Phospho@S'])==np.array([\n 'S(Phospho (S))',\n 'S(Phospho (ST))',\n 'S(Phospho (STY))',\n 'S(ph)',\n 'S(UniMod:21)',\n 'pS',\n 'S[Phospho (S)]',\n 'S[Phospho (ST)]',\n 'S[Phospho (STY)]',\n 'S[ph]',\n 'S[UniMod:21]'])\n)\nmq_reader.psm_df\n\n\n\n\n\n \n \n \n sequence\n charge\n rt\n scan_num\n raw_name\n precursor_mz\n score\n proteins\n decoy\n spec_idx\n mods\n mod_sites\n nAA\n rt_norm\n \n \n \n \n 0\n AAAAAAAGDSDSWDADAFSVEDPVRK\n 3\n 90.978\n 107307\n 20190402_QX1_SeVW_MA_HeLa_500ng_LC11\n 879.06841\n 148.950\n sp|O75822|EIF3J_HUMAN\n 0\n 107306\n Acetyl@Protein N-term\n 0\n 26\n 1.000000\n \n \n 1\n AAAAAAAAAPAAAATAPTTAATTAATAAQ\n 3\n 70.261\n 81358\n 20190402_QX1_SeVW_MA_HeLa_500ng_LC11\n 790.07495\n 41.423\n sp|P37108|SRP14_HUMAN\n 0\n 81357\n Acetyl@Protein N-term;Oxidation@M\n 0;9\n 29\n 0.772286\n \n \n 2\n AAAAAAAAAAPAAAATAPTTAATTAATAAQ\n 2\n 70.287\n 81391\n 20190402_QX1_SeVW_MA_HeLa_500ng_LC11\n 1184.60880\n 118.210\n sp|P37108|SRP14_HUMAN\n 0\n 81390\n \n \n 30\n 0.772571" - }, - { - "objectID": "psm_reader/psm_reader.html", - "href": "psm_reader/psm_reader.html", - "title": "Base Class for PSM Readers", - "section": "", - "text": "source" - }, - { - "objectID": "psm_reader/psm_reader.html#psmreaderbase", - "href": "psm_reader/psm_reader.html#psmreaderbase", - "title": "Base Class for PSM Readers", - "section": "PSMReaderBase", - "text": "PSMReaderBase\nPSMReaderBase is the base abstract class for all readers. It defines the basic procedures for importing other search engine results into AlphaBase format.\nThe main entry method is import_file(filename), and it will generate self._psm_df (or property self.psm_df) after import_file.\nIn import_file method, we designed five steps to load result files in to AlphaBase format:\n\norigin_df = self._load_file(filename). We load result files into a dataframe without doing any file conversion. As different search engines have different file format, some of them are not in the tabular format. All subclass of PSMReaderBase need to re-implement this method.\nself._translate_columns(origin_df). We translate columns in origin_df into AlphaBase columns by self.column_mapping. self.column_mapping provides a flexible way for developers to extract their required columns.\nself._load_modifications(origin_df). As different search engines have different representation of modifications. We use this method to extract the modifications into self._psm_df['mods'] and self._psm_df['mod_sites']. Note that the modification names are still in other search engines’ format. All subclass of PSMReaderBase need to re-implement this method.\nself._translate_modifications. Convert modification names into AlphaBase names (unimod_name@AA). For most of the search engines, we need a dict (self.modification_mapping) to map search engine modification format into AlphaBase (unimod_name@AA, unimod_name is in the unimod xml file). All subclass of PSMReaderBase need to re-implement this method.\nself._post_process(filename, origin_df). Any required post-processing steps. For example, we remove unknown modifications here.\n\n\nOther results must be converted into the alphabase dataframe with required columns:\n\nsequence (str): AA sequence, for example, ‘ATMYPEDR’.\nmods (str): modification names, separated by ‘;’. For example, ‘Oxidation@M’, ‘Acetyl@Protein N-term;Oxidation@M’.\nmod_sites (str): modification sites, seperated by ‘;’. For example, ‘3’, ‘0;3’. The N-term site is 0, and the C-term site is -1, and all other modification sites start from 1.\nnAA (int): number of AA in the sequence, could be set by df['nAA']=df.sequence.str.len.\ncharge (int): precursor charge states.\nrt (float): retention time (RT) of peptides, in minutes by default.\nrt_norm (float): RT normalized by the maximum value, could be set by df['rt_norm'] = df.rt/df.rt.max. ### and optional columns:\nccs (float): collisional cross section (CCS) value, requred for IM data.\nmobility (float): precursor ion mobility value, requred for IM data.\nprecursor_mz (float): precursor m/z value.\nproteins (str): protein names, separated by ‘;’.\ngenes (str): gene names, separated by ‘;’.\nprotein_ids (str): protein ids or uniprot ids, separated by ‘;’.\nscore (float): PSM score. The larger the better PSMs, meaning that E-value or P-value scores must be -log.\nfdr (float): FDR or q-value.\nraw_name (str): Raw file name.\nspec_idx (int): spectrum index starting from 0 in RAW data. For thermo RAW, it is also Scan number - 1. We can use it to locate the MS2 spectrum for identification.\nquery_id (int or str): the unique id for not only inlucdes unique spectrum (spec_idx), but also the precursor or MS1 isotope index. It could be query_idx in alphapept.\ndecoy: 0 if the peptide is target match, otherwise 1.\n\n/Users/zengwenfeng/opt/anaconda3/lib/python3.8/site-packages/fastcore/docscrape.py:225: UserWarning: Unknown section Attributes\n else: warn(msg)\n\nsource\n\n\nPSMReaderBase\n\n PSMReaderBase (column_mapping:dict=None, modification_mapping:dict=None,\n fdr=0.01, keep_decoy=False, rt_unit:str='minute',\n **kwargs)\n\nThe Base class for all PSMReaders. The key of the sub-classes for different search engine format is to re-define column_mapping and modification_mapping.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ncolumn_mapping\ndict\nNone\nA dict that maps alphabase’s columns to other search engine’s.The key of the column_mapping is alphabase’s column name, and the value could be the column name or a list of column namesin other engine’s result.If it is None, this dict will be init by self._init_column_mapping. The dict values could be either str or list, for exaplme:columns_mapping = { ‘sequence’: ‘NakedSequence’, #str ‘charge’: ‘Charge’, #str ‘proteins’:[‘Proteins’,‘UniprotIDs’], # list, this reader will automatically detect all of them.}Defaults to None.\n\n\nmodification_mapping\ndict\nNone\nA dict that maps alphabase’s modifications to other engine’s.If it is None, this dict will be init by self._init_modification_mapping. The dict values could be either str or list, for exaplme:modification_mapping = { ‘Oxidation@M’: ‘Oxidation (M)’, # str ‘Phospho@S’: [‘S(Phospho (STY))’,‘S(ph)’,‘pS’], # list, this reader will automatically detect all of them.}Defaults to None.\n\n\nfdr\nfloat\n0.01\nFDR level to keep PSMs.Defaults to 0.01.\n\n\nkeep_decoy\nbool\nFalse\nIf keep decoy PSMs in self.psm_df.Defautls to False.\n\n\nrt_unit\nstr\nminute\n\n\n\nkwargs\n\n\n\n\n\n\n\nsource\n\n\nPSMReaderBase.add_modification_mapping\n\n PSMReaderBase.add_modification_mapping (modification_mapping:dict)\n\nmodification_mapping example (MaxQuant):\n{\n 'Acetyl@Protein N-term': [\n '_(Acetyl (Protein N-term))',\n '_(ac)',\n '_(UniMod:1)',\n ]\n 'Carbamidomethyl@C': [\n 'C(Carbamidomethyl (C))',\n 'C(UniMod:4)',\n ]\n 'Oxidation@M': [\n 'M(Oxidation (M))',\n 'M(ox)',\n 'M(UniMod:35)',\n ]\n 'Phospho@S': [\n 'S(Phospho (S))',\n 'S(Phospho (ST))',\n 'S(Phospho (STY))',\n 'S(ph)',\n 'S(UniMod:21)',\n 'pS',\n ]\n 'Phospho@T': [\n 'T(Phospho (T))',\n 'T(Phospho (ST))',\n 'T(Phospho (STY))',\n 'T(ph)',\n 'T(UniMod:21)',\n 'pT',\n ]\n 'Phospho@Y': [\n 'Y(Phospho (Y))',\n 'Y(Phospho (STY))',\n 'Y(ph)',\n 'Y(UniMod:21)',\n 'pY',\n ]\n 'Deamidated@N': ['N(Deamidation (NQ))','N(de)']\n 'Deamidated@Q': ['Q(Deamidation (NQ))','Q(de)']\n 'GlyGly@K': ['K(GlyGly (K))', 'K(gl)']\n}\n\nsource\n\n\nPSMReaderBase.set_modification_mapping\n\n PSMReaderBase.set_modification_mapping (modification_mapping:dict)\n\n\nsource\n\n\nPSMReaderBase.import_file\n\n PSMReaderBase.import_file (_file:str)\n\nThis is the main entry function of PSM readers, it imports the file with following steps:\norigin_df = self._load_file(_file)\nself._translate_columns(origin_df)\nself._translate_decoy(origin_df)\nself._translate_score(origin_df)\nself._load_modifications(origin_df)\nself._translate_modifications()\nself._post_process(origin_df)\n\nsource\n\n\nPSMReaderBase.normalize_rt\n\n PSMReaderBase.normalize_rt ()\n\n\nsource\n\n\nPSMReaderBase.normalize_rt_by_raw_name\n\n PSMReaderBase.normalize_rt_by_raw_name ()" - }, - { - "objectID": "psm_reader/alphapept_reader.html", - "href": "psm_reader/alphapept_reader.html", - "title": "AlphaPept PSM Reader", - "section": "", - "text": "source\n\nAlphaPeptReader\n\n AlphaPeptReader (column_mapping:dict=None,\n modification_mapping:dict=None, fdr=0.01,\n keep_decoy=False, **kwargs)\n\nReading PSMs from alphapept’s *.ms_data.hdf\n\nsource\n\n\nget_x_tandem_score\n\n get_x_tandem_score (df:pandas.core.frame.DataFrame)\n\n\nsource\n\n\nparse_ap\n\n parse_ap (precursor)\n\nParser to parse peptide strings\n\n\nColumn and modification mapping from alphabase to MaxQuant\n\npsm_reader_yaml['alphapept']['column_mapping']\n\n{'rt': 'rt',\n 'scan_num': 'scan_no',\n 'spec_idx': 'raw_idx',\n 'query_id': 'query_idx',\n 'mobility': 'mobility',\n 'score': 'score',\n 'precursor_mz': 'mz',\n 'charge': 'charge',\n 'raw_name': 'raw_name',\n 'fdr': 'q_value',\n 'decoy': 'decoy'}\n\n\n\npsm_reader_yaml['alphapept']['modification_mapping']\n\n{'Carbamidomethyl@C': 'cC',\n 'Oxidation@M': 'oxM',\n 'Phospho@S': 'pS',\n 'Phospho@T': 'pT',\n 'Phospho@Y': 'pY',\n 'Acetyl@Protein N-term': 'a'}\n\n\nThe modified sequence column is precursor column" - }, - { - "objectID": "psm_reader/pfind_reader.html", - "href": "psm_reader/pfind_reader.html", - "title": "pFind PSM Reader", - "section": "", - "text": "source\n\nparse_pfind_protein\n\n parse_pfind_protein (protein, keep_reverse=True)\n\n\nsource\n\n\nget_pFind_mods\n\n get_pFind_mods (pfind_mod_str)\n\n\nsource\n\n\ntranslate_pFind_mod\n\n translate_pFind_mod (mod_str)\n\n\nsource\n\n\nconvert_one_pFind_mod\n\n convert_one_pFind_mod (mod)\n\n/Users/zengwenfeng/opt/anaconda3/lib/python3.8/site-packages/fastcore/docscrape.py:225: UserWarning: Unknown section Attributes\n else: warn(msg)\n\nsource\n\n\npFindReader\n\n pFindReader (column_mapping:dict=None, modification_mapping:dict=None,\n fdr=0.01, keep_decoy=False, **kwargs)\n\nThe Base class for all PSMReaders. The key of the sub-classes for different search engine format is to re-define column_mapping and modification_mapping.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ncolumn_mapping\ndict\nNone\nA dict that maps alphabase’s columns to other search engine’s.The key of the column_mapping is alphabase’s column name, and the value could be the column name or a list of column namesin other engine’s result.If it is None, this dict will be init by self._init_column_mapping. The dict values could be either str or list, for exaplme:columns_mapping = { ‘sequence’: ‘NakedSequence’, #str ‘charge’: ‘Charge’, #str ‘proteins’:[‘Proteins’,‘UniprotIDs’], # list, this reader will automatically detect all of them.}Defaults to None.\n\n\nmodification_mapping\ndict\nNone\nA dict that maps alphabase’s modifications to other engine’s.If it is None, this dict will be init by self._init_modification_mapping. The dict values could be either str or list, for exaplme:modification_mapping = { ‘Oxidation@M’: ‘Oxidation (M)’, # str ‘Phospho@S’: [‘S(Phospho (STY))’,‘S(ph)’,‘pS’], # list, this reader will automatically detect all of them.}Defaults to None.\n\n\nfdr\nfloat\n0.01\nFDR level to keep PSMs.Defaults to 0.01.\n\n\nkeep_decoy\nbool\nFalse\nIf keep decoy PSMs in self.psm_df.Defautls to False.\n\n\nkwargs\n\n\n\n\n\n\n\n\nColumn and modification mapping from alphabase to pFind\n\npsm_reader_yaml['pfind']['column_mapping']\n\n{'sequence': 'Sequence',\n 'charge': 'Charge',\n 'rt': 'RT',\n 'raw_name': 'raw_name',\n 'query_id': 'File_Name',\n 'scan_num': 'Scan_No',\n 'score': 'Final_Score',\n 'proteins': 'Proteins',\n 'uniprot_ids': 'Proteins',\n 'fdr': 'Q-value',\n 'decoy': ['Target/Decoy', 'Targe/Decoy']}\n\n\nThere is no modification mapping as pFind also uses unimod name for all modifications, we just need to convert the sites (AAs) accordingly.\n\n\nTesting" - }, - { - "objectID": "psm_reader/dia_psm_reader.html", - "href": "psm_reader/dia_psm_reader.html", - "title": "DIA PSM reader", - "section": "", - "text": "DiannReader: DIA-NN PSM (.tsv)\nSpectronautReader: Spectronaut generated library (.tsv or .csv)\nSpectronautReportReader: Spectronaut result report (.tsv or .csv)\nSwathReader: Swath library (.tsv or .csv)\n\nAs we know so far, all DIA search engines have similar tabular files to MaxQaunt, so here, all DIAReaders are inherited from MaxQauntReader.\n\nsource\n\nSwathReader\n\n SwathReader (column_mapping:dict=None, modification_mapping:dict=None,\n fdr=0.01, keep_decoy=False, mod_sep='()',\n underscore_for_ncterm=False, fixed_C57=False,\n mod_seq_columns=['ModifiedPeptide', 'ModifiedSequence',\n 'FullUniModPeptideName', 'ModifiedPeptideSequence',\n 'LabeledSequence', 'FullUniModPeptideName'], csv_sep='\\t',\n **kwargs)\n\nReader for Spectronaut’s output library TSV/CSV.\nOther parameters, please see MaxQuantReader in alphabase.psm_reader.maxquant_reader\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ncolumn_mapping\ndict\nNone\n\n\n\nmodification_mapping\ndict\nNone\n\n\n\nfdr\nfloat\n0.01\n\n\n\nkeep_decoy\nbool\nFalse\n\n\n\nmod_sep\nstr\n()\n\n\n\nunderscore_for_ncterm\nbool\nFalse\n\n\n\nfixed_C57\nbool\nFalse\n\n\n\nmod_seq_columns\nlist\n[‘ModifiedPeptide’, ‘ModifiedSequence’, ‘FullUniModPeptideName’, ‘ModifiedPeptideSequence’, ‘LabeledSequence’, ‘FullUniModPeptideName’]\n\n\n\ncsv_sep\nstr\n\nDelimiter for TSV/CSV, by default ’ ’\n\n\nkwargs\n\n\n\n\n\n\n\nsource\n\n\nSpectronautReader\n\n SpectronautReader (column_mapping:dict=None,\n modification_mapping:dict=None, fdr=0.01,\n keep_decoy=False, mod_sep='[]',\n underscore_for_ncterm=True, fixed_C57=False,\n mod_seq_columns=['ModifiedPeptide',\n 'ModifiedSequence', 'FullUniModPeptideName',\n 'ModifiedPeptideSequence', 'LabeledSequence',\n 'FullUniModPeptideName'], csv_sep='\\t',\n rt_unit='minute', **kwargs)\n\nReader for Spectronaut’s output library TSV/CSV.\nOther parameters, please see MaxQuantReader in alphabase.psm_reader.maxquant_reader\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ncolumn_mapping\ndict\nNone\n\n\n\nmodification_mapping\ndict\nNone\n\n\n\nfdr\nfloat\n0.01\n\n\n\nkeep_decoy\nbool\nFalse\n\n\n\nmod_sep\nstr\n[]\n\n\n\nunderscore_for_ncterm\nbool\nTrue\n\n\n\nfixed_C57\nbool\nFalse\n\n\n\nmod_seq_columns\nlist\n[‘ModifiedPeptide’, ‘ModifiedSequence’, ‘FullUniModPeptideName’, ‘ModifiedPeptideSequence’, ‘LabeledSequence’, ‘FullUniModPeptideName’]\n\n\n\ncsv_sep\nstr\n\nDelimiter for TSV/CSV, by default ’ ’\n\n\nrt_unit\nstr\nminute\n\n\n\nkwargs\n\n\n\n\n\n\n\n\nColumn and modification mapping from alphabase to Spectronaut\n\npsm_reader_yaml['spectronaut']['column_mapping']\n\n{'raw_name': 'ReferenceRun',\n 'sequence': ['StrippedPeptide', 'PeptideSequence'],\n 'charge': 'PrecursorCharge',\n 'rt': ['RT',\n 'iRT',\n 'Tr_recalibrated',\n 'RetentionTime',\n 'NormalizedRetentionTime'],\n 'ccs': 'CCS',\n 'precursor_mz': 'PrecursorMz',\n 'mobility': ['Mobility', 'IonMobility', 'PrecursorIonMobility'],\n 'proteins': ['Protein Name', 'ProteinId', 'ProteinID', 'ProteinName'],\n 'uniprot_ids': ['UniProtIds', 'UniProtID', 'UniprotId'],\n 'genes': ['Genes', 'Gene', 'GeneName']}\n\n\nmodification_mapping is the same as MaxQuantReader\nAnd alphabase will look for columns containing modified sequence on:\n\npsm_reader_yaml['spectronaut']['mod_seq_columns']\n\n['ModifiedPeptide',\n 'ModifiedSequence',\n 'FullUniModPeptideName',\n 'ModifiedPeptideSequence',\n 'LabeledSequence',\n 'FullUniModPeptideName']\n\n\n\nsource\n\n\nDiannReader\n\n DiannReader (column_mapping:dict=None, modification_mapping:dict=None,\n fdr=0.01, keep_decoy=False, mod_sep='()',\n underscore_for_ncterm=False, fixed_C57=False, csv_sep='\\t',\n rt_unit='minute', **kwargs)\n\nReader for Spectronaut’s output library TSV/CSV.\nOther parameters, please see MaxQuantReader in alphabase.psm_reader.maxquant_reader\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ncolumn_mapping\ndict\nNone\n\n\n\nmodification_mapping\ndict\nNone\n\n\n\nfdr\nfloat\n0.01\n\n\n\nkeep_decoy\nbool\nFalse\n\n\n\nmod_sep\nstr\n()\n\n\n\nunderscore_for_ncterm\nbool\nFalse\n\n\n\nfixed_C57\nbool\nFalse\n\n\n\ncsv_sep\nstr\n\nDelimiter for TSV/CSV, by default ’ ’\n\n\nrt_unit\nstr\nminute\n\n\n\nkwargs\n\n\n\n\n\n\n\nsource\n\n\nSpectronautReportReader\n\n SpectronautReportReader (column_mapping:dict=None,\n modification_mapping:dict=None, fdr=0.01,\n keep_decoy=False, mod_sep='[]',\n underscore_for_ncterm=True, fixed_C57=False,\n csv_sep=',', rt_unit='minute', **kwargs)\n\nReader for Spectronaut’s report TSV/CSV.\nOther parameters, please see MaxQuantReader in alphabase.psm_reader.maxquant_reader\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ncolumn_mapping\ndict\nNone\n\n\n\nmodification_mapping\ndict\nNone\n\n\n\nfdr\nfloat\n0.01\n\n\n\nkeep_decoy\nbool\nFalse\n\n\n\nmod_sep\nstr\n[]\n\n\n\nunderscore_for_ncterm\nbool\nTrue\n\n\n\nfixed_C57\nbool\nFalse\n\n\n\ncsv_sep\nstr\n,\nDelimiter for TSV/CSV, by default ‘,’\n\n\nrt_unit\nstr\nminute\n\n\n\nkwargs\n\n\n\n\n\n\n\n\nColumn and modification mapping from alphabase to DiaNN\n\npsm_reader_yaml['diann']['column_mapping']\n\n{'raw_name': 'Run',\n 'sequence': 'Stripped.Sequence',\n 'charge': 'Precursor.Charge',\n 'rt': 'RT',\n 'ccs': 'CCS',\n 'mobility': ['IM', 'IonMobility'],\n 'proteins': 'Protein.Names',\n 'uniprot_ids': 'Protein.Ids',\n 'genes': 'Genes',\n 'scan_num': 'MS2.Scan',\n 'score': 'CScore'}\n\n\nThe modified sequence column in DiaNN is Modified.Sequence\n\n\nTesting\n\nfrom io import StringIO\n\n\ntsv = StringIO('''R.FileName,R.Replicate,EG.PrecursorId,EG.ApexRT,FG.CalibratedMassAccuracy (PPM),FG.CalibratedMz\n20211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_01,1,_VIETPENDFK_.2,40.826847076416,-0.6350307649846,596.298998773218\n20211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_01,1,_GFSNEVSSK_.2,19.1254806518555,-1.54873822486555,477.730400257423\n20211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_01,1,_HLLNQAVGEEEVPK_.3,42.0593299865723,-0.309173676987587,521.611288926824\n20211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_01,1,_DATM[Oxidation (M)]EVQR_.2,12.8398199081421,-3.31103772642203,483.222124398527\n''')\n\nspn_reader = psm_reader_provider.get_reader('spectronaut_report')\nspn_reader.import_file(tsv)\nassert len(spn_reader.psm_df) == 4\nassert (spn_reader.psm_df.mods=='Oxidation@M').sum()==1\nassert (spn_reader.psm_df.mod_sites=='4').sum()==1\nspn_reader.psm_df\n\n\n\n\n\n \n \n \n raw_name\n rt\n charge\n mods\n mod_sites\n sequence\n nAA\n rt_norm\n precursor_mz\n \n \n \n \n 0\n 20211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_01\n 12.839820\n 2\n Oxidation@M\n 4\n DATMEVQR\n 8\n 0.305279\n 483.221474\n \n \n 1\n 20211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_01\n 19.125481\n 2\n \n \n GFSNEVSSK\n 9\n 0.454726\n 477.729989\n \n \n 2\n 20211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_01\n 40.826847\n 2\n \n \n VIETPENDFK\n 10\n 0.970697\n 596.298236\n \n \n 3\n 20211203_EXPL2_SoSt_SA_DIA_HeLa_1000mz_noCB_01\n 42.059330\n 3\n \n \n HLLNQAVGEEEVPK\n 14\n 1.000000\n 521.610617\n \n \n\n\n\n\n\ntsv = StringIO('''ReferenceRun PrecursorCharge Workflow IntModifiedPeptide CV AllowForNormalization ModifiedPeptide StrippedPeptide iRT IonMobility iRTSourceSpecific BGSInferenceId IsProteotypic IntLabeledPeptide LabeledPeptide PrecursorMz ReferenceRunQvalue ReferenceRunMS1Response FragmentLossType FragmentNumber FragmentType FragmentCharge FragmentMz RelativeIntensity ExcludeFromAssay Database ProteinGroups UniProtIds Protein Name ProteinDescription Organisms OrganismId Genes Protein Existence Sequence Version FASTAName\n202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843 2 _ALVAT[+80]PGK_ True _ALVAT[Phospho (STY)]PGK_ ALVATPGK -5.032703 0.758 -5.032703 P19338 False _ALVAT[+80]PGK_ _ALVAT[Phospho (STY)]PGK_ 418.717511324722 0 10352 noloss 3 y 1 301.187031733932 53.1991 False sp P19338 P19338 NUCL_HUMAN Nucleolin Homo sapiens NCL 1 3 MCT_human_UP000005640_9606\n202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843 2 _ALVAT[+80]PGK_ True _ALVAT[Phospho (STY)]PGK_ ALVATPGK -5.032703 0.758 -5.032703 P19338 False _ALVAT[+80]PGK_ _ALVAT[Phospho (STY)]PGK_ 418.717511324722 0 10352 H3PO4 4 y 1 384.224142529733 26.31595 False sp P19338 P19338 NUCL_HUMAN Nucleolin Homo sapiens NCL 1 3 MCT_human_UP000005640_9606\n202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843 2 _TLT[+80]PCPLR_ True _TLT[Phospho (STY)]PC[Carbamidomethyl (C)]PLR_ TLTPCPLR 27.71659 0.818 27.71659 Q5T200 False _TLT[+80]PPLR_ _TLT[Phospho (STY)]PPLR_ 439.230785875227 0.000138389150379226 23117 noloss 3 b 1 396.153027901512 6.3264 False sp Q5T200 Q5T200 ZC3HD_HUMAN Zinc finger CCCH domain-containing protein 13 Homo sapiens ZC3H13 1 1 MCT_human_UP000005640_9606\n202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843 2 _TLT[+80]PCPLR_ True _TLT[Phospho (STY)]PC[Carbamidomethyl (C)]PLR_ TLTPCPLR 27.71659 0.818 27.71659 Q5T200 False _TLT[+80]PPLR_ _TLT[Phospho (STY)]PPLR_ 439.230785875227 0.000138389150379226 23117 noloss 3 y 1 385.255780000092 29.70625 False sp Q5T200 Q5T200 ZC3HD_HUMAN Zinc finger CCCH domain-containing protein 13 Homo sapiens ZC3H13 1 1 MCT_human_UP000005640_9606\n202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library25_S4-C1_1_25867 2 _LFVT[+80]PPEGSSR_ True _[Acetyl (Protein N-term)]LFVS[Phospho (STY)]PPEGSSR_ LFVSPPEGSSR 38.05031 0.917 38.05031 Q14244;Q14244-6;Q14244-7 False _LFVT[+80]PPEGSSR_ _LFVT[Phospho (STY)]PPEGSSR_ 635.297385373987 0 14164 H3PO4 4 b 1 443.265279065723 12.24525 False sp Q14244;Q14244-6;Q14244-7 Q14244;Q14244-6;Q14244-7 MAP7_HUMAN Ensconsin;Isoform of Q14244, Isoform 6 of Ensconsin;Isoform of Q14244, Isoform 7 of Ensconsin Homo sapiens MAP7 1;; 1;; MCT_human_UP000005640_9606;MCT_human2_UP000005640_9606_additional;MCT_human2_UP000005640_9606_additional\n202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library25_S4-C1_1_25867 2 _LFVT[+80]PPEGSSR_ True _[Acetyl (Protein N-term)]LFVS[Phospho (STY)]PPEGSSR_ LFVSPPEGSSR 38.05031 0.917 38.05031 Q14244;Q14244-6;Q14244-7 False _LFVT[+80]PPEGSSR_ _LFVT[Phospho (STY)]PPEGSSR_ 635.297385373987 0 14164 noloss 6 y 1 632.299829640042 46.07855 False sp Q14244;Q14244-6;Q14244-7 Q14244;Q14244-6;Q14244-7 MAP7_HUMAN Ensconsin;Isoform of Q14244, Isoform 6 of Ensconsin;Isoform of Q14244, Isoform 7 of Ensconsin Homo sapiens MAP7 1;; 1;; MCT_human_UP000005640_9606;MCT_human2_UP000005640_9606_additional;MCT_human2_UP000005640_9606_additional\n202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library25_S4-C1_1_25867 2 _LFVT[+80]PPEGSSR_ True _[Acetyl (Protein N-term)]LFVS[Phospho (STY)]PPEGSSR_ LFVSPPEGSSR 38.05031 0.917 38.05031 Q14244;Q14244-6;Q14244-7 False _LFVT[+80]PPEGSSR_ _LFVT[Phospho (STY)]PPEGSSR_ 635.297385373987 0 14164 noloss 7 y 1 729.352593488892 100 False sp Q14244;Q14244-6;Q14244-7 Q14244;Q14244-6;Q14244-7 MAP7_HUMAN Ensconsin;Isoform of Q14244, Isoform 6 of Ensconsin;Isoform of Q14244, Isoform 7 of Ensconsin Homo sapiens MAP7 1;; 1;; MCT_human_UP000005640_9606;MCT_human2_UP000005640_9606_additional;MCT_human2_UP000005640_9606_additional\n''')\n\nspn_reader = psm_reader_provider.get_reader('spectronaut')\nspn_reader.import_file(tsv)\nassert len(spn_reader.psm_df) == 3\nassert spn_reader.psm_df.mods.values[0] == 'Phospho@T'\nassert spn_reader.psm_df.mod_sites.values[0] == '5'\nassert spn_reader.psm_df.mods.values[1] == 'Phospho@T;Carbamidomethyl@C'\nassert spn_reader.psm_df.mod_sites.values[1] == '3;5'\nassert spn_reader.psm_df.mods.values[2] == 'Acetyl@Protein N-term;Phospho@S'\nassert spn_reader.psm_df.mod_sites.values[2] == '0;4'\nspn_reader.psm_df\n\n\n\n\n\n \n \n \n raw_name\n sequence\n charge\n rt\n precursor_mz\n mobility\n proteins\n uniprot_ids\n genes\n mods\n mod_sites\n nAA\n rt_norm\n ccs\n \n \n \n \n 0\n 202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph...\n ALVATPGK\n 2\n -5.032703\n 418.717511\n 0.758\n NUCL_HUMAN\n P19338\n NCL\n Phospho@T\n 5\n 8\n 0.0\n 308.612143\n \n \n 1\n 202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph...\n TLTPCPLR\n 2\n 27.716590\n 439.230786\n 0.818\n ZC3HD_HUMAN\n Q5T200\n ZC3H13\n Phospho@T;Carbamidomethyl@C\n 3;5\n 8\n 1.0\n 332.788837\n \n \n 2\n 202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph...\n LFVSPPEGSSR\n 2\n 38.050310\n 635.297385\n 0.917\n MAP7_HUMAN\n Q14244;Q14244-6;Q14244-7\n MAP7\n Acetyl@Protein N-term;Phospho@S\n 0;4\n 11\n 1.0\n 371.282739\n \n \n\n\n\n\n\ntsv = StringIO('''PrecursorMz ProductMz Tr_recalibrated transition_name CE LibraryIntensity transition_group_id decoy PeptideSequence ProteinName Annotation FullUniModPeptideName PrecursorCharge GroupLabel UniprotID FragmentType FragmentCharge FragmentSeriesNumber\n685.732240417 886.020494795 -10 255_AAAAAAAAAASGAAIPPLIPPRR_3 -1 5257.9 13_AAAAAAAAAASGAAIPPLIPPRR_3 0 AAAAAAAAAASGAAIPPLIPPRR 1/O14654 y19^2/0.002 AAAAAAAAAASGAAIPPLIPPRR 3 light 1/O14654 y 2 19\n514.550999438 473.303261576 59.2 268_AAAAAAAAAASGAAIPPLIPPRR_4 -1 10000.0 14_AAAAAAAAAASGAAIPPLIPPRR_4 0 AAAAAAAAAASGAAIPPLIPPRR 1/O14654 y8^2/0.002 AAAAAAAAAASGAAIPPLIPPRR 4 light 1/O14654 y 2 8\n514.550999438 629.39313922 59.2 276_AAAAAAAAAASGAAIPPLIPPRR_4 -1 5923.1 14_AAAAAAAAAASGAAIPPLIPPRR_4 0 AAAAAAAAAASGAAIPPLIPPRR 1/O14654 y12^2/0.001 AAAAAAAAAASGAAIPPLIPPRR 4 light 1/O14654 y 2 12\n514.550999438 672.909153425 59.2 279_AAAAAAAAAASGAAIPPLIPPRR_4 -1 5249.8 14_AAAAAAAAAASGAAIPPLIPPRR_4 0 AAAAAAAAAASGAAIPPLIPPRR 1/O14654 y13^2/0.001 AAAAAAAAAASGAAIPPLIPPRR 4 light 1/O14654 y 2 13\n514.550999438 356.19284545 59.2 262_AAAAAAAAAASGAAIPPLIPPRR_4 -1 5233.6 14_AAAAAAAAAASGAAIPPLIPPRR_4 0 AAAAAAAAAASGAAIPPLIPPRR 1/O14654 b5/0.001,b10^2/0.001,m6:10/0.001 AAAAAAAAAASGAAIPPLIPPRR 4 light 1/O14654 b 1 5\n514.550999438 498.26707303 59.2 269_AAAAAAAAAASGAAIPPLIPPRR_4 -1 4976.0 14_AAAAAAAAAASGAAIPPLIPPRR_4 0 AAAAAAAAAASGAAIPPLIPPRR 1/O14654 b7/0.001,m4:10/0.001 AAAAAAAAAASGAAIPPLIPPRR 4 light 1/O14654 b 1 7\n514.550999438 427.22995924 59.2 265_AAAAAAAAAASGAAIPPLIPPRR_4 -1 4859.4 14_AAAAAAAAAASGAAIPPLIPPRR_4 0 AAAAAAAAAASGAAIPPLIPPRR 1/O14654 b6/0.002,m5:10/0.002 AAAAAAAAAASGAAIPPLIPPRR 4 light 1/O14654 b 1 6\n728.201724416 356.19284545 101.8 292_AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR_5 -1 10000.0 15_AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR_5 0 AAAAAAAAAASGAAIPPLIPPRRVITLYQCFSVSQR 1/O14654 b5/0.003,b10^2/0.003,m6:10/0.003 AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR 5 light 1/O14654 b 1 5\n728.201724416 576.310000482 101.8 297_AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR_5 -1 7611.0 15_AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR_5 0 AAAAAAAAAASGAAIPPLIPPRRVITLYQCFSVSQR 1/O14654 y5/0.002 AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR 5 light 1/O14654 y 1 5\n728.201724416 427.22995924 101.8 293_AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR_5 -1 6805.1 15_AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR_5 0 AAAAAAAAAASGAAIPPLIPPRRVITLYQCFSVSQR 1/O14654 b6/-0.002,m5:10/-0.002 AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR 5 light 1/O14654 b 1 6\n728.201724416 569.30418682 101.8 296_AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR_5 -1 6312.7 15_AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR_5 0 AAAAAAAAAASGAAIPPLIPPRRVITLYQCFSVSQR 1/O14654 b8/0.009,m3:10/0.009 AAAAAAAAAASGAAIPPLIPPRRVITLYQC(UniMod:4)FSVSQR 5 light 1/O14654 b 1 8\n''')\n\n\nosw_reader = psm_reader_provider.get_reader('openswath')\npsm_df = osw_reader.import_file(tsv)\nassert psm_df.loc[2,'mod_sites'] == '30'\nassert psm_df.loc[2,'mods'] == 'Carbamidomethyl@C'\n\n\ntsv = StringIO('''File.Name Run Protein.Group Protein.Ids Protein.Names Genes PG.Quantity PG.Normalised PG.MaxLFQ Genes.Quantity Genes.Normalised Genes.MaxLFQ Genes.MaxLFQ.Unique Modified.Sequence Stripped.Sequence Precursor.Id Precursor.Charge Q.Value Global.Q.Value Protein.Q.Value PG.Q.Value Global.PG.Q.Value GG.Q.Value Translated.Q.Value Proteotypic Precursor.Quantity Precursor.Normalised Precursor.Translated Quantity.Quality RT RT.Start RT.Stop iRT Predicted.RT Predicted.iRT Lib.Q.Value Ms1.Profile.Corr Ms1.Area Evidence Spectrum.Similarity Mass.Evidence CScore Decoy.Evidence Decoy.CScore Fragment.Quant.Raw Fragment.Quant.Corrected Fragment.Correlations MS2.Scan IM iIM Predicted.IM Predicted.iIM\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636 Q9UH36 Q9UH36 SRRD 3296.49 3428.89 3428.89 3296.49 3428.89 3428.89 3428.89 (UniMod:1)AAAAAAALESWQAAAPR AAAAAAALESWQAAAPR (UniMod:1)AAAAAAALESWQAAAPR2 2 3.99074e-05 1.96448e-05 0.000159821 0.000159821 0.000146135 0.000161212 0 1 3296.49 3428.89 3296.49 0.852479 19.9208 19.8731 19.9685 123.9 19.8266 128.292 0 0.960106 5308.05 1.96902 0.683134 0.362287 0.999997 1.23691 3.43242e-05 1212.01;2178.03;1390.01;1020.01;714.008;778.008; 1212.01;1351.73;887.591;432.92;216.728;732.751; 0.956668;0.757581;0.670497;0.592489;0.47072;0.855203; 30053 1.19708 1.19328 1.19453 1.19469\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642 Q9UH36 Q9UH36 SRRD 2365 2334.05 2334.05 2365 2334.05 2334.05 2334.05 (UniMod:1)AAAAAAALESWQAAAPR AAAAAAALESWQAAAPR (UniMod:1)AAAAAAALESWQAAAPR2 2 0.000184434 1.96448e-05 0.000596659 0.000596659 0.000146135 0.000604961 0 1 2365 2334.05 2365 0.922581 19.905 19.8573 19.9527 123.9 19.782 128.535 0 0.940191 4594.04 1.31068 0.758988 0 0.995505 0.28633 2.12584e-06 1209.02;1210.02;1414.02;1051.01;236.003;130.002; 1209.02;1109.89;732.154;735.384;0;46.0967; 0.919244;0.937624;0.436748;0.639369;0.296736;0.647924; 30029 1.195 1.19328 1.19381 1.19339\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648 Q9UH36 Q9UH36 SRRD 1664.51 1635.46 1635.47 1664.51 1635.46 1635.47 1635.47 (UniMod:1)AAAAAAALESWQAAAPR AAAAAAALESWQAAAPR (UniMod:1)AAAAAAALESWQAAAPR2 2 0.000185123 1.96448e-05 0.000307409 0.000307409 0.000146135 0.000311332 0 1 1664.51 1635.46 1664.51 0.811147 19.8893 19.8416 19.937 123.9 19.7567 128.896 0 0.458773 6614.06 1.7503 0.491071 0.00111683 0.997286 1.92753 2.80543e-05 744.01;1708.02;1630.02;1475.02;0;533.006; 322.907;808.594;577.15;536.033;0;533.006; 0.760181;0.764072;0.542005;0.415779;0;0.913438; 30005 1.19409 1.19328 1.19323 1.19308\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654 Q9UH36 Q9UH36 SRRD 3369.91 3343.38 3343.38 3369.91 3343.38 3343.38 3343.38 (UniMod:1)AAAAAAALESWQAAAPR AAAAAAALESWQAAAPR (UniMod:1)AAAAAAALESWQAAAPR2 2 0.000153377 1.96448e-05 0.000298151 0.000298151 0.000146135 0.000302297 0 1 3369.91 3343.38 3369.91 0.798104 19.872 19.8243 19.9196 123.9 19.7347 128.576 0 0.892774 5026.05 1.01465 0.704953 0 0.996593 0.476378 7.76581e-06 1654.02;1286.02;1894.02;993.011;778.008;1190.01; 1638.42;1286.02;1293.97;466.705;292.465;445.475; 0.854908;0.860012;0.708773;0.584142;0.716032;0.410465; 29981 1.19136 1.19328 1.19169 1.1919\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636 P51608-2 P51608-2 MECP2 1585.53 1649.21 7673.34 1585.53 1649.21 7673.34 7673.34 AAAAAAAPSGGGGGGEEERLEEK AAAAAAAPSGGGGGGEEERLEEK (UniMod:1)AAAAAAAPSGGGGGGEEERLEEK3 3 0.00014185 5.69066e-05 0.000159821 0.000159821 0.000146135 0.000161212 0 1 861.509 896.11 861.509 0.530747 7.34894 7.30125 7.39665 14.6582 7.35635 14.5905 0 0.85024 2010.02 1.27844 0.470734 0.117495 0.998266 0.848349 0.0613877 905.008;1021.01;1179.01;419.003;753.005;638.006; 422.004;0;439.505;419.003;325.502;119.251; 0.626628;-0.441015;0.438684;0.800641;0.794403;0.458813; 11077 1.01 1.01225 1.01075 1.01099\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642 P51608-2 P51608-2 MECP2 16870.2 16649.4 7963.26 16870.2 16649.4 7963.26 7963.26 AAAAAAAPSGGGGGGEEERLEEK AAAAAAAPSGGGGGGEEERLEEK (UniMod:1)AAAAAAAPSGGGGGGEEERLEEK3 3 0.000200767 5.69066e-05 0.000152765 0.000152765 0.000146135 0.000154631 0 1 1832.12 1808.14 1832.12 0.438822 7.3176 7.26989 7.36527 14.6582 7.29706 14.8141 0 0.814702 3622.03 0.571375 0.278903 0.971334 0.994097 0.779006 0.0590956 1430.01;946.009;804.008;260.002;710.006;232.002; 886.115;946.009;0;0;431.102;0; -0.0551893;0.901557;0.0979035;-0.326533;0.334642;-0.120337; 11029 1.01417 1.01225 1.01136 1.01447\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648 P51608-2 P51608-2 MECP2 16242.7 15959.3 13129.8 16242.7 15959.3 13129.8 13129.8 AAAAAAAPSGGGGGGEEERLEEK AAAAAAAPSGGGGGGEEERLEEK (UniMod:1)AAAAAAAPSGGGGGGEEERLEEK3 3 6.98405e-05 5.69066e-05 0.000168492 0.000168492 0.000146135 0.000169578 0 1 2765.24 2716.99 2765.24 0.619188 7.28562 7.23794 7.33338 14.6582 7.22243 15.2233 0 0.859167 2180.02 1.50997 0.43755 0.191245 0.999939 0.420023 0.00548723 1807.01;1018.01;1230.01;554.005;1216.01;276.002; 954.327;1006.89;804.021;554.005;0;143.651; 0.483734;0.907585;0.418797;0.61368;-0.523993;0.70046; 10981 1.015 1.01225 1.01115 1.01558\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654 P51608-2 P51608-2 MECP2 20914.7 20750 16106 20914.7 20750 16106 16106 AAAAAAAPSGGGGGGEEERLEEK AAAAAAAPSGGGGGGEEERLEEK (UniMod:1)AAAAAAAPSGGGGGGEEERLEEK3 3 0.000603914 5.69066e-05 0.000153516 0.000153516 0.000146135 0.000155304 0 1 4556.58 4520.72 4556.58 0.620251 7.26825 7.22055 7.31601 14.6582 7.18207 15.448 0 0.79218 3193.03 0.113147 0.344593 0.144439 0.971834 1.05178 0.112962 2855.02;1760.01;830.007;116.001;564.005;751.006; 2266.46;1760.01;530.111;0;0;317.258; 0.430169;0.867218;0.612985;-0.310664;-0.386197;0.286451; 10957 1.01208 1.01225 1.00965 1.01449\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636 Q96P70 Q96P70 IPO9 155722 161976 160062 155722 161976 160062 160062 (UniMod:1)AAAAAAGAASGLPGPVAQGLK AAAAAAGAASGLPGPVAQGLK (UniMod:1)AAAAAAGAASGLPGPVAQGLK2 2 3.99074e-05 1.96448e-05 0.000159821 0.000159821 0.000146135 0.000161212 0 1 44791.6 46590.6 44791.6 0.903543 14.709 14.6614 14.7567 77.7384 14.7374 77.4968 0 0.962703 395646 1.16168 0.790083 0 0.999999 0.491003 0.00391533 17738.2;18223.2;16218.2;17747.2;14484.2;12569.2; 17738.2;18223.2;16150;16115.2;14484.2;12569.2; 0.879361;0.89314;0.807683;0.73629;0.863152;0.984215; 22187 1.225 1.23344 1.23458 1.22263\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642 Q96P70 Q96P70 IPO9 172360 170104 155889 172360 170104 155889 155889 (UniMod:1)AAAAAAGAASGLPGPVAQGLK AAAAAAGAASGLPGPVAQGLK (UniMod:1)AAAAAAGAASGLPGPVAQGLK2 2 4.98766e-05 1.96448e-05 0.000152765 0.000152765 0.000146135 0.000154631 0 1 44700.5 44115.4 44700.5 0.615196 14.6456 14.5979 14.6933 77.7384 14.6419 77.8394 0 0.9107 553292 0.747052 0.814842 0 0.999996 0.830219 0.0331339 19349.2;20154.2;20586.2;20040.3;13620.2;12105.1; 19349.2;19014.1;19329.7;18862.6;13404.2;11947.1; 0.862894;0.42962;0.293099;0.655948;0.517625;0.323501; 22091 1.22042 1.23344 1.23392 1.21891\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648 Q96P70 Q96P70 IPO9 153712 151030 152845 153712 151030 152845 152845 (UniMod:1)AAAAAAGAASGLPGPVAQGLK AAAAAAGAASGLPGPVAQGLK (UniMod:1)AAAAAAGAASGLPGPVAQGLK2 2 6.08421e-05 1.96448e-05 0.000168492 0.000168492 0.000146135 0.000169578 0 1 40439.4 39733.8 40439.4 0.833327 14.6301 14.5824 14.6777 77.7384 14.5747 78.2527 0 0.989019 1.0768e+06 1.68843 0.759575 0 0.999999 0.674737 0.0631384 17597.2;19526.2;16647.2;16204.2;12871.2;11069.2; 17377.7;19526.2;16647.2;16204.2;12871.2;10190.5; 0.828262;0.979726;0.827511;0.9628;0.90466;0.751867; 22067 1.22708 1.23344 1.23332 1.2261\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654 Q96P70 Q96P70 IPO9 147008 145850 159209 147008 145850 159209 159209 (UniMod:1)AAAAAAGAASGLPGPVAQGLK AAAAAAGAASGLPGPVAQGLK (UniMod:1)AAAAAAGAASGLPGPVAQGLK2 2 4.42595e-05 1.96448e-05 0.000153516 0.000153516 0.000146135 0.000155304 0 1 41861.6 41532.1 41861.6 0.752921 14.549 14.5013 14.5967 77.7384 14.5155 78.0748 0 0.877873 939172 1.59762 0.821027 0 0.999997 0.397952 1.22212e-05 18143.2;19574.2;17444.2;17956.2;11427.2;13025.2; 17409.2;18432.7;16706.7;10820.4;11427.2;13025.2; 0.625292;0.399297;0.717726;0.321047;0.864595;0.825535; 21947 1.2275 1.23344 1.23199 1.2281\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636 P28482 P28482 MAPK1 72652.7 75570.7 78604.9 72652.7 75570.7 78604.9 78604.9 (UniMod:1)AAAAAAGAGPEM(UniMod:35)VR AAAAAAGAGPEMVR (UniMod:1)AAAAAAGAGPEM(UniMod:35)VR2 2 0.00693727 0.000834654 0.000159821 0.000159821 0.000146135 0.000161212 0 1 192.198 199.917 192.198 0.0197094 7.4249 7.37721 7.4726 15.9025 7.49813 15.2482 0 0.754191 8842.06 1.19725 0.470393 0.086229 0.843331 2.80548 0.384248 897.008;1032.01;279.002;377.003;440.004;286.003; 0;137.786;54.4117;0;89.692;286.003; -0.20379;-0.0679789;0.241761;-0.388501;-0.0459688;0.973644; 11191 1.01917 1.0262 1.02479 1.02031\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642 P28482 P28482 MAPK1 69911.3 68996.2 63388.2 69911.3 68996.2 63388.2 63388.2 (UniMod:1)AAAAAAGAGPEM(UniMod:35)VR AAAAAAGAGPEMVR (UniMod:1)AAAAAAGAGPEM(UniMod:35)VR2 2 0.00122498 0.000834654 0.000152765 0.000152765 0.000146135 0.000154631 0 1 1572.67 1552.08 1572.67 0.906427 7.45711 7.40943 7.50482 15.9025 7.43922 16.0749 0 0.371998 5937.05 0.30888 0.510876 0.72688 0.95182 1.96259 0.65474 1320.01;838.009;638.006;827.009;562.005;339.003; 1320.01;252.656;0;213.073;330.325;0; 0.976001;0.542934;0.346963;0.38014;0.442774;-0.259898; 11239 1.01773 1.0262 1.02509 1.01834\n''')\ndiann_reader = psm_reader_provider.get_reader('diann')\n_df = diann_reader.import_file(tsv)\nassert 'ccs' in diann_reader.psm_df.columns\nassert len(diann_reader.psm_df) == 14\nassert np.sum(diann_reader.psm_df.mods.str.contains('Acetyl@Protein N-term')) == 10\nassert np.sum(~diann_reader.psm_df.mods.str.contains('Acetyl@Protein N-term')) == 4\nassert np.sum(diann_reader.psm_df.mods.str.contains('Oxidation@M')) == 2\nassert np.all(np.array(diann_reader.modification_mapping['Phospho@S'])==np.array([\n 'S(Phospho (S))',\n 'S(Phospho (ST))',\n 'S(Phospho (STY))',\n 'S(ph)',\n 'S(UniMod:21)',\n 'pS',\n 'S[Phospho (S)]',\n 'S[Phospho (ST)]',\n 'S[Phospho (STY)]',\n 'S[ph]',\n 'S[UniMod:21]'])\n)\n_df\n\n\n\n\n\n \n \n \n raw_name\n sequence\n charge\n rt\n mobility\n proteins\n uniprot_ids\n genes\n scan_num\n score\n spec_idx\n mods\n mod_sites\n nAA\n rt_norm\n precursor_mz\n ccs\n \n \n \n \n 0\n 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...\n AAAAAAGAGPEMVR\n 2\n 7.42490\n 1.01917\n NaN\n P28482\n MAPK1\n 11191\n 0.843331\n 11190\n Acetyl@Protein N-term;Oxidation@M\n 0;12\n 14\n 0.372721\n 650.819344\n 412.544080\n \n \n 1\n 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...\n AAAAAAGAGPEMVR\n 2\n 7.45711\n 1.01773\n NaN\n P28482\n MAPK1\n 11239\n 0.951820\n 11238\n Acetyl@Protein N-term;Oxidation@M\n 0;12\n 14\n 0.374635\n 650.819344\n 411.961191\n \n \n 2\n 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...\n AAAAAAALESWQAAAPR\n 2\n 19.92080\n 1.19708\n NaN\n Q9UH36\n SRRD\n 30053\n 0.999997\n 30052\n Acetyl@Protein N-term\n 0\n 17\n 1.000000\n 834.428635\n 483.435307\n \n \n 3\n 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...\n AAAAAAALESWQAAAPR\n 2\n 19.90500\n 1.19500\n NaN\n Q9UH36\n SRRD\n 30029\n 0.995505\n 30028\n Acetyl@Protein N-term\n 0\n 17\n 1.000000\n 834.428635\n 482.595308\n \n \n 4\n 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...\n AAAAAAALESWQAAAPR\n 2\n 19.88930\n 1.19409\n NaN\n Q9UH36\n SRRD\n 30005\n 0.997286\n 30004\n Acetyl@Protein N-term\n 0\n 17\n 1.000000\n 834.428635\n 482.227809\n \n \n 5\n 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...\n AAAAAAALESWQAAAPR\n 2\n 19.87200\n 1.19136\n NaN\n Q9UH36\n SRRD\n 29981\n 0.996593\n 29980\n Acetyl@Protein N-term\n 0\n 17\n 1.000000\n 834.428635\n 481.125311\n \n \n 6\n 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...\n AAAAAAGAASGLPGPVAQGLK\n 2\n 14.70900\n 1.22500\n NaN\n Q96P70\n IPO9\n 22187\n 0.999999\n 22186\n Acetyl@Protein N-term\n 0\n 21\n 0.738374\n 895.991600\n 494.430146\n \n \n 7\n 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...\n AAAAAAGAASGLPGPVAQGLK\n 2\n 14.64560\n 1.22042\n NaN\n Q96P70\n IPO9\n 22091\n 0.999996\n 22090\n Acetyl@Protein N-term\n 0\n 21\n 0.735775\n 895.991600\n 492.581583\n \n \n 8\n 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...\n AAAAAAGAASGLPGPVAQGLK\n 2\n 14.63010\n 1.22708\n NaN\n Q96P70\n IPO9\n 22067\n 0.999999\n 22066\n Acetyl@Protein N-term\n 0\n 21\n 0.735576\n 895.991600\n 495.269668\n \n \n 9\n 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...\n AAAAAAGAASGLPGPVAQGLK\n 2\n 14.54900\n 1.22750\n NaN\n Q96P70\n IPO9\n 21947\n 0.999997\n 21946\n Acetyl@Protein N-term\n 0\n 21\n 0.732136\n 895.991600\n 495.439187\n \n \n 10\n 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...\n AAAAAAAPSGGGGGGEEERLEEK\n 3\n 7.34894\n 1.01000\n NaN\n P51608-2\n MECP2\n 11077\n 0.998266\n 11076\n \n \n 23\n 0.368908\n 695.666290\n 610.813640\n \n \n 11\n 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...\n AAAAAAAPSGGGGGGEEERLEEK\n 3\n 7.31760\n 1.01417\n NaN\n P51608-2\n MECP2\n 11029\n 0.994097\n 11028\n \n \n 23\n 0.367626\n 695.666290\n 613.335514\n \n \n 12\n 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...\n AAAAAAAPSGGGGGGEEERLEEK\n 3\n 7.28562\n 1.01500\n NaN\n P51608-2\n MECP2\n 10981\n 0.999939\n 10980\n \n \n 23\n 0.366309\n 695.666290\n 613.837470\n \n \n 13\n 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_sp...\n AAAAAAAPSGGGGGGEEERLEEK\n 3\n 7.26825\n 1.01208\n NaN\n P51608-2\n MECP2\n 10957\n 0.971834\n 10956\n \n \n 23\n 0.365753\n 695.666290\n 612.071553\n \n \n\n\n\n\n\ntsv = StringIO('''File.Name Run Protein.Group Protein.Ids Protein.Names Genes PG.Quantity PG.Normalised PG.MaxLFQ Genes.Quantity Genes.Normalised Genes.MaxLFQ Genes.MaxLFQ.Unique Modified.Sequence Stripped.Sequence Precursor.Id Precursor.Charge Q.Value Global.Q.Value Protein.Q.Value PG.Q.Value Global.PG.Q.Value GG.Q.Value Translated.Q.Value Proteotypic Precursor.Quantity Precursor.Normalised Precursor.Translated Quantity.Quality RT RT.Start RT.Stop iRT Predicted.RT Predicted.iRT Lib.Q.Value Ms1.Profile.Corr Ms1.Area Evidence Spectrum.Similarity Mass.Evidence CScore Decoy.Evidence Decoy.CScore Fragment.Quant.Raw Fragment.Quant.Corrected Fragment.Correlations MS2.Scan IM iIM Predicted.IM Predicted.iIM\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636 Q9UH36 Q9UH36 SRRD 3296.49 3428.89 3428.89 3296.49 3428.89 3428.89 3428.89 (UniMod:1)AAAAAAALESWQAAAPR AAAAAAALESWQAAAPR (UniMod:1)AAAAAAALESWQAAAPR2 2 3.99074e-05 1.96448e-05 0.000159821 0.000159821 0.000146135 0.000161212 0 1 3296.49 3428.89 3296.49 0.852479 19.9208 19.8731 19.9685 123.9 19.8266 128.292 0 0.960106 5308.05 1.96902 0.683134 0.362287 0.999997 1.23691 3.43242e-05 1212.01;2178.03;1390.01;1020.01;714.008;778.008; 1212.01;1351.73;887.591;432.92;216.728;732.751; 0.956668;0.757581;0.670497;0.592489;0.47072;0.855203; 30053 1.19708 1.19328 1.19453 1.19469\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642 Q9UH36 Q9UH36 SRRD 2365 2334.05 2334.05 2365 2334.05 2334.05 2334.05 (UniMod:1)AAAAAAALESWQAAAPR AAAAAAALESWQAAAPR (UniMod:1)AAAAAAALESWQAAAPR2 2 0.000184434 1.96448e-05 0.000596659 0.000596659 0.000146135 0.000604961 0 1 2365 2334.05 2365 0.922581 19.905 19.8573 19.9527 123.9 19.782 128.535 0 0.940191 4594.04 1.31068 0.758988 0 0.995505 0.28633 2.12584e-06 1209.02;1210.02;1414.02;1051.01;236.003;130.002; 1209.02;1109.89;732.154;735.384;0;46.0967; 0.919244;0.937624;0.436748;0.639369;0.296736;0.647924; 30029 1.195 1.19328 1.19381 1.19339\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648 Q9UH36 Q9UH36 SRRD 1664.51 1635.46 1635.47 1664.51 1635.46 1635.47 1635.47 (UniMod:1)AAAAAAALESWQAAAPR AAAAAAALESWQAAAPR (UniMod:1)AAAAAAALESWQAAAPR2 2 0.000185123 1.96448e-05 0.000307409 0.000307409 0.000146135 0.000311332 0 1 1664.51 1635.46 1664.51 0.811147 19.8893 19.8416 19.937 123.9 19.7567 128.896 0 0.458773 6614.06 1.7503 0.491071 0.00111683 0.997286 1.92753 2.80543e-05 744.01;1708.02;1630.02;1475.02;0;533.006; 322.907;808.594;577.15;536.033;0;533.006; 0.760181;0.764072;0.542005;0.415779;0;0.913438; 30005 1.19409 1.19328 1.19323 1.19308\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654 Q9UH36 Q9UH36 SRRD 3369.91 3343.38 3343.38 3369.91 3343.38 3343.38 3343.38 (UniMod:1)AAAAAAALESWQAAAPR AAAAAAALESWQAAAPR (UniMod:1)AAAAAAALESWQAAAPR2 2 0.000153377 1.96448e-05 0.000298151 0.000298151 0.000146135 0.000302297 0 1 3369.91 3343.38 3369.91 0.798104 19.872 19.8243 19.9196 123.9 19.7347 128.576 0 0.892774 5026.05 1.01465 0.704953 0 0.996593 0.476378 7.76581e-06 1654.02;1286.02;1894.02;993.011;778.008;1190.01; 1638.42;1286.02;1293.97;466.705;292.465;445.475; 0.854908;0.860012;0.708773;0.584142;0.716032;0.410465; 29981 1.19136 1.19328 1.19169 1.1919\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636 P51608-2 P51608-2 MECP2 1585.53 1649.21 7673.34 1585.53 1649.21 7673.34 7673.34 AAAAAAAPSGGGGGGEEERLEEK AAAAAAAPSGGGGGGEEERLEEK (UniMod:1)AAAAAAAPSGGGGGGEEERLEEK3 3 0.00014185 5.69066e-05 0.000159821 0.000159821 0.000146135 0.000161212 0 1 861.509 896.11 861.509 0.530747 7.34894 7.30125 7.39665 14.6582 7.35635 14.5905 0 0.85024 2010.02 1.27844 0.470734 0.117495 0.998266 0.848349 0.0613877 905.008;1021.01;1179.01;419.003;753.005;638.006; 422.004;0;439.505;419.003;325.502;119.251; 0.626628;-0.441015;0.438684;0.800641;0.794403;0.458813; 11077 1.01 1.01225 1.01075 1.01099\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642 P51608-2 P51608-2 MECP2 16870.2 16649.4 7963.26 16870.2 16649.4 7963.26 7963.26 AAAAAAAPSGGGGGGEEERLEEK AAAAAAAPSGGGGGGEEERLEEK (UniMod:1)AAAAAAAPSGGGGGGEEERLEEK3 3 0.000200767 5.69066e-05 0.000152765 0.000152765 0.000146135 0.000154631 0 1 1832.12 1808.14 1832.12 0.438822 7.3176 7.26989 7.36527 14.6582 7.29706 14.8141 0 0.814702 3622.03 0.571375 0.278903 0.971334 0.994097 0.779006 0.0590956 1430.01;946.009;804.008;260.002;710.006;232.002; 886.115;946.009;0;0;431.102;0; -0.0551893;0.901557;0.0979035;-0.326533;0.334642;-0.120337; 11029 1.01417 1.01225 1.01136 1.01447\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648 P51608-2 P51608-2 MECP2 16242.7 15959.3 13129.8 16242.7 15959.3 13129.8 13129.8 AAAAAAAPSGGGGGGEEERLEEK AAAAAAAPSGGGGGGEEERLEEK (UniMod:1)AAAAAAAPSGGGGGGEEERLEEK3 3 6.98405e-05 5.69066e-05 0.000168492 0.000168492 0.000146135 0.000169578 0 1 2765.24 2716.99 2765.24 0.619188 7.28562 7.23794 7.33338 14.6582 7.22243 15.2233 0 0.859167 2180.02 1.50997 0.43755 0.191245 0.999939 0.420023 0.00548723 1807.01;1018.01;1230.01;554.005;1216.01;276.002; 954.327;1006.89;804.021;554.005;0;143.651; 0.483734;0.907585;0.418797;0.61368;-0.523993;0.70046; 10981 1.015 1.01225 1.01115 1.01558\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654 P51608-2 P51608-2 MECP2 20914.7 20750 16106 20914.7 20750 16106 16106 AAAAAAAPSGGGGGGEEERLEEK AAAAAAAPSGGGGGGEEERLEEK (UniMod:1)AAAAAAAPSGGGGGGEEERLEEK3 3 0.000603914 5.69066e-05 0.000153516 0.000153516 0.000146135 0.000155304 0 1 4556.58 4520.72 4556.58 0.620251 7.26825 7.22055 7.31601 14.6582 7.18207 15.448 0 0.79218 3193.03 0.113147 0.344593 0.144439 0.971834 1.05178 0.112962 2855.02;1760.01;830.007;116.001;564.005;751.006; 2266.46;1760.01;530.111;0;0;317.258; 0.430169;0.867218;0.612985;-0.310664;-0.386197;0.286451; 10957 1.01208 1.01225 1.00965 1.01449\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636 Q96P70 Q96P70 IPO9 155722 161976 160062 155722 161976 160062 160062 (UniMod:1)AAAAAAGAASGLPGPVAQGLK AAAAAAGAASGLPGPVAQGLK (UniMod:1)AAAAAAGAASGLPGPVAQGLK2 2 3.99074e-05 1.96448e-05 0.000159821 0.000159821 0.000146135 0.000161212 0 1 44791.6 46590.6 44791.6 0.903543 14.709 14.6614 14.7567 77.7384 14.7374 77.4968 0 0.962703 395646 1.16168 0.790083 0 0.999999 0.491003 0.00391533 17738.2;18223.2;16218.2;17747.2;14484.2;12569.2; 17738.2;18223.2;16150;16115.2;14484.2;12569.2; 0.879361;0.89314;0.807683;0.73629;0.863152;0.984215; 22187 1.225 1.23344 1.23458 1.22263\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642 Q96P70 Q96P70 IPO9 172360 170104 155889 172360 170104 155889 155889 (UniMod:1)AAAAAAGAASGLPGPVAQGLK AAAAAAGAASGLPGPVAQGLK (UniMod:1)AAAAAAGAASGLPGPVAQGLK2 2 4.98766e-05 1.96448e-05 0.000152765 0.000152765 0.000146135 0.000154631 0 1 44700.5 44115.4 44700.5 0.615196 14.6456 14.5979 14.6933 77.7384 14.6419 77.8394 0 0.9107 553292 0.747052 0.814842 0 0.999996 0.830219 0.0331339 19349.2;20154.2;20586.2;20040.3;13620.2;12105.1; 19349.2;19014.1;19329.7;18862.6;13404.2;11947.1; 0.862894;0.42962;0.293099;0.655948;0.517625;0.323501; 22091 1.22042 1.23344 1.23392 1.21891\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B2_1_22648 Q96P70 Q96P70 IPO9 153712 151030 152845 153712 151030 152845 152845 (UniMod:1)AAAAAAGAASGLPGPVAQGLK AAAAAAGAASGLPGPVAQGLK (UniMod:1)AAAAAAGAASGLPGPVAQGLK2 2 6.08421e-05 1.96448e-05 0.000168492 0.000168492 0.000146135 0.000169578 0 1 40439.4 39733.8 40439.4 0.833327 14.6301 14.5824 14.6777 77.7384 14.5747 78.2527 0 0.989019 1.0768e+06 1.68843 0.759575 0 0.999999 0.674737 0.0631384 17597.2;19526.2;16647.2;16204.2;12871.2;11069.2; 17377.7;19526.2;16647.2;16204.2;12871.2;10190.5; 0.828262;0.979726;0.827511;0.9628;0.90466;0.751867; 22067 1.22708 1.23344 1.23332 1.2261\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-B8_1_22654 Q96P70 Q96P70 IPO9 147008 145850 159209 147008 145850 159209 159209 (UniMod:1)AAAAAAGAASGLPGPVAQGLK AAAAAAGAASGLPGPVAQGLK (UniMod:1)AAAAAAGAASGLPGPVAQGLK2 2 4.42595e-05 1.96448e-05 0.000153516 0.000153516 0.000146135 0.000155304 0 1 41861.6 41532.1 41861.6 0.752921 14.549 14.5013 14.5967 77.7384 14.5155 78.0748 0 0.877873 939172 1.59762 0.821027 0 0.999997 0.397952 1.22212e-05 18143.2;19574.2;17444.2;17956.2;11427.2;13025.2; 17409.2;18432.7;16706.7;10820.4;11427.2;13025.2; 0.625292;0.399297;0.717726;0.321047;0.864595;0.825535; 21947 1.2275 1.23344 1.23199 1.2281\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A2_1_22636 P28482 P28482 MAPK1 72652.7 75570.7 78604.9 72652.7 75570.7 78604.9 78604.9 (UniMod:1)AAAAAAGAGPEM(UniMod:35)VR AAAAAAGAGPEMVR (UniMod:1)AAAAAAGAGPEM(UniMod:35)VR2 2 0.00693727 0.000834654 0.000159821 0.000159821 0.000146135 0.000161212 0 1 192.198 199.917 192.198 0.0197094 7.4249 7.37721 7.4726 15.9025 7.49813 15.2482 0 0.754191 8842.06 1.19725 0.470393 0.086229 0.843331 2.80548 0.384248 897.008;1032.01;279.002;377.003;440.004;286.003; 0;137.786;54.4117;0;89.692;286.003; -0.20379;-0.0679789;0.241761;-0.388501;-0.0459688;0.973644; 11191 1.01917 1.0262 1.02479 1.02031\nF:\\XXX\\20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642.d 20201218_tims03_Evo03_PS_SA_HeLa_200ng_high_speed_21min_8cm_S2-A8_1_22642 P28482 P28482 MAPK1 69911.3 68996.2 63388.2 69911.3 68996.2 63388.2 63388.2 (UniMod:1)AAAAAAGAGPEM(UniMod:35)VR AAAAAAGAGPEMVR (UniMod:1)AAAAAAGAGPEM(UniMod:35)VR2 2 0.00122498 0.000834654 0.000152765 0.000152765 0.000146135 0.000154631 0 1 1572.67 1552.08 1572.67 0.906427 7.45711 7.40943 7.50482 15.9025 7.43922 16.0749 0 0.371998 5937.05 0.30888 0.510876 0.72688 0.95182 1.96259 0.65474 1320.01;838.009;638.006;827.009;562.005;339.003; 1320.01;252.656;0;213.073;330.325;0; 0.976001;0.542934;0.346963;0.38014;0.442774;-0.259898; 11239 1.01773 1.0262 1.02509 1.01834\n''')\ndiann_reader = psm_reader_provider.get_reader_by_yaml(psm_reader_yaml['diann'])\ndiann_reader.import_file(tsv)\n\nassert 'ccs' in diann_reader.psm_df.columns\nassert len(diann_reader.psm_df) == 14\nassert np.sum(diann_reader.psm_df.mods.str.contains('Acetyl@Protein N-term')) == 10\nassert np.sum(~diann_reader.psm_df.mods.str.contains('Acetyl@Protein N-term')) == 4\nassert np.sum(diann_reader.psm_df.mods.str.contains('Oxidation@M')) == 2\nassert np.all(np.array(diann_reader.modification_mapping['Phospho@S'])==np.array([\n 'S(Phospho (S))',\n 'S(Phospho (ST))',\n 'S(Phospho (STY))',\n 'S(ph)',\n 'S(UniMod:21)',\n 'pS',\n 'S[Phospho (S)]',\n 'S[Phospho (ST)]',\n 'S[Phospho (STY)]',\n 'S[ph]',\n 'S[UniMod:21]'])\n)" - }, - { - "objectID": "peptide/precursor.html", - "href": "peptide/precursor.html", - "title": "Precursor Functionalities", - "section": "", - "text": "source\n\nupdate_precursor_mz\n\n update_precursor_mz (precursor_df:pandas.core.frame.DataFrame,\n batch_size=500000)\n\nCalculate precursor_mz inplace in the precursor_df\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nprecursor_df\nDataFrame\n\nprecursor_df with the ‘charge’ column\n\n\nbatch_size\nint\n500000\n\n\n\nReturns\nDataFrame\n\nprecursor_df with ‘precursor_mz’\n\n\n\n\nsource\n\n\nis_precursor_refined\n\n is_precursor_refined (precursor_df:pandas.core.frame.DataFrame)\n\n\nsource\n\n\nrefine_precursor_df\n\n refine_precursor_df (df:pandas.core.frame.DataFrame, drop_frag_idx=True,\n ensure_data_validity=False)\n\nRefine df inplace for faster precursor/fragment calculation.\n\nsource\n\n\nhash_precursor_df\n\n hash_precursor_df (precursor_df:pandas.core.frame.DataFrame, seed:int=0)\n\nAdd columns ‘mod_seq_hash’ and ‘mod_seq_charge_hash’ into precursor_df (inplace). The 64-bit hash function is from mmh3 (mmh3.hash64).\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nprecursor_df\nDataFrame\n\nprecursor_df\n\n\nseed\nint\n0\n\n\n\nReturns\nDataFrame\n\nDataFrame with columns ‘mod_seq_hash’ and ‘mod_seq_charge_hash’\n\n\n\n\nsource\n\n\nhash_mod_seq_charge_df\n\n hash_mod_seq_charge_df (precursor_df:pandas.core.frame.DataFrame, seed=0)\n\nInternal function\n\nsource\n\n\nhash_mod_seq_df\n\n hash_mod_seq_df (precursor_df:pandas.core.frame.DataFrame, seed=0)\n\nInternal function\n\nsource\n\n\nget_mod_seq_charge_hash\n\n get_mod_seq_charge_hash (sequence:str, mods:str, mod_sites:str,\n charge:int, seed=0)\n\nGet hash code value for a precursor: (sequence, mods, mod_sites, charge)\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nsequence\nstr\n\nAmino acid sequence\n\n\nmods\nstr\n\nModification names in AlphaBase format\n\n\nmod_sites\nstr\n\nModification sites in AlphaBase format\n\n\ncharge\nint\n\nPrecursor charge state\n\n\nseed\nint\n0\nSeed for hashing.Optional, by default 0\n\n\nReturns\nnp.int64\n\n64-bit hash code value\n\n\n\n\nsource\n\n\nget_mod_seq_hash\n\n get_mod_seq_hash (sequence:str, mods:str, mod_sites:str, seed:int=0)\n\nGet hash code value for a peptide: (sequence, mods, mod_sites)\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nsequence\nstr\n\nAmino acid sequence\n\n\nmods\nstr\n\nModification names in AlphaBase format\n\n\nmod_sites\nstr\n\nModification sites in AlphaBase format\n\n\nseed\nint\n0\nSeed for hashing.Optional, by default 0\n\n\nReturns\nint64\n\n64-bit hash code value\n\n\n\n\nsource\n\n\ncalc_precursor_isotope_mp\n\n calc_precursor_isotope_mp (precursor_df:pandas.core.frame.DataFrame,\n processes:int=8, mp_batch_size:int=100000,\n process_bar=None,\n min_right_most_intensity:float=0.2)\n\ncalc_precursor_isotope is not that fast for large dataframes, so here we use multiprocessing for faster isotope pattern calculation. The speed is acceptable with multiprocessing (3.8 min for 21M precursors, 8 processes).\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nprecursor_df\nDataFrame\n\nPrecursor_df to calculate\n\n\nprocesses\nint\n8\nProcess number. Optional, by default 8\n\n\nmp_batch_size\nint\n100000\nMultiprocessing batch size. Optional, by default 100000.\n\n\nprocess_bar\nNoneType\nNone\nThe tqdm-based callback function to check multiprocessing. Defaults to None.\n\n\nmin_right_most_intensity\nfloat\n0.2\nThe minimal intensity value of the right-most peak relative to apex peak. Optional, by default 0.2\n\n\nReturns\nDataFrame\n\nprecursor_df with additional columns:- isotope_m1_intensity- isotope_m1_mz- isotope_apex_intensity- isotope_apex_mz- isotope_apex_index- isotope_right_most_intensity- isotope_right_most_mz- isotope_right_most_index\n\n\n\n\nsource\n\n\ncalc_precursor_isotope\n\n calc_precursor_isotope (precursor_df:pandas.core.frame.DataFrame,\n min_right_most_intensity:float=0.2)\n\nCalculate isotope mz values and relative (to M0) intensity values for precursor_df inplace.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nprecursor_df\nDataFrame\n\nprecursor_df to calculate\n\n\nmin_right_most_intensity\nfloat\n0.2\nThe minimal intensity value of the right-most peak relative to apex peak. Optional, by default 0.2\n\n\nReturns\npd.DataFrame\n\nprecursor_df with additional columns:- isotope_m1_intensity- isotope_m1_mz- isotope_apex_intensity- isotope_apex_mz- isotope_apex_index- isotope_right_most_intensity- isotope_right_most_mz- isotope_right_most_index\n\n\n\n\nsource\n\n\nget_mod_seq_isotope_distribution\n\n get_mod_seq_isotope_distribution (seq_mods:tuple,\n isotope_dist:alphabase.constants.isotop\n e.IsotopeDistribution,\n min_right_most_intensity:float=0.2)\n\nGet isotope abundance distribution by IsotopeDistribution. This function is designed for multiprocessing.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nseq_mods\ntuple\n\n(sequence, mods)\n\n\nisotope_dist\nIsotopeDistribution\n\nSee IsotopeDistribution in alphabase.constants.isotope\n\n\nmin_right_most_intensity\nfloat\n0.2\nThe minimal intensity value of the right-most peak relative to apex peak. Optional, by default 0.2\n\n\nReturns\ntuple\n\nfloat - Abundance of mono+1 / monofloat - Abundance of apex / monoint - Apex isotope position relative to mono, i.e. apex index - mono index and 0 refers to the position of mono itselffloat - Abundance of right-most peak which has at least min_right_most_intensity intensity relative to the apex peakint - Right-most position relative to mono, i.e. right-most index - mono index\n\n\n\n\nsource\n\n\nget_right_most_isotope_index\n\n get_right_most_isotope_index (intensities:numpy.ndarray, apex_idx:int,\n min_right_most_intensity:float)\n\nGet right-most isotope index\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nintensities\nndarray\nIsotope intensities\n\n\napex_idx\nint\nThe index or position of apex peak\n\n\nmin_right_most_intensity\nfloat\nMinimal intensity to consider for right-most peak relative to apex\n\n\nReturns\nint\nIndex or position of the right-most peak\n\n\n\n\nsource\n\n\nget_mod_seq_formula\n\n get_mod_seq_formula (seq:str, mods:str)\n\n‘PEPTIDE’,‘Acetyl@Any N-term’ –> [(‘C’,n), (‘H’,m), …]\n\n\nTesting\n\nrepeat = 2\npeptides = ['AGHCEWQMKAADER']*repeat\nmods = ['Acetyl@Protein N-term;Carbamidomethyl@C;Oxidation@M']*repeat\nsites = ['0;4;8']*repeat\npeptides += ['AGHCEWQMK']*repeat\nmods += ['']*repeat\nsites += ['']*repeat\n\nprecursor_df = pd.DataFrame({\n 'sequence': peptides,\n 'mods': mods,\n 'mod_sites': sites\n})\nprecursor_df['nAA'] = precursor_df['sequence'].str.len()\nprecursor_df['charge'] = 2" - }, - { - "objectID": "peptide/fragment.html", - "href": "peptide/fragment.html", - "title": "Fragment Functionalities", - "section": "", - "text": "peptide N-term modification site is 0\nC-term modification site is -1\nother modifications sites are integers from 1 to nAA\n\nJust in case that we have two modifications, one is on the peptide N-term, and the other is on the N-term AA site chain. Similar for C-term sites.\n\nsource" - }, - { - "objectID": "peptide/fragment.html#test-mod-deltas", - "href": "peptide/fragment.html#test-mod-deltas", - "title": "Fragment Functionalities", - "section": "Test mod deltas", - "text": "Test mod deltas\n\nrepeat = 1\npeptides = ['AGHCEWQMK']*repeat\nmods = ['Acetyl@Protein N-term;Carbamidomethyl@C;Oxidation@M']*repeat\nsites = ['0;4;8']*repeat\npeptides += ['AGHCEWQMK']*repeat\nmods += ['Acetyl@Protein N-term;Carbamidomethyl@C;Oxidation@M']*repeat\nsites += ['0;4;8']*repeat\n\nprecursor_df = pd.DataFrame({\n 'sequence': peptides,\n 'mods': mods,\n 'mod_sites': sites\n})\nprecursor_df['nAA'] = precursor_df['sequence'].str.len()\nprecursor_df['charge'] = 2\nmod_deltas = ['']*len(precursor_df)\nmod_delta_sites = ['']*len(precursor_df)\nmod_deltas[0],mod_delta_sites[0] = '100;200','0;-1'\nprecursor_df['mod_deltas'] = mod_deltas\nprecursor_df['mod_delta_sites'] = mod_delta_sites\nupdate_precursor_mz(precursor_df)\nassert np.allclose(precursor_df.precursor_mz.values, [752.747333, 602.747333])\nfragment_mz_df = create_fragment_mz_dataframe(precursor_df, charged_frag_types=fragment_mz_df.columns.values)\nassert np.allclose(fragment_mz_df['y_z1'].values[precursor_df.frag_start_idx[0]:precursor_df.frag_end_idx[0]], \n [1291.43971168, 1234.41824796, 1097.3593361 , 937.32868742,\n 808.28609433, 622.20678138, 494.14820387, 347.11280417]\n), f'200 Da must be added to all y-ions'\nassert np.allclose(fragment_mz_df['b_z1'].values[precursor_df.frag_start_idx[0]:precursor_df.frag_end_idx[0]], \n [214.05495494, 271.07641866, 408.13533052, 568.1659792 ,\n 697.20857228, 883.28788524, 1011.34646274, 1158.38186245]\n), f'100 Da must be added to all b-ions'\nprecursor_df\n\n\n\n\n\n \n \n \n sequence\n mods\n mod_sites\n nAA\n charge\n mod_deltas\n mod_delta_sites\n precursor_mz\n frag_start_idx\n frag_end_idx\n \n \n \n \n 0\n AGHCEWQMK\n Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat...\n 0;4;8\n 9\n 2\n 100;200\n 0;-1\n 752.747333\n 0\n 8\n \n \n 1\n AGHCEWQMK\n Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat...\n 0;4;8\n 9\n 2\n \n \n 602.747333\n 8\n 16" - }, - { - "objectID": "peptide/mass_calc.html", - "href": "peptide/mass_calc.html", - "title": "Mass Calculation", - "section": "", - "text": "calc_b_y_and_peptide_mass\n\n calc_b_y_and_peptide_mass (sequence:str, mod_names:List[str],\n mod_sites:List[int],\n mod_deltas:List[float]=None,\n mod_delta_sites:List[int]=None)\n\nIt is highly recommend to use calc_b_y_and_peptide_masses_for_same_len_seqs as it is much faster\n\nsource\n\n\ncalc_mod_delta_masses_for_same_len_seqs\n\n calc_mod_delta_masses_for_same_len_seqs (nAA:int,\n mod_deltas_list:List[List[float]\n ],\n mod_sites_list:List[List[int]])\n\nCalculate delta modification masses for the given peptide length (nAA), For open-search, we may also get modification mass deltas other than mod names. This function calculate modification masses from these delta masses.\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nnAA\nint\npeptide length\n\n\nmod_deltas_list\ntyping.List[typing.List[float]]\n\n\n\nmod_sites_list\ntyping.List[typing.List[int]]\nlist of modification site list corresponding to mod_names_list.* site=0 refers to an N-term modification* site=-1 refers to a C-term modification* 1<=site<=peplen refers to a normal modification\n\n\nReturns\nndarray\n2-D array with shape=(nAA, pep_count or len(mod_names_list))). Masses of modifications through all the peptides, 0 if sites has no modifications\n\n\n\n\nsource\n\n\ncalc_delta_modification_mass\n\n calc_delta_modification_mass (pep_len:int, mass_deltas:List[float],\n mass_delta_sites:List[int])\n\nFor open-search, we may also get modification mass deltas other than mod names. This function calculate modification masses from these delta masses.\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\npep_len\nint\nnAA\n\n\nmass_deltas\ntyping.List[float]\nmass deltas on the peptide\n\n\nmass_delta_sites\ntyping.List[int]\nlocalized sites of corresponding mass deltas\n\n\nReturns\nndarray\n1-D array with length=peplen.Masses of modifications (mass deltas) through the peptide,0 if sites has no modifications\n\n\n\n\n\ncalc_peptide_masses_for_same_len_seqs and calc_b_y_and_peptide_masses_for_same_len_seqs are key functions for mass calculation in this module.\ncalc_peptide_masses_for_same_len_seqs calculates the peptide masses for the given sequence array and modification lists.\ncalc_b_y_and_peptide_masses_for_same_len_seqs calculates b/y neutral masses and peptide masses for the given sequence array and modification lists. Note that all a/b/c neutral masses can be calculated from b fragment masses, and x/y/z from y masses. So the key are b/y masses.\n\nsource\n\n\ncalc_b_y_and_peptide_masses_for_same_len_seqs\n\n calc_b_y_and_peptide_masses_for_same_len_seqs (sequences:numpy.ndarray,\n mod_list:List[List[str]],\n site_list:List[List[int]],\n mod_delta_list:List[List[f\n loat]]=None, mod_delta_sit\n e_list:List[List[int]]=Non\n e)\n\nCalculate b/y fragment masses and peptide masses for peptide sequences with same lengths. We need ‘same_len’ here because numpy can process AA sequences with same length very fast.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nsequences\nndarray\n\n\n\n\nmod_list\ntyping.List[typing.List[str]]\n\nlist of modifications , e.g. [['Oxidation@M','Phospho@S'],['Phospho@S','Deamidated@N']]\n\n\nsite_list\ntyping.List[typing.List[int]]\n\nlist of modification sitescorresponding to mod_list, e.g. [[3,6],[4,17]]\n\n\nmod_delta_list\ntyping.List[typing.List[float]]\nNone\nlist of modifications, e.g. [[15.994915,79.966331],[79.966331,0.984016]]\n\n\nmod_delta_site_list\ntyping.List[typing.List[int]]\nNone\nlist of modification mass delta sitescorresponding to mod_list, e.g. [[3,6],[4,17]]\n\n\nReturns\ntyping.Tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray]\n\nneutral b fragment masses (2-D array)\n\n\n\n\nsource\n\n\ncalc_peptide_masses_for_same_len_seqs\n\n calc_peptide_masses_for_same_len_seqs (sequences:numpy.ndarray,\n mod_list:List[str],\n mod_delta_list:List[str]=None)\n\nCalculate peptide masses for peptide sequences with same lengths. We need ‘same_len’ here because numpy can process AA sequences with same length very fast. See alphabase.aa.calc_sequence_masses_for_same_len_seqs\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nsequences\nndarray\n\n\n\n\nmod_list\ntyping.List[str]\n\nlist of modifications, e.g. ['Oxidation@M;Phospho@S','Phospho@S;Deamidated@N']\n\n\nmod_delta_list\ntyping.List[str]\nNone\n\n\n\nReturns\nndarray\n\npeptide masses (1-D array, H2O already added)\n\n\n\n\n\nTesting\n\nseq, mods, mod_sites = 'AGHCEWQMK', ['Carbamidomethyl@C', 'Oxidation@M'], [4, 8]\nb,y,pepmass = calc_b_y_and_peptide_mass(seq, mods, mod_sites)\nassert np.allclose(b, [ 71.03711379, 128.05857751, 265.11748936, 425.14813804,\n 554.19073113, 740.27004408, 868.32862159, 1015.3640213 ]\n)\nassert np.allclose(y, [ [1090.43243521, 1033.41097149, 896.35205963, 736.32141095,\n 607.27881786, 421.19950491, 293.14092741, 146.1055277 ] ]\n)\nassert np.allclose(pepmass, 1161.46954899713)\n\n\nb_frags,y_frags,pepmasses=calc_b_y_and_peptide_masses_for_same_len_seqs([seq]*2, [mods,[]], [mod_sites,[]])\nassert np.allclose(b_frags[0], [ 71.03711379, 128.05857751, 265.11748936, 425.14813804,\n 554.19073113, 740.27004408, 868.32862159, 1015.3640213 ]\n)\nassert np.allclose(y_frags[0], [ [1090.43243521, 1033.41097149, 896.35205963, 736.32141095,\n 607.27881786, 421.19950491, 293.14092741, 146.1055277 ] ]\n)\nassert np.allclose(pepmasses[0], 1161.46954899713)\n\n\nassert np.allclose(calc_peptide_masses_for_same_len_seqs([seq]*2, [';'.join(mods),\"\"]), [1161.469549 , 1088.45317066])" - }, - { - "objectID": "peptide/mobility.html", - "href": "peptide/mobility.html", - "title": "CCS/Mobility Functionalities", - "section": "", - "text": "source\n\nmobility_to_ccs_for_df\n\n mobility_to_ccs_for_df (precursor_df:pandas.core.frame.DataFrame,\n mobility_column:str, vendor='bruker')\n\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nprecursor_df\nDataFrame\n\nprecursor_df\n\n\nmobility_column\nstr\n\nmobility column name in precursor_df\n\n\nvendor\nstr\nbruker\nDifferent vender may have different IM calculation. Defaults to “bruker”.Note that other vendors are not implemented currently.\n\n\nReturns\nndarray\n\nCCS values\n\n\n\n\nsource\n\n\nccs_to_mobility_for_df\n\n ccs_to_mobility_for_df (precursor_df:pandas.core.frame.DataFrame,\n ccs_column:str, vendor='bruker')\n\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nprecursor_df\nDataFrame\n\nprecursor_df\n\n\nccs_column\nstr\n\nCCS column name in precursor_df\n\n\nvendor\nstr\nbruker\nDifferent vender may have different IM calculation. Defaults to “bruker”.Note that other vendors are not implemented currently.\n\n\nReturns\nndarray\n\nmobility values\n\n\n\n\nsource\n\n\nmobility_to_ccs_bruker\n\n mobility_to_ccs_bruker (im_values:numpy.ndarray, charges:numpy.ndarray,\n precursor_mzs:numpy.ndarray)\n\nConvert mobility to CCS for Bruker (timsTOF)\n\nsource\n\n\nccs_to_mobility_bruker\n\n ccs_to_mobility_bruker (ccs_values:numpy.ndarray, charges:numpy.ndarray,\n precursor_mzs:numpy.ndarray)\n\nConvert CCS to mobility for Bruker (timsTOF)\n\nsource\n\n\nget_reduced_mass\n\n get_reduced_mass (precursor_mzs:numpy.ndarray, charges:numpy.ndarray)\n\nReduced mass for CCS and mobility calculation" - }, - { - "objectID": "spectral_library/decoy_library.html", - "href": "spectral_library/decoy_library.html", - "title": "Decoy Libraries", - "section": "", - "text": "source\n\nDiaNNDecoyLib\n\n DiaNNDecoyLib\n (target_lib:alphabase.spectral_library.library_base.SpecLi\n bBase, raw_AAs:str='GAVLIFMPWSCTYHKRQEND',\n mutated_AAs:str='LLLVVLLLLTSSSSLLNDQE', **kwargs)\n\nDiaNN-like decoy peptide generator\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ntarget_lib\nSpecLibBase\n\nTarget library object\n\n\nraw_AAs\nstr\nGAVLIFMPWSCTYHKRQEND\nAAs those DiaNN decoy from. Defaults to ‘GAVLIFMPWSCTYHKRQEND’.\n\n\nmutated_AAs\nstr\nLLLVVLLLLTSSSSLLNDQE\nDiaNN\n\n\nkwargs\n\n\n\n\n\n\n\nsource\n\n\nDecoyLib\n\n DecoyLib (target_lib:alphabase.spectral_library.library_base.SpecLibBase,\n fix_C_term=True, **kwargs)\n\nPseudo-reverse peptide decoy generator Currently, only sequence-level decoy is implemented, but AlphaPeptDeep will add modifications onto both target and decoy sequences, so it is enough for practical uses.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ntarget_lib\nSpecLibBase\n\nTarget library to decoy.\n\n\nfix_C_term\nbool\nTrue\nIf fix C-term AA when decoy. Defaults to True.\n\n\nkwargs\n\n\n\n\n\n\n\nsource\n\n\nDecoyLib.decoy_sequence\n\n DecoyLib.decoy_sequence ()\n\nGenerate decoy sequences from self.target_lib\n\nsource\n\n\nDecoyLibProvider\n\n DecoyLibProvider ()\n\nInitialize self. See help(type(self)) for accurate signature.\n\nsource\n\n\nDecoyLibProvider.get_decoy_lib\n\n DecoyLibProvider.get_decoy_lib (name:str,\n target_lib:alphabase.spectral_library.lib\n rary_base.SpecLibBase, **kwargs)\n\nGet an object of a subclass of DecoyLib based on registered name.\n\n\n\n\nType\nDetails\n\n\n\n\nname\nstr\nRegistered decoy class name\n\n\ntarget_lib\nSpecLibBase\nTarget library for decoy generation\n\n\nkwargs\n\n\n\n\nReturns\nDecoyLib\nDecoy library object\n\n\n\n\n\nRegistered decoy methods\n\ndecoy_lib_provider.decoy_dict\n\n{'pseudo_reverse': __main__.DecoyLib, 'diann': __main__.DiaNNDecoyLib}" - }, - { - "objectID": "spectral_library/library_base.html", - "href": "spectral_library/library_base.html", - "title": "Base Class for Spectral Libraries", - "section": "", - "text": "source\n\nSpecLibBase\n\n SpecLibBase (charged_frag_types:List[str]=['b_z1', 'b_z2', 'y_z1',\n 'y_z2'], precursor_mz_min=400, precursor_mz_max=6000,\n decoy:str=None)\n\nBase spectral library in alphabase and alphapeptdeep.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ncharged_frag_types\ntyping.List[str]\n[‘b_z1’, ‘b_z2’, ‘y_z1’, ‘y_z2’]\n[‘b_z1’,‘b_z2’,‘y_z1’,‘y_modloss_z1’, …]; ‘b_z1’: ‘b’ is the fragment type and ‘z1’ is the charge state z=1.\n\n\nprecursor_mz_min\nint\n400\nUse this to clip precursor df. Defaults to 400.\n\n\nprecursor_mz_max\nint\n6000\nUse this to clip precursor df. Defaults to 6000.\n\n\ndecoy\nstr\nNone\nDecoy methods, could be “pseudo_reverse” or “diann”.Defaults to None.\n\n\n\n\nsource\n\n\nSpecLibBase.append_decoy_sequence\n\n SpecLibBase.append_decoy_sequence ()\n\nAppend decoy sequence into precursor_df. Decoy method is based on self.decoy(str).\ndecoy_lib = (\n decoy_lib_provider.get_decoy_lib(\n self.decoy, self\n )\n)\ndecoy_lib.decoy_sequence()\n...\n\nsource\n\n\nSpecLibBase.hash_precursor_df\n\n SpecLibBase.hash_precursor_df ()\n\nInsert hash codes for peptides and precursors\n\nsource\n\n\nSpecLibBase.calc_precursor_isotope\n\n SpecLibBase.calc_precursor_isotope (multiprocessing:bool=True,\n mp_process_num:int=8,\n mp_process_bar=None,\n min_num_for_mp:int=1000)\n\nAppend isotope columns into self.precursor_df. See alphabase.peptide.precursor.calc_precursor_isotope for details.\n\nsource\n\n\nSpecLibBase.flatten_fragment_data\n\n SpecLibBase.flatten_fragment_data ()\n\nCreate flattened (1-D) np.ndarray for fragment mz and intensity dataframes, respectively. The arrays are references to original data, that means: 1. This method is fast; 2. Changing the array values will change the df values. They can be unraveled back using: array.reshape(len(self._fragment_mz_df.columns), -1)\n\nsource\n\n\nSpecLibBase.calc_precursor_mz\n\n SpecLibBase.calc_precursor_mz ()\n\nCalculate precursor mz for self._precursor_df, and clip the self._precursor_df using self.clip_by_precursor_mz_\n\nsource\n\n\nSpecLibBase.clip_by_precursor_mz_\n\n SpecLibBase.clip_by_precursor_mz_ ()\n\nClip self._precursor_df inplace by self.min_precursor_mz and self.max_precursor_mz\n\nsource\n\n\nSpecLibBase.load_hdf\n\n SpecLibBase.load_hdf (hdf_file:str, load_mod_seq:bool=False)\n\nLoad the hdf library from hdf_file\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nhdf_file\nstr\n\nhdf library path to load\n\n\nload_mod_seq\nbool\nFalse\nif also load mod_seq_df. Defaults to False.\n\n\n\n\nsource\n\n\nSpecLibBase.load_df_from_hdf\n\n SpecLibBase.load_df_from_hdf (hdf_file:str, df_name:str)\n\nLoad specific dataset (dataframe) from hdf_file.\n\n\n\n\nType\nDetails\n\n\n\n\nhdf_file\nstr\nThe hdf file name\n\n\ndf_name\nstr\nThe dataset/dataframe name in the hdf file\n\n\nReturns\nDataFrame\nLoaded dataframe\n\n\n\n\nsource\n\n\nSpecLibBase.save_hdf\n\n SpecLibBase.save_hdf (hdf_file:str)\n\nSave library dataframes into hdf_file. For self.precursor_df, this method will save it into two hdf groups: hdf_file: library/precursor_df and library/mod_seq_df.\nlibrary/precursor_df contains all essential numberic columns those can be loaded faster from hdf file into memory: ‘precursor_mz’, ‘charge’, ‘mod_seq_hash’, ‘mod_seq_charge_hash’, ‘frag_start_idx’, ‘frag_end_idx’, ‘decoy’, ‘rt_pred’, ‘ccs_pred’, ‘mobility_pred’, ‘miss_cleave’, ‘nAA’, [‘isotope_mz_m1’, ‘isotope_intensity_m1’], …\nlibrary/mod_seq_df contains all string columns and the other not essential columns: ‘sequence’,‘mods’,‘mod_sites’, [‘proteins’, ‘genes’]… as well as ‘mod_seq_hash’, ‘mod_seq_charge_hash’ columns to map back to precursor_df\n\n\n\n\nType\nDetails\n\n\n\n\nhdf_file\nstr\nthe hdf file path to save\n\n\n\n\nsource\n\n\nSpecLibBase.save_df_to_hdf\n\n SpecLibBase.save_df_to_hdf (hdf_file:str, df_key:str,\n df:pandas.core.frame.DataFrame,\n delete_existing=False)\n\nSave a new HDF group or dataset into existing HDF file\n\nsource\n\n\nSpecLibBase.refine_df\n\n SpecLibBase.refine_df ()\n\nSort nAA and reset_index for faster calculation (or prediction)\n\nsource\n\n\nSpecLibBase.calc_precursor_isotope\n\n SpecLibBase.calc_precursor_isotope (multiprocessing:bool=True,\n mp_process_num:int=8,\n mp_process_bar=None,\n min_num_for_mp:int=1000)\n\nAppend isotope columns into self.precursor_df. See alphabase.peptide.precursor.calc_precursor_isotope for details.\n\n\nTesting\n\nimport pandas as pd\nimport os\n\n\nrepeat = 3\npeptides = ['AGHCEWQMK']*repeat\nmods = ['Acetyl@Protein N-term;Carbamidomethyl@C;Oxidation@M']*repeat\nsites = ['0;4;8']*repeat\npeptides += ['AGHCEWQMKAADER']*repeat\nmods += ['']*repeat\nsites += ['']*repeat\n\nprecursor_df = pd.DataFrame({\n 'sequence': peptides,\n 'mods': mods,\n 'mod_sites': sites\n})\nprecursor_df['nAA'] = precursor_df['sequence'].str.len()\nprecursor_df['charge'] = 2\ntarget_lib = SpecLibBase(\n ['b_z1','b_z2','y_z1','y_z2'],\n decoy='pseudo_reverse'\n)\ntarget_lib._precursor_df = precursor_df\ntarget_lib.calc_precursor_mz()\ntarget_lib._fragment_mz_df = pd.DataFrame()\ntarget_lib._fragment_intensity_df = pd.DataFrame()\nif not os.path.isdir('sandbox'):\n os.makedirs('sandbox')\ntarget_lib.save_hdf('sandbox/test_lib.hdf')\ntarget_lib.save_df_to_hdf('sandbox/test_lib.hdf','protein_df',pd.DataFrame(\n {\n 'id':[1,2],\n 'full_name': [1,2],\n 'description': [1,2],\n 'sequence': [1,2]\n })\n)\nnew_lib = SpecLibBase([])\nnew_lib.load_hdf('sandbox/test_lib.hdf')\n\nassert len(new_lib.precursor_df) > 0\nassert len(new_lib.fragment_mz_df) == 0\nassert len(new_lib.fragment_intensity_df) == 0\n\nassert 'sequence' not in new_lib.precursor_df.columns\nassert 'mod_seq_hash' in new_lib.precursor_df.columns\n\n\nnew_lib = SpecLibBase([])\nnew_lib.load_hdf('sandbox/test_lib.hdf', load_mod_seq=True)\nassert 'sequence' in new_lib.precursor_df.columns\nassert 'mod_seq_hash' in new_lib.precursor_df.columns\n\ndf = target_lib.load_df_from_hdf('sandbox/test_lib.hdf', 'precursor_df')\nassert len(precursor_df)==len(df)\ndf = target_lib.load_df_from_hdf('sandbox/test_lib.hdf', 'protein_df')\nassert len(df)==2\nos.remove('sandbox/test_lib.hdf')\nprecursor_df\n\n\n\n\n\n \n \n \n sequence\n mods\n mod_sites\n nAA\n charge\n precursor_mz\n mod_seq_hash\n mod_seq_charge_hash\n \n \n \n \n 0\n AGHCEWQMK\n Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat...\n 0;4;8\n 9\n 2\n 602.747333\n -5783464648586361190\n -5783464648586361188\n \n \n 1\n AGHCEWQMK\n Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat...\n 0;4;8\n 9\n 2\n 602.747333\n -5783464648586361190\n -5783464648586361188\n \n \n 2\n AGHCEWQMK\n Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat...\n 0;4;8\n 9\n 2\n 602.747333\n -5783464648586361190\n -5783464648586361188\n \n \n 3\n AGHCEWQMKAADER\n \n \n 14\n 2\n 816.356299\n -1606275412423975023\n -1606275412423975021\n \n \n 4\n AGHCEWQMKAADER\n \n \n 14\n 2\n 816.356299\n -1606275412423975023\n -1606275412423975021\n \n \n 5\n AGHCEWQMKAADER\n \n \n 14\n 2\n 816.356299\n -1606275412423975023\n -1606275412423975021\n \n \n\n\n\n\n\ntarget_lib.append_decoy_sequence()\nassert len(target_lib.precursor_df) == len(precursor_df)*2\ntarget_lib.precursor_df\n\n\n\n\n\n \n \n \n sequence\n mods\n mod_sites\n nAA\n charge\n precursor_mz\n mod_seq_hash\n mod_seq_charge_hash\n decoy\n \n \n \n \n 0\n AGHCEWQMK\n Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat...\n 0;4;8\n 9\n 2\n 602.747333\n -5783464648586361190\n -5783464648586361188\n 0\n \n \n 1\n AGHCEWQMK\n Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat...\n 0;4;8\n 9\n 2\n 602.747333\n -5783464648586361190\n -5783464648586361188\n 0\n \n \n 2\n AGHCEWQMK\n Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat...\n 0;4;8\n 9\n 2\n 602.747333\n -5783464648586361190\n -5783464648586361188\n 0\n \n \n 3\n MQWECHGAK\n Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat...\n 0;4;8\n 9\n 2\n 602.747333\n -5783464648586361190\n -5783464648586361188\n 1\n \n \n 4\n MQWECHGAK\n Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat...\n 0;4;8\n 9\n 2\n 602.747333\n -5783464648586361190\n -5783464648586361188\n 1\n \n \n 5\n MQWECHGAK\n Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat...\n 0;4;8\n 9\n 2\n 602.747333\n -5783464648586361190\n -5783464648586361188\n 1\n \n \n 6\n AGHCEWQMKAADER\n \n \n 14\n 2\n 816.356299\n -1606275412423975023\n -1606275412423975021\n 0\n \n \n 7\n AGHCEWQMKAADER\n \n \n 14\n 2\n 816.356299\n -1606275412423975023\n -1606275412423975021\n 0\n \n \n 8\n AGHCEWQMKAADER\n \n \n 14\n 2\n 816.356299\n -1606275412423975023\n -1606275412423975021\n 0\n \n \n 9\n EDAAKMQWECHGAR\n \n \n 14\n 2\n 816.356299\n -1606275412423975023\n -1606275412423975021\n 1\n \n \n 10\n EDAAKMQWECHGAR\n \n \n 14\n 2\n 816.356299\n -1606275412423975023\n -1606275412423975021\n 1\n \n \n 11\n EDAAKMQWECHGAR\n \n \n 14\n 2\n 816.356299\n -1606275412423975023\n -1606275412423975021\n 1\n \n \n\n\n\n\n\ntarget_lib.calc_fragment_mz_df()\nassert 'b_z1' in target_lib.fragment_mz_df\nassert len(target_lib.fragment_mz_df) == np.sum(target_lib.precursor_df.nAA-1)\ntarget_lib.fragment_mz_df\n\n\n\n\n\n \n \n \n b_z1\n b_z2\n y_z1\n y_z2\n \n \n \n \n 0\n 114.054955\n 57.531116\n 1091.439712\n 546.223494\n \n \n 1\n 171.076419\n 86.041848\n 1034.418248\n 517.712762\n \n \n 2\n 308.135331\n 154.571303\n 897.359336\n 449.183306\n \n \n 3\n 468.165979\n 234.586628\n 737.328687\n 369.167982\n \n \n 4\n 597.208572\n 299.107924\n 608.286094\n 304.646685\n \n \n ...\n ...\n ...\n ...\n ...\n \n \n 121\n 1089.466972\n 545.237124\n 543.245626\n 272.126451\n \n \n 122\n 1192.476157\n 596.741717\n 440.236442\n 220.621859\n \n \n 123\n 1329.535069\n 665.271173\n 303.177530\n 152.092403\n \n \n 124\n 1386.556532\n 693.781904\n 246.156066\n 123.581671\n \n \n 125\n 1457.593646\n 729.300461\n 175.118952\n 88.063114\n \n \n\n126 rows × 4 columns" - }, - { - "objectID": "constants/modification.html", - "href": "constants/modification.html", - "title": "Modification information", - "section": "", - "text": "The default modification TSV is stored in alphabase/constants/const_files/modification.tsv. Please check it to add more modifications.\nFirst, we load modification.tsv into MOD_DF.\nThen, we extract information of MOD_CHEM (dict), MOD_MASS (dict), MOD_LOSS_MASS (dict), MOD_INFO_DICT (dict) … from MOD_DF. This step is done in update_all_by_MOD_DF.\nAll these steps are done by load_mod_df.\nsource" - }, - { - "objectID": "constants/modification.html#we-can-update-modification-list-for-differet-requirements-for-example", - "href": "constants/modification.html#we-can-update-modification-list-for-differet-requirements-for-example", - "title": "Modification information", - "section": "We can update modification list for differet requirements, for example:", - "text": "We can update modification list for differet requirements, for example:\n\nadd_modifications_for_lower_case_AA()\nMOD_DF = MOD_DF[\n (MOD_DF['classification'].isin(['Post-translational','O-linked glycosylation','AA substitution','Multiple','Non-standard residue','Pre-translational']))\n & MOD_DF['lower_case_AA']\n] # we only need PTMs\nupdate_all_by_MOD_DF()\n# MOD_INFO_DICT is also updated\npd.DataFrame().from_dict(MOD_INFO_DICT, orient='index')\n\n\n\n\n\n \n \n \n mod_name\n avge_mass\n classification\n composition\n modloss_composition\n mono_mass\n unimod_id\n unimod_mass\n unimod_modloss\n modloss_importance\n mass\n modloss_original\n modloss\n lower_case_AA\n \n \n \n \n GlyGly@k\n GlyGly@k\n 114.042927\n Post-translational\n H(6)C(4)N(2)O(2)\n H(6)C(4)N(2)O(2)\n 114.042927\n 121\n 114.042927\n 114.042927\n 1000000.0\n 114.042927\n 114.042927\n 114.042927\n True\n \n \n 15N-oxobutanoic@s^Protein N-term\n 15N-oxobutanoic@s^Protein N-term\n -18.023900\n Post-translational\n H(-3)15N(-1)\n \n -18.023584\n 1419\n -18.023584\n 0.000000\n 0.0\n -18.023584\n 0.000000\n 0.000000\n True\n \n \n 15N-oxobutanoic@t^Protein N-term\n 15N-oxobutanoic@t^Protein N-term\n -18.023900\n Post-translational\n H(-3)15N(-1)\n \n -18.023584\n 1419\n -18.023584\n 0.000000\n 0.0\n -18.023584\n 0.000000\n 0.000000\n True\n \n \n 3-deoxyglucosone@r\n 3-deoxyglucosone@r\n 144.125300\n Multiple\n H(8)C(6)O(4)\n \n 144.042259\n 949\n 144.042259\n 0.000000\n 0.0\n 144.042259\n 0.000000\n 0.000000\n True\n \n \n 3-phosphoglyceryl@k\n 3-phosphoglyceryl@k\n 168.042000\n Post-translational\n H(5)C(3)O(6)P(1)\n \n 167.982375\n 1387\n 167.982375\n 0.000000\n 0.0\n 167.982375\n 0.000000\n 0.000000\n True\n \n \n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n \n \n pyrophospho@t\n pyrophospho@t\n 159.959800\n Post-translational\n H(2)O(6)P(2)\n H(3)O(7)P(2)\n 159.932662\n 898\n 159.932662\n 176.935402\n 0.0\n 159.932662\n 176.935401\n 0.000000\n True\n \n \n s-GlcNAc@s\n s-GlcNAc@s\n 283.255700\n O-linked glycosylation\n H(13)C(8)N(1)O(8)S(1)\n H(13)C(8)N(1)O(8)S(1)\n 283.036187\n 1412\n 283.036187\n 283.036187\n 0.0\n 283.036188\n 283.036188\n 0.000000\n True\n \n \n s-GlcNAc@t\n s-GlcNAc@t\n 283.255700\n O-linked glycosylation\n H(13)C(8)N(1)O(8)S(1)\n H(13)C(8)N(1)O(8)S(1)\n 283.036187\n 1412\n 283.036187\n 283.036187\n 0.0\n 283.036188\n 283.036188\n 0.000000\n True\n \n \n serotonylation@q\n serotonylation@q\n 159.184600\n Post-translational\n H(9)C(10)N(1)O(1)\n \n 159.068414\n 1992\n 159.068414\n 0.000000\n 0.0\n 159.068414\n 0.000000\n 0.000000\n True\n \n \n trifluoro@l\n trifluoro@l\n 53.971400\n Non-standard residue\n H(-3)F(3)\n \n 53.971735\n 750\n 53.971735\n 0.000000\n 0.0\n 53.971734\n 0.000000\n 0.000000\n True\n \n \n\n1249 rows × 14 columns\n\n\n\n\nsource\n\nadd_new_modifications\n\n add_new_modifications (new_mods:list)\n\nAdd new modifications into MOD_DF\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nnew_mods\nlist\nlist of tuples. Tuple example:( modname@site:str (e.g. Mod@S), chemical compositions:str (e.g. “H(4)O(2)”), [optional] modloss compositions:str (e.g. “H(2)O(1)”),)" - }, - { - "objectID": "constants/element.html", - "href": "constants/element.html", - "title": "Atom element information", - "section": "", - "text": "EMPTY_DIST defines a “zero element”, its monoisotopic position is 0 with abundance 1. It is used for abundance convolution between different isotopes (see abundance_convolution).\n\nsource\n\ntruncate_isotope\n\n truncate_isotope (isotopes:numpy.ndarray, mono_idx:int)\n\nFor a given isotope distribution (intensity patterns), this function truncates the distribution by top MAX_ISOTOPE_LEN neighbors those contain the monoisotopic peak pointed by mono_idx.\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nisotopes\nndarray\nIsotope patterns with size > MAX_ISOTOPE_LEN.\n\n\nmono_idx\nint\nMonoisotopic peak position (index) in the isotope patterns\n\n\nReturns\ntuple\nthe new position of mono_idx\n\n\n\n\n\nLoad chemical element information\nFirst, we load alphadeep/constants/nist_element.yaml into CHEM_INFO_DICT, which is the base dict for further processing.\nThen we call reset_elements to extract corresponding information for CHEM_MONO_MASS (mono mass dict), CHEM_ISOTOPE_DIST (isotope distribution dict), and CHEM_MONO_IDX (dict of mono position in the isotope distribution).\nAt last, MASS_H2O and MASS_NH3 are re-calculated based on masses of H, O, and N in CHEM_MONO_MASS.\nAll these steps are done in load_elem_yaml(yaml_file).\n\nsource\n\n\nload_elem_yaml\n\n load_elem_yaml (yaml_file:str)\n\nLoad built-in or user-defined element yaml file. Default yaml is: os.path.join(_base_dir, ‘nist_element.yaml’)\n\nsource\n\n\nreset_elements\n\n reset_elements ()\n\n\n\nCalculate mass from a formula\nNow we have CHEM_MONO_MASS, we can calculate the mass of different chemical formula. Formula format: H(1)C(2)O(3)...\n\nsource\n\n\ncalc_mass_from_formula\n\n calc_mass_from_formula (formula:str)\n\nCalculates the mass of the formula`\n\n\n\n\nType\nDetails\n\n\n\n\nformula\nstr\ne.g. H(1)C(2)O(3)\n\n\nReturns\nfloat\nmass of the formula\n\n\n\n\nsource\n\n\nparse_formula\n\n parse_formula (formula:str)\n\nGiven a formula (str, e.g. H(1)C(2)O(3)), it generates [('H', 2), ('C', 2), ('O', 1)]\nExample" - }, - { - "objectID": "constants/isotope.html", - "href": "constants/isotope.html", - "title": "Isotope distribution", - "section": "", - "text": "source\n\nabundance_convolution\n\n abundance_convolution (d1:numpy.ndarray, mono1:int, d2:numpy.ndarray,\n mono2:int)\n\nIf we have two isotope distributions, we can convolute them into one distribution.\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nd1\nndarray\nisotope distribution to convolute\n\n\nmono1\nint\nmono position of d1.\n\n\nd2\nndarray\nisotope distribution to convolute\n\n\nmono2\nint\nmono position of d2\n\n\nReturns\ntyping.Tuple[numpy.ndarray, int]\nnp.ndarray, convoluted isotope distributionint, new mono position.\n\n\n\nFor a given chemical formula, e.g. H(100)O(50)N(20), we first calculate the isotope distribution using “binary search”-like method for each type of element (here are H(100), O(50) and N(20)) (see one_element_dist). And then we convolute these distributions of all types into one distribution (see formula_dist).\n\nsource\n\n\nformula_dist\n\n formula_dist (formula:Union[list,str])\n\nGenerate the isotope distribution and the mono index for a given formula (as a list, e.g. [('H', 2), ('C', 2), ('O', 1)]).\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nformula\ntyping.Union[list, str]\nchemical formula, could be str or list.If str: “H(1)N(2)O(3)”.If list: “[(‘H’,1),(‘H’,2),(‘H’,3)]”.\n\n\nReturns\ntyping.Tuple[numpy.ndarray, int]\nnp.ndarray, isotope distributionint, mono position\n\n\n\n\nsource\n\n\none_element_dist\n\n one_element_dist (elem:str, n:int,\n chem_isotope_dist:numba.typed.typeddict.Dict,\n chem_mono_idx:numba.typed.typeddict.Dict)\n\nCalculate the isotope distribution for an element and its numbers.\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nelem\nstr\nelement.\n\n\nn\nint\nelement number.\n\n\nchem_isotope_dist\nDict\nuse CHEM_ISOTOPE_DIST as parameter.\n\n\nchem_mono_idx\nDict\nuse CHEM_MONO_IDX as parameter.\n\n\nReturns\ntyping.Tuple[numpy.ndarray, int]\nnp.ndarray, isotope distribution of the element.int, mono position in the distribution\n\n\n\nCompare calculated isotope distributions with sisweb.com/mstools/isotope.htm\nDesired distribution for H10: (100, 0.16, 0.0001) calculated from sisweb.com/mstools/isotope.htm in low resolution mode (centroid mode)\nDesired distribution for C(100)H(100)O(10): (90.7784, 100, 56.368, 21.6475, 6.3624, 1.524, 0.3093) calculated from sisweb.com/mstools/isotope.htm in low resolution mode (centroid mode)\nThe target and calculated distributions are very similar\nCompare with Averagine\nTest for heavy labeled formula\n\n\nIsotopeDistribution\nformula_dist always calculates the distribution of each element based on the element number (using binary-search-like operation) and convolute distributions of different elements. If we have many peptides to calculate, each element’s distribution will be calculated repeatly. In IsotopeDistribution, instead of generating on-the-fly, we pre-built the isotope distribution table for each of the most common elements (C,H,N,O,S,P) with the element number from 0 to N, and N is large enough to cover all composition in shotgun proteomics. Thus, for a given chemical formula, we just need to check the distribution table for each element and convolute distributions among different elements.\n/Users/zengwenfeng/opt/anaconda3/lib/python3.8/site-packages/fastcore/docscrape.py:225: UserWarning: Unknown section Attributes\n else: warn(msg)\n\nsource\n\n\nIsotopeDistribution\n\n IsotopeDistribution (max_elem_num_dict:dict={'C': 2000, 'H': 5000, 'N':\n 1000, 'O': 1000, 'S': 200, 'P': 200})\n\nFaster calculation of isotope abundance distribution by pre-building isotope distribution tables for most common elements.\nWe have considered large enough number of elements for shotgun proteomics. We can increase max_elem_num_dict to support larger peptide or top-down in the future. However, current MAX_ISOTOPE_LEN is not suitable for top-down, it must be extended to a larger number (100?). Note that non-standard amino acids have 1000000 C elements in AlphaBase, We clip 1000000 C to the maximal number of C in max_elem_num_dict. As they have very large masses thus impossible to identify, their isotope distributions do not matter.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nmax_elem_num_dict\ndict\n{‘C’: 2000, ‘H’: 5000, ‘N’: 1000, ‘O’: 1000, ‘S’: 200, ‘P’: 200}\nDefine the maximal number of the elements. Defaults to { ‘C’: 2000, ‘H’: 5000, ‘N’: 1000, ‘O’: 1000, ‘S’: 200, ‘P’: 200, }\n\n\n\n/Users/zengwenfeng/opt/anaconda3/lib/python3.8/site-packages/fastcore/docscrape.py:225: UserWarning: Unknown section Examples\n else: warn(msg)\n\nsource\n\n\nIsotopeDistribution.calc_formula_distribution\n\n IsotopeDistribution.calc_formula_distribution\n (formula:List[Tuple[str,in\n t]])\n\nCalculate isotope abundance distribution for a given formula\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nformula\ntyping.List[typing.Tuple[str, int]]\nchemical formula: “[(‘H’,1),(‘C’,2),(‘O’,3)]”.\n\n\nReturns\ntyping.Tuple[numpy.ndarray, int]\nnp.ndarray, isotope abundance distributionint, monoisotope position in the distribution array\n\n\n\n\niso = IsotopeDistribution()\nformula = 'C(100)H(100)O(10)Na(1)Fe(1)'\nformula = parse_formula(formula)\ndist, mono = iso.calc_formula_distribution(formula)\ndist1, mono1 = formula_dist(formula)\nassert np.allclose(dist, dist1)\nassert mono==mono1\nassert mono==2\ndist\n\narray([1.92320044e-02, 2.10952666e-02, 3.13753566e-01, 3.42663681e-01,\n 1.95962632e-01, 7.69157517e-02, 2.31993814e-02, 5.71948249e-03,\n 1.19790438e-03, 2.18815385e-04])" - }, - { - "objectID": "constants/aa.html", - "href": "constants/aa.html", - "title": "Amino acid information", - "section": "", - "text": "The amino acid masses are stored in 128-lengh array AA_ASCII_MASS. If an ASCII code is not in AA_CHEM, the mass will be 1e8 to disable it for MS search.\nWe also provide a AA table (AA_DF dataframe) for users.\n\nsource\n\nreset_AA_df\n\n reset_AA_df ()\n\n\nsource\n\n\nreset_AA_mass\n\n reset_AA_mass ()\n\nAA mass in np.array with shape (128,)\n\nAA_DF.loc[ord('A'):ord('Z'),:]\n\n\n\n\n\n \n \n \n aa\n formula\n mass\n \n \n \n \n 65\n A\n C(3)H(5)N(1)O(1)S(0)\n 7.103711e+01\n \n \n 66\n B\n C(1000000)\n 1.200000e+07\n \n \n 67\n C\n C(3)H(5)N(1)O(1)S(1)\n 1.030092e+02\n \n \n 68\n D\n C(4)H(5)N(1)O(3)S(0)\n 1.150269e+02\n \n \n 69\n E\n C(5)H(7)N(1)O(3)S(0)\n 1.290426e+02\n \n \n 70\n F\n C(9)H(9)N(1)O(1)S(0)\n 1.470684e+02\n \n \n 71\n G\n C(2)H(3)N(1)O(1)S(0)\n 5.702146e+01\n \n \n 72\n H\n C(6)H(7)N(3)O(1)S(0)\n 1.370589e+02\n \n \n 73\n I\n C(6)H(11)N(1)O(1)S(0)\n 1.130841e+02\n \n \n 74\n J\n C(6)H(11)N(1)O(1)S(0)\n 1.130841e+02\n \n \n 75\n K\n C(6)H(12)N(2)O(1)S(0)\n 1.280950e+02\n \n \n 76\n L\n C(6)H(11)N(1)O(1)S(0)\n 1.130841e+02\n \n \n 77\n M\n C(5)H(9)N(1)O(1)S(1)\n 1.310405e+02\n \n \n 78\n N\n C(4)H(6)N(2)O(2)S(0)\n 1.140429e+02\n \n \n 79\n O\n C(12)H(19)N(3)O(2)\n 2.371477e+02\n \n \n 80\n P\n C(5)H(7)N(1)O(1)S(0)\n 9.705276e+01\n \n \n 81\n Q\n C(5)H(8)N(2)O(2)S(0)\n 1.280586e+02\n \n \n 82\n R\n C(6)H(12)N(4)O(1)S(0)\n 1.561011e+02\n \n \n 83\n S\n C(3)H(5)N(1)O(2)S(0)\n 8.703203e+01\n \n \n 84\n T\n C(4)H(7)N(1)O(2)S(0)\n 1.010477e+02\n \n \n 85\n U\n C(3)H(5)N(1)O(1)Se(1)\n 1.509536e+02\n \n \n 86\n V\n C(5)H(9)N(1)O(1)S(0)\n 9.906841e+01\n \n \n 87\n W\n C(11)H(10)N(2)O(1)S(0)\n 1.860793e+02\n \n \n 88\n X\n C(1000000)\n 1.200000e+07\n \n \n 89\n Y\n C(9)H(9)N(1)O(2)S(0)\n 1.630633e+02\n \n \n 90\n Z\n C(1000000)\n 1.200000e+07\n \n \n\n\n\n\ncalc_sequence_mass can easily get the mass list of each amino acid. The key is: np.array(sequence, 'c').view(np.int8) converts a string into an ASCII code array\nNote that this function is rarely used in alphabase as it is not fast for a set of peptides.\n\nsource\n\n\ncalc_sequence_mass\n\n calc_sequence_mass (sequence:str)\n\n\n\n\n\nType\nDetails\n\n\n\n\nsequence\nstr\nUnmodified peptide sequence\n\n\nReturns\nndarray\nMasses of each amino acid.\n\n\n\nWe provide calc_AA_masses_for_same_len_seqs and calc_sequence_masses_for_same_len_seqs functions to fast calculate masses for a given array of AA sequences with same length. They are fast because they both use slicing and reshape operation based on AA_ASCII_MASS array.\n/Users/zengwenfeng/opt/anaconda3/lib/python3.8/site-packages/fastcore/docscrape.py:225: UserWarning: potentially wrong underline length... \nRaises \n------- in \nCalculate sequence masses for the array of same-len AA sequences.\n...\n else: warn(msg)\n/Users/zengwenfeng/opt/anaconda3/lib/python3.8/site-packages/fastcore/docscrape.py:225: UserWarning: Unknown section Raises\n else: warn(msg)\n\nsource\n\n\ncalc_sequence_masses_for_same_len_seqs\n\n calc_sequence_masses_for_same_len_seqs (sequence_array:numpy.ndarray)\n\nCalculate sequence masses for the array of same-len AA sequences.\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nsequence_array\nndarray\nunmodified sequences with the same length.\n\n\nReturns\nndarray\n1-D (array_size, sequence_len) array of masses.\n\n\n\n/Users/zengwenfeng/opt/anaconda3/lib/python3.8/site-packages/fastcore/docscrape.py:225: UserWarning: potentially wrong underline length... \nRaises \n------- in \nCalculate AA masses for the array of same-len AA sequences.\n...\n else: warn(msg)\n\nsource\n\n\ncalc_AA_masses_for_same_len_seqs\n\n calc_AA_masses_for_same_len_seqs (sequence_array:numpy.ndarray)\n\nCalculate AA masses for the array of same-len AA sequences.\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nsequence_array\nndarray\nunmodified sequences with the same length.\n\n\nReturns\nndarray\n2-D (array_size, sequence_len) array of masses.\n\n\n\nFor a single sequence\n\nassert np.allclose(\n calc_sequence_mass('ACDEFGNYK'),\n [ 71.03711379, 103.00918496, 115.02694302, 129.04259309,\n 147.06841391, 57.02146372, 114.04292744, 163.06332853,\n 128.09496302 ]\n)\n\nFor sequences with the same length\nIt is very easy to generate b/y ions from a sequence or a list of sequences with same length\n\naa_masses = calc_AA_masses_for_same_len_seqs(['ACDEFGHIK','BCDEFGHIK','CCDEFGHIK'])\nb_masses = np.cumsum(aa_masses, axis=1)\nb_masses, pepmass = b_masses[:,:-1], b_masses[:,-1:]\npepmass += MASS_H2O\n{'pepmass':pepmass, 'b masses':b_masses, 'y masses':pepmass-b_masses}\n\n{'pepmass': array([[1.01845422e+03],\n [1.20009474e+07],\n [1.05042629e+03]]),\n 'b masses': array([[7.10371138e+01, 1.74046299e+02, 2.89073242e+02, 4.18115835e+02,\n 5.65184249e+02, 6.22205712e+02, 7.59264624e+02, 8.72348688e+02],\n [1.20000000e+07, 1.20001030e+07, 1.20002180e+07, 1.20003471e+07,\n 1.20004941e+07, 1.20005512e+07, 1.20006882e+07, 1.20008013e+07],\n [1.03009185e+02, 2.06018370e+02, 3.21045313e+02, 4.50087906e+02,\n 5.97156320e+02, 6.54177784e+02, 7.91236696e+02, 9.04320760e+02]]),\n 'y masses': array([[947.41710224, 844.40791728, 729.38097426, 600.33838117,\n 453.26996726, 396.24850354, 259.18959168, 146.1055277 ],\n [947.41710224, 844.40791728, 729.38097426, 600.33838117,\n 453.26996726, 396.24850354, 259.18959168, 146.1055277 ],\n [947.41710224, 844.40791728, 729.38097426, 600.33838117,\n 453.26996726, 396.24850354, 259.18959168, 146.1055277 ]])}\n\n\ncalc_AA_masses_for_var_len_seqs is rarely used in alphabase.\n\nsource\n\n\ncalc_AA_masses_for_var_len_seqs\n\n calc_AA_masses_for_var_len_seqs (sequence_array:numpy.ndarray)\n\nWe recommend to use calc_AA_masses_for_same_len_seqs as it is much faster.\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nsequence_array\nndarray\nSequences with variable lengths.\n\n\nReturns\nndarray\n1D array of masses, zero values are padded to fill the max length.\n\n\n\n\nmasses = calc_AA_masses_for_var_len_seqs(['EFGHIK','AAAGCDEFGHIK','DDDDCCDEFGHIK'])\nmasses\n\narray([[1.29042593e+02, 1.47068414e+02, 5.70214637e+01, 1.37058912e+02,\n 1.13084064e+02, 1.28094963e+02, 1.00000000e+08, 1.00000000e+08,\n 1.00000000e+08, 1.00000000e+08, 1.00000000e+08, 1.00000000e+08,\n 1.00000000e+08],\n [7.10371138e+01, 7.10371138e+01, 7.10371138e+01, 5.70214637e+01,\n 1.03009185e+02, 1.15026943e+02, 1.29042593e+02, 1.47068414e+02,\n 5.70214637e+01, 1.37058912e+02, 1.13084064e+02, 1.28094963e+02,\n 1.00000000e+08],\n [1.15026943e+02, 1.15026943e+02, 1.15026943e+02, 1.15026943e+02,\n 1.03009185e+02, 1.03009185e+02, 1.15026943e+02, 1.29042593e+02,\n 1.47068414e+02, 5.70214637e+01, 1.37058912e+02, 1.13084064e+02,\n 1.28094963e+02]])" - }, - { - "objectID": "protein/fasta.html", - "href": "protein/fasta.html", - "title": "Protein and Peptide Processing", - "section": "", - "text": "source\n\nconcat_proteins\n\n concat_proteins (protein_dict:dict, sep='$')\n\nConcatenate all protein sequences into a single sequence, seperated by sep ($ by default).\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nprotein_dict\ndict\n\nprotein_dict by read_fasta_file()\n\n\nsep\nstr\n$\n\n\n\nReturns\nstr\n\nconcatenated sequence seperated by sep.\n\n\n\n\nsource\n\n\nload_all_proteins\n\n load_all_proteins (fasta_file_list:list)\n\n/Users/zengwenfeng/opt/anaconda3/lib/python3.8/site-packages/fastcore/docscrape.py:225: UserWarning: Unknown section Yields\n else: warn(msg)\n\nsource\n\n\nread_fasta_file\n\n read_fasta_file (fasta_filename:str='')\n\nRead a FASTA file line by line\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nfasta_filename\nstr\n\nfasta.\n\n\n\n\nsource\n\n\nget_uniprot_gene_name\n\n get_uniprot_gene_name (description:str)\n\n\nsource\n\n\nDigest\n\n Digest (protease:str='trypsin/P', max_missed_cleavages:int=2,\n peptide_length_min:int=6, peptide_length_max:int=45)\n\nDigest a protein sequence\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nprotease\nstr\ntrypsin/P\nprotease name, could be pre-defined name defined in protease_dictor a regular expression. By default ‘trypsin/P’\n\n\nmax_missed_cleavages\nint\n2\nMax number of misses cleavage sites.By default 2\n\n\npeptide_length_min\nint\n6\nMinimal cleaved peptide length, by default 6\n\n\npeptide_length_max\nint\n45\nMaximal cleaved peptide length, by default 45\n\n\n\n\nsource\n\n\ncleave_sequence_with_cut_pos\n\n cleave_sequence_with_cut_pos (sequence:str, cut_pos:numpy.ndarray,\n n_missed_cleavages:int=2,\n pep_length_min:int=6,\n pep_length_max:int=45)\n\nCleave a sequence with cut postions (cut_pos). Filters to have a minimum and maximum length.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nsequence\nstr\n\nprotein sequence\n\n\ncut_pos\nndarray\n\ncut postions determined by a given protease.\n\n\nn_missed_cleavages\nint\n2\nthe number of max missed cleavages.\n\n\npep_length_min\nint\n6\nmin peptide length.\n\n\npep_length_max\nint\n45\nmax peptide length.\n\n\nReturns\ntuple\n\nList[str]. Cleaved peptide sequences with missed cleavages.List[int]. Number of miss cleavage of each peptide.List[bool]. If N-term peptideList[bool]. If C-term pepetide\n\n\n\n\nsource\n\n\nDigest.cleave_sequence\n\n Digest.cleave_sequence (sequence:str)\n\nCleave a sequence.\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nsequence\nstr\nthe given (protein) sequence.\n\n\nReturns\ntuple\nlist[str]: cleaved peptide sequences with missed cleavageslist[int]: miss cleavage listlist[bool]: is protein N-termlist[bool]: is protein C-term\n\n\n\n\nsource\n\n\nget_fix_mods\n\n get_fix_mods (sequence:str, fix_mod_aas:str, fix_mod_dict:dict)\n\nGenerate fix modifications for the sequence\n\nseq = 'ACBCDCK'\n_fix_mod_dict = {}\n_fix_mod_dict['C'] = 'mod@C'\nmods, mod_sites = get_fix_mods(seq, 'C', _fix_mod_dict)\nassert mods==';'.join(['mod@C']*3)\nassert mod_sites=='2;4;6'\nget_fix_mods(seq, 'C', _fix_mod_dict)\n\n('mod@C;mod@C;mod@C', '2;4;6')\n\n\n\nsource\n\n\nget_var_mod_sites\n\n get_var_mod_sites (sequence:str, target_mod_aas:str, max_var_mod:int,\n max_combs:int)\n\nget all combinations of variable modification sites\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nsequence\nstr\npeptide sequence\n\n\ntarget_mod_aas\nstr\nAAs that may have modifications\n\n\nmax_var_mod\nint\nmax number of mods in a sequence\n\n\nmax_combs\nint\nmax number of combinations for a sequence\n\n\nReturns\nlist\nlist of combinations (tuple) of modification sites \n\n\n\n\nsource\n\n\nget_candidate_sites\n\n get_candidate_sites (sequence:str, target_mod_aas:str)\n\nget candidate modification sites\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nsequence\nstr\npeptide sequence\n\n\ntarget_mod_aas\nstr\nAAs that may have modifications\n\n\nReturns\nlist\ncandiadte mod sites in alphabase format (0: N-term, -1: C-term, 1-n:others)\n\n\n\n\nseq = 'AMCMSTYK'\ncandidate_sites = get_candidate_sites(seq, 'MSTY')\nassert np.all(np.array(candidate_sites)==np.array([2,4,5,6,7]))\nget_var_mod_sites(seq, 'MSTY', 3, 20)\n\n[(2,),\n (4,),\n (5,),\n (6,),\n (7,),\n (2, 4),\n (2, 5),\n (2, 6),\n (2, 7),\n (4, 5),\n (4, 6),\n (4, 7),\n (5, 6),\n (5, 7),\n (6, 7),\n (2, 4, 5),\n (2, 4, 6),\n (2, 4, 7),\n (2, 5, 6),\n (2, 5, 7)]\n\n\n\nsource\n\n\nget_var_mods\n\n get_var_mods (sequence:str, var_mod_aas:str, mod_dict:dict,\n max_var_mod:int, max_combs:int, keep_unmodified:bool=False)\n\nGenerate all modification combinations and associated sites for the sequence.\n\nsource\n\n\nget_var_mods_per_sites_single_mod_on_aa\n\n get_var_mods_per_sites_single_mod_on_aa (sequence:str, mod_sites:tuple,\n var_mod_dict:dict)\n\nUsed when the var mod list contains only one mods on the each AA, for example: Mod1@A, Mod2@D …\n\nsource\n\n\nget_var_mods_per_sites_multi_mods_on_aa\n\n get_var_mods_per_sites_multi_mods_on_aa (sequence:str, mod_sites:tuple,\n var_mod_dict:dict)\n\nUsed only when the var mod list contains more than one mods on the same AA, for example: Mod1@A, Mod2@A …\n\nsource\n\n\nparse_term_mod\n\n parse_term_mod (term_mod_name:str)\n\n\nsource\n\n\ncreate_labeling_peptide_df\n\n create_labeling_peptide_df (peptide_df:pandas.core.frame.DataFrame,\n labels:list)\n\n\nsource\n\n\nparse_labels\n\n parse_labels (labels:list)\n\n\nsource\n\n\nadd_single_peptide_labeling\n\n add_single_peptide_labeling (seq:str, mods:str, mod_sites:str,\n label_aas:str, label_mod_dict:dict,\n nterm_label_mod:str, cterm_label_mod:str)\n\n\nsource\n\n\nprotein_idxes_to_names\n\n protein_idxes_to_names (protein_idxes:str, protein_names:list)\n\n\nsource\n\n\nappend_regular_modifications\n\n append_regular_modifications (df:pandas.core.frame.DataFrame,\n var_mods=['Phospho@S', 'Phospho@T',\n 'Phospho@Y'], max_mod_num=1, max_combs=100,\n keep_unmodified=True,\n cannot_modify_pep_nterm_aa:bool=False,\n cannot_modify_pep_cterm_aa:bool=False)\n\nAppend regular (not N/C-term) variable modifications to the exsiting modifications of each sequence in df.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ndf\nDataFrame\n\nPrecursor dataframe\n\n\nvar_mods\nlist\n[‘Phospho@S’, ‘Phospho@T’, ‘Phospho@Y’]\nConsidered varialbe modification list. Defaults to [‘Phospho@S’,‘Phospho@T’,‘Phospho@Y’].\n\n\nmax_mod_num\nint\n1\nMaximal modification number for each sequence of the var_mods. Defaults to 1.\n\n\nmax_combs\nint\n100\nOne sequence is only allowed to explode to max_combs number of modified peptides. Defaults to 100.\n\n\nkeep_unmodified\nbool\nTrue\nIf unmodified (only refered to var_mods)peptides are also remained in the returned dataframe. Defaults to True.\n\n\ncannot_modify_pep_nterm_aa\nbool\nFalse\nSimilar to cannot_modify_pep_cterm_aa, by default False\n\n\ncannot_modify_pep_cterm_aa\nbool\nFalse\nIf the modified AA is at C-term, then the modification cannot modified it.For example GlyGly@K, for a peptide ACDKEFGK, if GlyGly is at the C-term, trypsin cannot cleave the C-term K, hence there will be no such a modified peptide ACDKEFGK(GlyGly).by default False\n\n\nReturns\nDataFrame\n\nThe precursor_df with new modification added.\n\n\n\n\nsource\n\n\nFastaLib\n\n FastaLib (charged_frag_types:list=['b_z1', 'b_z2', 'y_z1', 'y_z2'],\n protease:str='trypsin/P', max_missed_cleavages:int=2,\n peptide_length_min:int=7, peptide_length_max:int=35,\n precursor_charge_min:int=2, precursor_charge_max:int=4,\n precursor_mz_min:float=200.0, precursor_mz_max:float=2000.0,\n var_mods:list=['Acetyl@Protein N-term', 'Oxidation@M'],\n max_var_mod_num:int=2, fix_mods:list=['Carbamidomethyl@C'],\n decoy:str=None, I_to_L=False)\n\nClass to process fasta files and generate libraries, including: - Digest protein sequences - Add fixed, variable or labeling modifications to the peptide sequences - Add charge states - Append decoy peptides - Save libraries into hdf file\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ncharged_frag_types\nlist\n[‘b_z1’, ‘b_z2’, ‘y_z1’, ‘y_z2’]\nFragment types with charge, by default [ ‘b_z1’,‘b_z2’,‘y_z1’, ‘y_z2’ ]\n\n\nprotease\nstr\ntrypsin/P\nCould be pre-defined protease name defined in protease_dict,or a regular expression. By default ‘trypsin/P’\n\n\nmax_missed_cleavages\nint\n2\nMaximal missed cleavages, by default 2\n\n\npeptide_length_min\nint\n7\nMinimal cleaved peptide length, by default 7\n\n\npeptide_length_max\nint\n35\nMaximal cleaved peptide length, by default 35\n\n\nprecursor_charge_min\nint\n2\nMinimal precursor charge, by default 2\n\n\nprecursor_charge_max\nint\n4\nMaximal precursor charge, by default 4\n\n\nprecursor_mz_min\nfloat\n200.0\nMinimal precursor mz, by default 200.0\n\n\nprecursor_mz_max\nfloat\n2000.0\nMaximal precursor mz, by default 2000.0\n\n\nvar_mods\nlist\n[‘Acetyl@Protein N-term’, ‘Oxidation@M’]\nlist of variable modifications, by default [‘Acetyl@Protein N-term’,‘Oxidation@M’]\n\n\nmax_var_mod_num\nint\n2\nMaximal number of variable modifications on a peptide sequence, by default 2\n\n\nfix_mods\nlist\n[‘Carbamidomethyl@C’]\nlist of fixed modifications, by default [‘Carbamidomethyl@C’]\n\n\ndecoy\nstr\nNone\nor pseudo_reverse or diann\n\n\nI_to_L\nbool\nFalse\n\n\n\n\n\nsource\n\n\nFastaLib.add_modifications\n\n FastaLib.add_modifications ()\n\nAdd fixed and variable modifications to all peptide sequences in self.precursor_df\n\nsource\n\n\nFastaLib.add_additional_modifications\n\n FastaLib.add_additional_modifications (var_mods=['Phospho@S',\n 'Phospho@T', 'Phospho@Y'],\n max_mod_num:int=1,\n max_combs:int=100,\n keep_unmodified:bool=True, cannot_\n modify_pep_nterm_aa:bool=False, ca\n nnot_modify_pep_cterm_aa:bool=Fals\n e)\n\nAdd external defined variable modifications to all peptide sequences in self.precursor_df. See append_regular_modifications for details\n\nsource\n\n\nFastaLib.add_mods_for_one_seq\n\n FastaLib.add_mods_for_one_seq (sequence:str, is_prot_nterm,\n is_prot_cterm)\n\nAdd fixed and variable modifications to a sequence\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nsequence\nstr\nPeptide sequence\n\n\nis_prot_nterm\nbool\nif protein N-term\n\n\nis_prot_cterm\nbool\nif protein C-term\n\n\nReturns\ntuple\nlist[str]: list of modification nameslist[str]: list of modification sites\n\n\n\n\nsource\n\n\nFastaLib.add_peptide_labeling\n\n FastaLib.add_peptide_labeling (labeling_channel_dict:dict)\n\nAdd labeling onto peptides inplace of self._precursor_df\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nlabeling_channel_dict\ndict\nFor example:{ ‘reference’: [], # not labelled for reference ‘0’: [‘Dimethyl@Any N-term’,‘Dimethyl@K’], ‘4’: [‘Dimethyl:2H(4)@Any N-term’,‘Dimethyl:2H(4)@K’], ‘8’: [‘Dimethyl:2H(6)13C(2)@Any N-term’,‘Dimethyl:2H(6)13C(2)@K’],}.The key name could be arbitrary distinguished strings for channel name,and value must be a list of modification names (str) in alphabase format.\n\n\n\n\nsource\n\n\nSpecLibBase.append_decoy_sequence\n\n SpecLibBase.append_decoy_sequence ()\n\nAppend decoy sequence into precursor_df. Decoy method is based on self.decoy(str).\ndecoy_lib = (\n decoy_lib_provider.get_decoy_lib(\n self.decoy, self\n )\n)\ndecoy_lib.decoy_sequence()\n...\n\nsource\n\n\nFastaLib.get_peptides_from_fasta\n\n FastaLib.get_peptides_from_fasta (fasta_file:Union[str,list])\n\nLoad peptide sequences from fasta files.\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nfasta_file\ntyping.Union[str, list]\nCould be a fasta file (str) or a list of fasta files (list[str])\n\n\n\n\nsource\n\n\nFastaLib.get_peptides_from_protein_dict\n\n FastaLib.get_peptides_from_protein_dict (protein_dict:dict)\n\nCleave the protein sequences in protein_dict.\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nprotein_dict\ndict\nFormat:{ ‘prot_id1’: ‘protein_id’: ‘prot_id1’ ‘sequence’: string ‘gene_name’: string ‘description’: string ‘prot_id2’: …}\n\n\n\n\nsource\n\n\nFastaLib.get_peptides_from_peptide_sequence_list\n\n FastaLib.get_peptides_from_peptide_sequence_list (pep_seq_list:list,\n protein_list:list=None)\n\n\nsource\n\n\nFastaLib.import_and_process_fasta\n\n FastaLib.import_and_process_fasta (fasta_files:Union[str,list])\n\nImport and process a fasta file or a list of fasta files. It includes: - Load the fasta file(s) - Append decoy peptide sequences - Add modifications to peptides - Add charge\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nfasta_files\ntyping.Union[str, list]\nA fasta file or a list of fasta files\n\n\n\n\nsource\n\n\nFastaLib.import_and_process_protein_dict\n\n FastaLib.import_and_process_protein_dict (protein_dict:dict)\n\nImport the protein_dict instead of fasta files.\nprotein_dict = load_all_proteins(fasta_files)\n\n\n\n\n\n\n\n\n\nType\nDetails\n\n\n\n\nprotein_dict\ndict\nFormat:{ ‘prot_id1’: ‘protein_id’: ‘prot_id1’ ‘sequence’: string ‘gene_name’: string ‘description’: string ‘prot_id2’: …}\n\n\n\n\nsource\n\n\nFastaLib.import_and_process_peptide_sequences\n\n FastaLib.import_and_process_peptide_sequences (pep_seq_list:list,\n protein_list:list=None)\n\nImporting peptide sequences instead of proteins\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\npep_seq_list\nlist\n\nPeptide sequence list\n\n\nprotein_list\nlist\nNone\nProtein id list which maps to pep_seq_list one-by-one, by default None\n\n\n\n\nsource\n\n\nFastaLib.save_hdf\n\n FastaLib.save_hdf (hdf_file:str)\n\nSave the contents into hdf file (attribute -> hdf_file): - self.precursor_df -> library/precursor_df - self.protein_df -> library/protein_df - self.fragment_mz_df -> library/fragment_mz_df - self.fragment_intensity_df -> library/fragment_intensity_df\n\n\n\n\nType\nDetails\n\n\n\n\nhdf_file\nstr\nThe hdf file path\n\n\n\n\nsource\n\n\nFastaLib.load_hdf\n\n FastaLib.load_hdf (hdf_file:str, load_mod_seq:bool=False)\n\nLoad contents from hdf file: - self.precursor_df <- library/precursor_df - self.precursor_df <- library/mod_seq_df if load_mod_seq is True - self.protein_df <- library/protein_df - self.fragment_mz_df <- library/fragment_mz_df - self.fragment_intensity_df <- library/fragment_intensity_df\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\nhdf_file\nstr\n\nhdf file path\n\n\nload_mod_seq\nbool\nFalse\nAfter library is generated with hash values (int64) for sequences (str) and modifications (str),we don’t need sequence information for searching. So we can skip loading sequences to make the loading much faster.By default False\n\n\n\n\n\nTesting\n\ndf = pd.DataFrame(\n {\n 'sequence': ['ABSTY','ACXSX','ACDEFG'],\n 'mods': ['', 'Acetyl@Protein N-term', ''],\n 'mod_sites': ['', '0', '']\n }\n)\ndf = append_regular_modifications(df, keep_unmodified=True)\nassert np.sum(df.sequence=='ABSTY')==4\nassert np.sum(df.sequence=='ACXSX')==2\nassert np.sum(df.sequence=='ACDEFG')==1\nassert all(df[df.sequence=='ABSTY'].mods.values == np.array(['Phospho@S','Phospho@T','Phospho@Y','']))\nassert all(df[df.sequence=='ABSTY'].mod_sites.values == np.array(['3','4','5','']))\nassert all(df[df.sequence=='ACXSX'].mods.values == np.array(['Acetyl@Protein N-term;Phospho@S','Acetyl@Protein N-term']))\nassert all(df[df.sequence=='ACXSX'].mod_sites.values == np.array(['0;4','0']))\ndf\n\n\n\n\n\n \n \n \n sequence\n mods\n mod_sites\n \n \n \n \n 0\n ABSTY\n Phospho@S\n 3\n \n \n 1\n ABSTY\n Phospho@T\n 4\n \n \n 2\n ABSTY\n Phospho@Y\n 5\n \n \n 3\n ABSTY\n \n \n \n \n 4\n ACXSX\n Acetyl@Protein N-term;Phospho@S\n 0;4\n \n \n 5\n ACXSX\n Acetyl@Protein N-term\n 0\n \n \n 6\n ACDEFG\n \n \n \n \n\n\n\n\n\ndf = pd.DataFrame(\n {\n 'sequence': ['ABSTY','ACXSX','ACDEFG'],\n 'mods': ['', 'Acetyl@Protein N-term', ''],\n 'mod_sites': ['', '0', '']\n }\n)\ndf = append_regular_modifications(df, keep_unmodified=False)\nassert np.sum(df.sequence=='ABSTY')==3\nassert np.sum(df.sequence=='ACXSX')==1\nassert np.sum(df.sequence=='ACDEFG')==0\ndf\n\n\n\n\n\n \n \n \n sequence\n mods\n mod_sites\n \n \n \n \n 0\n ABSTY\n Phospho@S\n 3\n \n \n 1\n ABSTY\n Phospho@T\n 4\n \n \n 2\n ABSTY\n Phospho@Y\n 5\n \n \n 3\n ACXSX\n Acetyl@Protein N-term;Phospho@S\n 0;4\n \n \n\n\n\n\n\n_lib = FastaLib(None, I_to_L=False, decoy='pseudo_reverse')\nprot1 = 'MABCDESTKAFGHIJKLMNOPQRAFGHIJK'\nprot2 = 'AFGHIJKLMNOPQR'\nprotein_dict = {\n 'xx': {\n 'protein_id': 'xx',\n 'gene_name': '',\n 'sequence': prot1\n },\n 'yy': {\n 'protein_id': 'yy',\n 'gene_name': 'gene',\n 'sequence': prot2\n }\n}\n_lib.get_peptides_from_protein_dict(protein_dict)\n_lib.precursor_df\n\n\n\n\n\n \n \n \n sequence\n protein_idxes\n miss_cleavage\n is_prot_nterm\n is_prot_cterm\n mods\n mod_sites\n nAA\n \n \n \n \n 0\n AFGHIJK\n 0;1\n 0\n True\n True\n \n \n 7\n \n \n 1\n LMNOPQR\n 0;1\n 0\n False\n True\n \n \n 7\n \n \n 2\n ABCDESTK\n 0\n 0\n True\n False\n \n \n 8\n \n \n 3\n MABCDESTK\n 0\n 0\n True\n False\n \n \n 9\n \n \n 4\n AFGHIJKLMNOPQR\n 0;1\n 1\n True\n True\n \n \n 14\n \n \n 5\n LMNOPQRAFGHIJK\n 0\n 1\n False\n True\n \n \n 14\n \n \n 6\n ABCDESTKAFGHIJK\n 0\n 1\n True\n False\n \n \n 15\n \n \n 7\n MABCDESTKAFGHIJK\n 0\n 1\n True\n False\n \n \n 16\n \n \n 8\n AFGHIJKLMNOPQRAFGHIJK\n 0\n 2\n False\n True\n \n \n 21\n \n \n 9\n ABCDESTKAFGHIJKLMNOPQR\n 0\n 2\n True\n False\n \n \n 22\n \n \n 10\n MABCDESTKAFGHIJKLMNOPQR\n 0\n 2\n True\n False\n \n \n 23\n \n \n\n\n\n\n\n_lib.protein_df\n\n\n\n\n\n \n \n \n protein_id\n gene_name\n sequence\n \n \n \n \n 0\n xx\n \n MABCDESTKAFGHIJKLMNOPQRAFGHIJK\n \n \n 1\n yy\n gene\n AFGHIJKLMNOPQR\n \n \n\n\n\n\n\n_lib.append_protein_name()\nassert 'proteins' in _lib.precursor_df.columns\n_lib.precursor_df\n\n\n\n\n\n \n \n \n sequence\n protein_idxes\n miss_cleavage\n is_prot_nterm\n is_prot_cterm\n mods\n mod_sites\n nAA\n proteins\n genes\n \n \n \n \n 0\n AFGHIJK\n 0;1\n 0\n True\n True\n \n \n 7\n xx;yy\n gene\n \n \n 1\n LMNOPQR\n 0;1\n 0\n False\n True\n \n \n 7\n xx;yy\n gene\n \n \n 2\n ABCDESTK\n 0\n 0\n True\n False\n \n \n 8\n xx\n \n \n \n 3\n MABCDESTK\n 0\n 0\n True\n False\n \n \n 9\n xx\n \n \n \n 4\n AFGHIJKLMNOPQR\n 0;1\n 1\n True\n True\n \n \n 14\n xx;yy\n gene\n \n \n 5\n LMNOPQRAFGHIJK\n 0\n 1\n False\n True\n \n \n 14\n xx\n \n \n \n 6\n ABCDESTKAFGHIJK\n 0\n 1\n True\n False\n \n \n 15\n xx\n \n \n \n 7\n MABCDESTKAFGHIJK\n 0\n 1\n True\n False\n \n \n 16\n xx\n \n \n \n 8\n AFGHIJKLMNOPQRAFGHIJK\n 0\n 2\n False\n True\n \n \n 21\n xx\n \n \n \n 9\n ABCDESTKAFGHIJKLMNOPQR\n 0\n 2\n True\n False\n \n \n 22\n xx\n \n \n \n 10\n MABCDESTKAFGHIJKLMNOPQR\n 0\n 2\n True\n False\n \n \n 23\n xx\n \n \n \n\n\n\n\n\n_lib.add_modifications()\n_lib.precursor_df\n\n\n\n\n\n \n \n \n sequence\n protein_idxes\n miss_cleavage\n is_prot_nterm\n is_prot_cterm\n mods\n mod_sites\n nAA\n proteins\n genes\n \n \n \n \n 0\n AFGHIJK\n 0;1\n 0\n True\n True\n \n \n 7\n xx;yy\n gene\n \n \n 1\n AFGHIJK\n 0;1\n 0\n True\n True\n Acetyl@Protein N-term\n 0\n 7\n xx;yy\n gene\n \n \n 2\n LMNOPQR\n 0;1\n 0\n False\n True\n Oxidation@M\n 2\n 7\n xx;yy\n gene\n \n \n 3\n LMNOPQR\n 0;1\n 0\n False\n True\n \n \n 7\n xx;yy\n gene\n \n \n 4\n ABCDESTK\n 0\n 0\n True\n False\n Carbamidomethyl@C\n 3\n 8\n xx\n \n \n \n 5\n ABCDESTK\n 0\n 0\n True\n False\n Carbamidomethyl@C;Acetyl@Protein N-term\n 3;0\n 8\n xx\n \n \n \n 6\n MABCDESTK\n 0\n 0\n True\n False\n Carbamidomethyl@C;Oxidation@M\n 4;1\n 9\n xx\n \n \n \n 7\n MABCDESTK\n 0\n 0\n True\n False\n Carbamidomethyl@C\n 4\n 9\n xx\n \n \n \n 8\n MABCDESTK\n 0\n 0\n True\n False\n Carbamidomethyl@C;Acetyl@Protein N-term;Oxidat...\n 4;0;1\n 9\n xx\n \n \n \n 9\n MABCDESTK\n 0\n 0\n True\n False\n Carbamidomethyl@C;Acetyl@Protein N-term\n 4;0\n 9\n xx\n \n \n \n 10\n AFGHIJKLMNOPQR\n 0;1\n 1\n True\n True\n Oxidation@M\n 9\n 14\n xx;yy\n gene\n \n \n 11\n AFGHIJKLMNOPQR\n 0;1\n 1\n True\n True\n \n \n 14\n xx;yy\n gene\n \n \n 12\n AFGHIJKLMNOPQR\n 0;1\n 1\n True\n True\n Acetyl@Protein N-term;Oxidation@M\n 0;9\n 14\n xx;yy\n gene\n \n \n 13\n AFGHIJKLMNOPQR\n 0;1\n 1\n True\n True\n Acetyl@Protein N-term\n 0\n 14\n xx;yy\n gene\n \n \n 14\n LMNOPQRAFGHIJK\n 0\n 1\n False\n True\n Oxidation@M\n 2\n 14\n xx\n \n \n \n 15\n LMNOPQRAFGHIJK\n 0\n 1\n False\n True\n \n \n 14\n xx\n \n \n \n 16\n ABCDESTKAFGHIJK\n 0\n 1\n True\n False\n Carbamidomethyl@C\n 3\n 15\n xx\n \n \n \n 17\n ABCDESTKAFGHIJK\n 0\n 1\n True\n False\n Carbamidomethyl@C;Acetyl@Protein N-term\n 3;0\n 15\n xx\n \n \n \n 18\n MABCDESTKAFGHIJK\n 0\n 1\n True\n False\n Carbamidomethyl@C;Oxidation@M\n 4;1\n 16\n xx\n \n \n \n 19\n MABCDESTKAFGHIJK\n 0\n 1\n True\n False\n Carbamidomethyl@C\n 4\n 16\n xx\n \n \n \n 20\n MABCDESTKAFGHIJK\n 0\n 1\n True\n False\n Carbamidomethyl@C;Acetyl@Protein N-term;Oxidat...\n 4;0;1\n 16\n xx\n \n \n \n 21\n MABCDESTKAFGHIJK\n 0\n 1\n True\n False\n Carbamidomethyl@C;Acetyl@Protein N-term\n 4;0\n 16\n xx\n \n \n \n 22\n AFGHIJKLMNOPQRAFGHIJK\n 0\n 2\n False\n True\n Oxidation@M\n 9\n 21\n xx\n \n \n \n 23\n AFGHIJKLMNOPQRAFGHIJK\n 0\n 2\n False\n True\n \n \n 21\n xx\n \n \n \n 24\n ABCDESTKAFGHIJKLMNOPQR\n 0\n 2\n True\n False\n Carbamidomethyl@C;Oxidation@M\n 3;17\n 22\n xx\n \n \n \n 25\n ABCDESTKAFGHIJKLMNOPQR\n 0\n 2\n True\n False\n Carbamidomethyl@C\n 3\n 22\n xx\n \n \n \n 26\n ABCDESTKAFGHIJKLMNOPQR\n 0\n 2\n True\n False\n Carbamidomethyl@C;Acetyl@Protein N-term;Oxidat...\n 3;0;17\n 22\n xx\n \n \n \n 27\n ABCDESTKAFGHIJKLMNOPQR\n 0\n 2\n True\n False\n Carbamidomethyl@C;Acetyl@Protein N-term\n 3;0\n 22\n xx\n \n \n \n 28\n MABCDESTKAFGHIJKLMNOPQR\n 0\n 2\n True\n False\n Carbamidomethyl@C;Oxidation@M\n 4;1\n 23\n xx\n \n \n \n 29\n MABCDESTKAFGHIJKLMNOPQR\n 0\n 2\n True\n False\n Carbamidomethyl@C;Oxidation@M\n 4;18\n 23\n xx\n \n \n \n 30\n MABCDESTKAFGHIJKLMNOPQR\n 0\n 2\n True\n False\n Carbamidomethyl@C;Oxidation@M;Oxidation@M\n 4;1;18\n 23\n xx\n \n \n \n 31\n MABCDESTKAFGHIJKLMNOPQR\n 0\n 2\n True\n False\n Carbamidomethyl@C\n 4\n 23\n xx\n \n \n \n 32\n MABCDESTKAFGHIJKLMNOPQR\n 0\n 2\n True\n False\n Carbamidomethyl@C;Acetyl@Protein N-term;Oxidat...\n 4;0;1\n 23\n xx\n \n \n \n 33\n MABCDESTKAFGHIJKLMNOPQR\n 0\n 2\n True\n False\n Carbamidomethyl@C;Acetyl@Protein N-term;Oxidat...\n 4;0;18\n 23\n xx\n \n \n \n 34\n MABCDESTKAFGHIJKLMNOPQR\n 0\n 2\n True\n False\n Carbamidomethyl@C;Acetyl@Protein N-term;Oxidat...\n 4;0;1;18\n 23\n xx\n \n \n \n 35\n MABCDESTKAFGHIJKLMNOPQR\n 0\n 2\n True\n False\n Carbamidomethyl@C;Acetyl@Protein N-term\n 4;0\n 23\n xx\n \n \n \n\n\n\n\n\n_lib.add_additional_modifications(['Phospho@S','Phospho@T'])\nassert _lib.precursor_df.mods.str.contains('Phospho').any()\n_lib.precursor_df\n\n\n\n\n\n \n \n \n sequence\n protein_idxes\n miss_cleavage\n is_prot_nterm\n is_prot_cterm\n mods\n mod_sites\n nAA\n proteins\n genes\n \n \n \n \n 0\n AFGHIJK\n 0;1\n 0\n True\n True\n \n \n 7\n xx;yy\n gene\n \n \n 1\n AFGHIJK\n 0;1\n 0\n True\n True\n Acetyl@Protein N-term\n 0\n 7\n xx;yy\n gene\n \n \n 2\n LMNOPQR\n 0;1\n 0\n False\n True\n Oxidation@M\n 2\n 7\n xx;yy\n gene\n \n \n 3\n LMNOPQR\n 0;1\n 0\n False\n True\n \n \n 7\n xx;yy\n gene\n \n \n 4\n ABCDESTK\n 0\n 0\n True\n False\n Carbamidomethyl@C;Phospho@S\n 3;6\n 8\n xx\n \n \n \n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n \n \n 79\n MABCDESTKAFGHIJKLMNOPQR\n 0\n 2\n True\n False\n Carbamidomethyl@C;Acetyl@Protein N-term;Oxidat...\n 4;0;1;18;8\n 23\n xx\n \n \n \n 80\n MABCDESTKAFGHIJKLMNOPQR\n 0\n 2\n True\n False\n Carbamidomethyl@C;Acetyl@Protein N-term;Oxidat...\n 4;0;1;18\n 23\n xx\n \n \n \n 81\n MABCDESTKAFGHIJKLMNOPQR\n 0\n 2\n True\n False\n Carbamidomethyl@C;Acetyl@Protein N-term;Phospho@S\n 4;0;7\n 23\n xx\n \n \n \n 82\n MABCDESTKAFGHIJKLMNOPQR\n 0\n 2\n True\n False\n Carbamidomethyl@C;Acetyl@Protein N-term;Phospho@T\n 4;0;8\n 23\n xx\n \n \n \n 83\n MABCDESTKAFGHIJKLMNOPQR\n 0\n 2\n True\n False\n Carbamidomethyl@C;Acetyl@Protein N-term\n 4;0\n 23\n xx\n \n \n \n\n84 rows × 10 columns\n\n\n\n\n_lib = FastaLib(\n ['b_z1','y_z1'], I_to_L=False, \n decoy='pseudo_reverse'\n)\nprot1 = 'MACDESTYKBKFGHIKLMNPQRST'\nprot2 = 'FGHIKLMNPQR'\nprotein_dict = {\n 'xx': {\n 'protein_id': 'xx',\n 'sequence': prot1\n },\n 'yy': {\n 'protein_id': 'yy',\n 'sequence': prot2\n }\n}\n_lib.import_and_process_protein_dict(protein_dict)\n_lib.calc_precursor_isotope()\nassert (_lib.precursor_df.charge == _lib.min_precursor_charge).any()\nassert (_lib.precursor_df.charge == _lib.max_precursor_charge).any()\nassert (_lib.precursor_df.decoy==1).any()\nassert ('MACDESTY'[::-1]+'K') in _lib.precursor_df.sequence.values\nassert 'isotope_apex_index' in _lib.precursor_df.columns\nassert 'isotope_apex_intensity' in _lib.precursor_df.columns\nassert ~_lib.precursor_df.sequence.str.contains('B').any()\n_lib.precursor_df\n\n\n\n\n\n \n \n \n sequence\n protein_idxes\n miss_cleavage\n is_prot_nterm\n is_prot_cterm\n mods\n mod_sites\n nAA\n decoy\n charge\n precursor_mz\n isotope_m1_intensity\n isotope_apex_intensity\n isotope_apex_index\n isotope_right_most_intensity\n isotope_right_most_index\n isotope_m1_mz\n isotope_apex_mz\n isotope_right_most_mz\n \n \n \n \n 0\n LMNPQRST\n 0\n 1\n False\n True\n Oxidation@M\n 2\n 8\n 0\n 2\n 481.739834\n 0.478814\n 1.0\n 0\n 0.478814\n 1\n 482.241484\n 481.739834\n 482.241484\n \n \n 1\n LMNPQRST\n 0\n 1\n False\n True\n Oxidation@M\n 2\n 8\n 0\n 3\n 321.495648\n 0.478814\n 1.0\n 0\n 0.478814\n 1\n 321.830081\n 321.495648\n 321.830081\n \n \n 2\n LMNPQRST\n 0\n 1\n False\n True\n Oxidation@M\n 2\n 8\n 0\n 4\n 241.373555\n 0.478814\n 1.0\n 0\n 0.478814\n 1\n 241.624380\n 241.373555\n 241.624380\n \n \n 3\n LMNPQRST\n 0\n 1\n False\n True\n \n \n 8\n 0\n 2\n 473.742377\n 0.478433\n 1.0\n 0\n 0.478433\n 1\n 474.244027\n 473.742377\n 474.244027\n \n \n 4\n LMNPQRST\n 0\n 1\n False\n True\n \n \n 8\n 0\n 3\n 316.164010\n 0.478433\n 1.0\n 0\n 0.478433\n 1\n 316.498443\n 316.164010\n 316.498443\n \n \n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n \n \n 79\n FGHIKLMNPQRST\n 0\n 2\n False\n True\n Oxidation@M\n 7\n 13\n 0\n 3\n 515.604920\n 0.828432\n 1.0\n 0\n 0.420789\n 2\n 515.939354\n 515.604920\n 516.273787\n \n \n 80\n FGHIKLMNPQRST\n 0\n 2\n False\n True\n Oxidation@M\n 7\n 13\n 0\n 4\n 386.955509\n 0.828432\n 1.0\n 0\n 0.420789\n 2\n 387.206334\n 386.955509\n 387.457159\n \n \n 81\n FGHIKLMNPQRST\n 0\n 2\n False\n True\n \n \n 13\n 0\n 2\n 764.906285\n 0.828051\n 1.0\n 0\n 0.418418\n 2\n 765.407935\n 764.906285\n 765.909585\n \n \n 82\n FGHIKLMNPQRST\n 0\n 2\n False\n True\n \n \n 13\n 0\n 3\n 510.273282\n 0.828051\n 1.0\n 0\n 0.418418\n 2\n 510.607715\n 510.273282\n 510.942149\n \n \n 83\n FGHIKLMNPQRST\n 0\n 2\n False\n True\n \n \n 13\n 0\n 4\n 382.956781\n 0.828051\n 1.0\n 0\n 0.418418\n 2\n 383.207606\n 382.956781\n 383.458431\n \n \n\n84 rows × 19 columns\n\n\n\n\n_lib.import_and_process_protein_dict(protein_dict)\n_lib.add_peptide_labeling({\n 'light': ['Dimethyl@Any N-term','Dimethyl@K'],\n 'heavy': ['Dimethyl:2H(6)13C(2)@Any N-term','Dimethyl:2H(6)13C(2)@K'],\n})\n_lib.calc_precursor_isotope()\nassert (_lib.precursor_df.decoy==1).any()\nassert ('MACDESTY'[::-1]+'K') in _lib.precursor_df.sequence.values\nassert 'isotope_apex_index' in _lib.precursor_df.columns\nassert 'isotope_apex_intensity' in _lib.precursor_df.columns\nassert ~_lib.precursor_df.sequence.str.contains('B').any()\n_lib.precursor_df\n\n\n\n\n\n \n \n \n sequence\n protein_idxes\n miss_cleavage\n is_prot_nterm\n is_prot_cterm\n mods\n mod_sites\n nAA\n decoy\n charge\n label_channel\n precursor_mz\n isotope_m1_intensity\n isotope_apex_intensity\n isotope_apex_index\n isotope_right_most_intensity\n isotope_right_most_index\n isotope_m1_mz\n isotope_apex_mz\n isotope_right_most_mz\n \n \n \n \n 0\n LMNPQRST\n 0\n 1\n False\n True\n Oxidation@M;Dimethyl@Any N-term\n 2;0\n 8\n 0\n 2\n light\n 495.755484\n 0.500906\n 1.0\n 0\n 0.500906\n 1\n 496.257134\n 495.755484\n 496.257134\n \n \n 1\n LMNPQRST\n 0\n 1\n False\n True\n Oxidation@M;Dimethyl@Any N-term\n 2;0\n 8\n 0\n 3\n light\n 330.839415\n 0.500906\n 1.0\n 0\n 0.500906\n 1\n 331.173848\n 330.839415\n 331.173848\n \n \n 2\n LMNPQRST\n 0\n 1\n False\n True\n Oxidation@M;Dimethyl@Any N-term\n 2;0\n 8\n 0\n 4\n light\n 248.381380\n 0.500906\n 1.0\n 0\n 0.500906\n 1\n 248.632205\n 248.381380\n 248.632205\n \n \n 3\n LMNPQRST\n 0\n 1\n False\n True\n Dimethyl@Any N-term\n 0\n 8\n 0\n 2\n light\n 487.758027\n 0.500525\n 1.0\n 0\n 0.500525\n 1\n 488.259677\n 487.758027\n 488.259677\n \n \n 4\n LMNPQRST\n 0\n 1\n False\n True\n Dimethyl@Any N-term\n 0\n 8\n 0\n 3\n light\n 325.507777\n 0.500525\n 1.0\n 0\n 0.500525\n 1\n 325.842210\n 325.507777\n 325.842210\n \n \n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n ...\n \n \n 163\n FGHIKLMNPQRST\n 0\n 2\n False\n True\n Oxidation@M;Dimethyl:2H(6)13C(2)@Any N-term;Di...\n 7;0;5\n 13\n 0\n 3\n heavy\n 539.655367\n 0.788273\n 1.0\n 0\n 0.392103\n 2\n 539.989801\n 539.655367\n 540.324234\n \n \n 164\n FGHIKLMNPQRST\n 0\n 2\n False\n True\n Oxidation@M;Dimethyl:2H(6)13C(2)@Any N-term;Di...\n 7;0;5\n 13\n 0\n 4\n heavy\n 404.993344\n 0.788273\n 1.0\n 0\n 0.392103\n 2\n 405.244169\n 404.993344\n 405.494994\n \n \n 165\n FGHIKLMNPQRST\n 0\n 2\n False\n True\n Dimethyl:2H(6)13C(2)@Any N-term;Dimethyl:2H(6)...\n 0;5\n 13\n 0\n 2\n heavy\n 800.981955\n 0.787646\n 1.0\n 0\n 0.389779\n 2\n 801.483605\n 800.981955\n 801.985255\n \n \n 166\n FGHIKLMNPQRST\n 0\n 2\n False\n True\n Dimethyl:2H(6)13C(2)@Any N-term;Dimethyl:2H(6)...\n 0;5\n 13\n 0\n 3\n heavy\n 534.323729\n 0.787646\n 1.0\n 0\n 0.389779\n 2\n 534.658162\n 534.323729\n 534.992596\n \n \n 167\n FGHIKLMNPQRST\n 0\n 2\n False\n True\n Dimethyl:2H(6)13C(2)@Any N-term;Dimethyl:2H(6)...\n 0;5\n 13\n 0\n 4\n heavy\n 400.994616\n 0.787646\n 1.0\n 0\n 0.389779\n 2\n 401.245441\n 400.994616\n 401.496266\n \n \n\n168 rows × 20 columns" - }, - { - "objectID": "protein/test_fasta.html", - "href": "protein/test_fasta.html", - "title": "Testing fasta", - "section": "", - "text": "Init fasta lib\n\nfrom alphabase.protein.fasta import FastaLib\n\nprotein_dict = {\n 'xx': {\n 'protein_id': 'xx',\n 'sequence': 'MACDESTYKBKFGHIKLMNPQRST'\n },\n 'yy': {\n 'protein_id': 'yy',\n 'sequence': 'FGHIKLMNPQR'\n }\n}\n\nfastalib = FastaLib(\n ['b_z1','b_z2','y_z1','y_z2'], \n var_mods=['Oxidation@M','Acetyl@Protein N-term'],\n fix_mods=['Carbamidomethyl@C'],\n decoy='pseudo_reverse',\n I_to_L=False, \n)\n\nCall import_protein_dict or import_fasta to load proteins, append decoys, add modifications and add charge states.\nfastalib.import_fasta([fasta1, fasta2])\n\nfastalib.import_and_process_protein_dict(protein_dict)\nfastalib.protein_df\n\n\n\n\n\n \n \n \n protein_id\n sequence\n \n \n \n \n 0\n xx\n MACDESTYKBKFGHIKLMNPQRST\n \n \n 1\n yy\n FGHIKLMNPQR\n \n \n\n\n\n\n\nassert 'decoy' in fastalib.precursor_df.columns\nassert 'mods' in fastalib.precursor_df.columns\nassert 'mod_sites' in fastalib.precursor_df.columns\nassert 'charge' in fastalib.precursor_df.columns\n\nCall calc_precursor_isotope to calculate the precursor_mz, and M1/M2 isotope mz and intensity.\n\nfastalib.calc_precursor_isotope()\nassert 'precursor_mz' in fastalib.precursor_df.columns\nassert 'isotope_apex_mz' in fastalib.precursor_df.columns\nassert 'isotope_apex_intensity' in fastalib.precursor_df.columns\nassert 'isotope_apex_index' in fastalib.precursor_df.columns\nassert 'isotope_right_most_mz' in fastalib.precursor_df.columns\nassert 'isotope_right_most_intensity' in fastalib.precursor_df.columns\nassert 'isotope_right_most_index' in fastalib.precursor_df.columns\nassert 'isotope_m1_mz' in fastalib.precursor_df.columns\nassert 'isotope_m1_intensity' in fastalib.precursor_df.columns\n\nCall calc_fragment_mz_df to calculate the fragment dataframe\n\nfastalib.calc_fragment_mz_df()\nassert 'frag_start_idx' in fastalib.precursor_df.columns\nassert 'frag_end_idx' in fastalib.precursor_df.columns\nimport numpy as np\nassert len(fastalib.fragment_mz_df) == (fastalib.precursor_df.nAA.values-1).sum()\n\nUse save_hdf to save as hdf file:\nfastalib.save_hdf(hdf_file_path)\nThen use load_hdf to load precursor and fragment dataframes:\nfastalib.load_df(hdf_file_path, load_mod_seq=True)" - }, - { - "objectID": "io/hdf.html", - "href": "io/hdf.html", - "title": "HDF functionalities", - "section": "", - "text": "import alphabase.io.hdf\n\n# Other packages used to demonstrate functionality\nimport numpy as np\nimport pandas as pd\nimport os\n\nInstead of relying directly on the h5py interface, we will use an HDF wrapper file to provide consistent access to only those specific HDF features we want. Since components of an HDF file come in three shapes datasets, groups and attributes, we will first define a generic HDF wrapper object to handle these components. Once this is done, the HDF wrapper file can be treated as such an object with additional features to open and close the initial connection.\n\n#| hide\nfrom nbdev.showdoc import show_doc\n\n\n\nHDF_File\n\n HDF_File (file_name:str, read_only:bool=True, truncate:bool=False,\n delete_existing:bool=False)\n\nA generic class to access HDF components." - }, - { - "objectID": "yaml_utils.html", - "href": "yaml_utils.html", - "title": "YAML Utils", - "section": "", - "text": "source\n\nsave_yaml\n\n save_yaml (filename, settings)\n\n\nsource\n\n\nload_yaml\n\n load_yaml (filename)" - }, - { - "objectID": "index.html", - "href": "index.html", - "title": "AlphaBase", - "section": "", - "text": "AlphaBase provides all basic python functionalities for AlphaPept ecosystem from the Mann Labs at the Max Planck Institute of Biochemistry and the University of Copenhagen. To enable all hyperlinks in this document, please view it at GitHub. For documentation, please see GitHub Pages" - }, - { - "objectID": "index.html#about", - "href": "index.html#about", - "title": "AlphaBase", - "section": "About", - "text": "About\nAn open-source Python package of the AlphaPept ecosystem from the Mann Labs at the Max Planck Institute of Biochemistry and the University of Copenhagen. It provides basic functionalities for AlphaPept ecosystem." - }, - { - "objectID": "index.html#license", - "href": "index.html#license", - "title": "AlphaBase", - "section": "License", - "text": "License\nAlphaBase was developed by the Mann Labs at the Max Planck Institute of Biochemistry and the University of Copenhagen and is freely available with an Apache License. External Python packages (available in the requirements folder) have their own licenses, which can be consulted on their respective websites." - }, - { - "objectID": "index.html#installation", - "href": "index.html#installation", - "title": "AlphaBase", - "section": "Installation", - "text": "Installation\nAlphaBase can be installed and used on all major operating systems (Windows, macOS and Linux). There are two different types of installation possible:\n\nPip installer: Choose this installation if you want to use AlphaBase as a Python package in an existing Python 3.8 environment (e.g. a Jupyter notebook).\nDeveloper installer: Choose this installation if you are familiar with conda and Python. This installation allows access to all available features of AlphaBase and even allows to modify its source code directly. Generally, the developer version of AlphaBase outperforms the precompiled versions which makes this the installation of choice for high-throughput experiments.\n\n\nPip\nAlphaBase can be installed in an existing Python 3.8 environment with a single bash command. This bash command can also be run directly from within a Jupyter notebook by prepending it with a !:\npip install alphabase\nInstalling AlphaBase like this avoids conflicts when integrating it in other tools, as this does not enforce strict versioning of dependancies. However, if new versions of dependancies are released, they are not guaranteed to be fully compatible with AlphaBase. While this should only occur in rare cases where dependencies are not backwards compatible, you can always force AlphaBase to use dependancy versions which are known to be compatible with:\npip install \"alphabase[stable]\"\nNOTE: You might need to run pip install -U pip before installing AlphaBase like this. Also note the double quotes \".\nFor those who are really adventurous, it is also possible to directly install any branch (e.g. @development) with any extras (e.g. #egg=alphabase[stable,development-stable]) from GitHub with e.g.\npip install \"git+https://github.com/MannLabs/alphabase.git@development#egg=alphabase[stable,development-stable]\"\n\n\nDeveloper\nAlphaBase can also be installed in editable (i.e. developer) mode with a few bash commands. This allows to fully customize the software and even modify the source code to your specific needs. When an editable Python package is installed, its source code is stored in a transparent location of your choice. While optional, it is advised to first (create and) navigate to e.g. a general software folder:\nmkdir ~/folder/where/to/install/software\ncd ~/folder/where/to/install/software\nThe following commands assume you do not perform any additional cd commands anymore.\nNext, download the AlphaBase repository from GitHub either directly or with a git command. This creates a new AlphaBase subfolder in your current directory.\ngit clone https://github.com/MannLabs/alphabase.git\nFor any Python package, it is highly recommended to use a separate conda virtual environment, as otherwise dependancy conflicts can occur with already existing packages.\nconda create --name alphabase python=3.8 -y\nconda activate alphabase\nFinally, AlphaBase and all its dependancies need to be installed. To take advantage of all features and allow development (with the -e flag), this is best done by also installing the development dependencies instead of only the core dependencies:\npip install -e \"./alphabase[development]\"\nBy default this installs loose dependancies (no explicit versioning), although it is also possible to use stable dependencies (e.g. pip install -e \"./alphabase[stable,development-stable]\").\nBy using the editable flag -e, all modifications to the AlphaBase source code folder are directly reflected when running AlphaBase. Note that the AlphaBase folder cannot be moved and/or renamed if an editable version is installed. In case of confusion, you can always retrieve the location of any Python module with e.g. the command import module followed by module.__file__." - }, - { - "objectID": "index.html#usage", - "href": "index.html#usage", - "title": "AlphaBase", - "section": "Usage", - "text": "Usage\nTODO" - }, - { - "objectID": "index.html#troubleshooting", - "href": "index.html#troubleshooting", - "title": "AlphaBase", - "section": "Troubleshooting", - "text": "Troubleshooting\nIn case of issues, check out the following:\n\nIssues: Try a few different search terms to find out if a similar problem has been encountered before\nDiscussions: Check if your problem or feature requests has been discussed before." - }, - { - "objectID": "index.html#citations", - "href": "index.html#citations", - "title": "AlphaBase", - "section": "Citations", - "text": "Citations\nThere are currently no plans to draft a manuscript." - }, - { - "objectID": "index.html#how-to-contribute", - "href": "index.html#how-to-contribute", - "title": "AlphaBase", - "section": "How to contribute", - "text": "How to contribute\nIf you like this software, you can give us a star to boost our visibility! All direct contributions are also welcome. Feel free to post a new issue or clone the repository and create a pull request with a new branch. For an even more interactive participation, check out the discussions and the the Contributors License Agreement." - }, - { - "objectID": "index.html#changelog", - "href": "index.html#changelog", - "title": "AlphaBase", - "section": "Changelog", - "text": "Changelog\nSee the HISTORY.md for a full overview of the changes made in each version." - } -] \ No newline at end of file diff --git a/docs/site_libs/bootstrap/bootstrap-icons.css b/docs/site_libs/bootstrap/bootstrap-icons.css deleted file mode 100644 index f51d04bc..00000000 --- a/docs/site_libs/bootstrap/bootstrap-icons.css +++ /dev/null @@ -1,1704 +0,0 @@ -@font-face { - font-family: "bootstrap-icons"; - src: -url("./bootstrap-icons.woff?524846017b983fc8ded9325d94ed40f3") format("woff"); -} - -.bi::before, -[class^="bi-"]::before, -[class*=" bi-"]::before { - display: inline-block; - font-family: bootstrap-icons !important; - font-style: normal; - font-weight: normal !important; - font-variant: normal; - text-transform: none; - line-height: 1; - vertical-align: -.125em; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.bi-123::before { content: "\f67f"; } -.bi-alarm-fill::before { content: "\f101"; } -.bi-alarm::before { content: "\f102"; } -.bi-align-bottom::before { content: "\f103"; } -.bi-align-center::before { content: "\f104"; } -.bi-align-end::before { content: "\f105"; } -.bi-align-middle::before { content: "\f106"; } -.bi-align-start::before { content: "\f107"; } -.bi-align-top::before { content: "\f108"; } -.bi-alt::before { content: "\f109"; } -.bi-app-indicator::before { content: "\f10a"; } -.bi-app::before { content: "\f10b"; } -.bi-archive-fill::before { content: "\f10c"; } -.bi-archive::before { content: "\f10d"; } -.bi-arrow-90deg-down::before { content: "\f10e"; } -.bi-arrow-90deg-left::before { content: "\f10f"; } -.bi-arrow-90deg-right::before { content: "\f110"; } -.bi-arrow-90deg-up::before { content: "\f111"; } -.bi-arrow-bar-down::before { content: "\f112"; } -.bi-arrow-bar-left::before { content: "\f113"; } -.bi-arrow-bar-right::before { content: "\f114"; } -.bi-arrow-bar-up::before { content: "\f115"; } -.bi-arrow-clockwise::before { content: "\f116"; } -.bi-arrow-counterclockwise::before { content: "\f117"; } -.bi-arrow-down-circle-fill::before { content: "\f118"; } -.bi-arrow-down-circle::before { content: "\f119"; } -.bi-arrow-down-left-circle-fill::before { content: "\f11a"; } -.bi-arrow-down-left-circle::before { content: "\f11b"; } -.bi-arrow-down-left-square-fill::before { content: "\f11c"; } -.bi-arrow-down-left-square::before { content: "\f11d"; } -.bi-arrow-down-left::before { content: "\f11e"; } -.bi-arrow-down-right-circle-fill::before { content: "\f11f"; } -.bi-arrow-down-right-circle::before { content: "\f120"; } -.bi-arrow-down-right-square-fill::before { content: "\f121"; } -.bi-arrow-down-right-square::before { content: "\f122"; } -.bi-arrow-down-right::before { content: "\f123"; } -.bi-arrow-down-short::before { content: "\f124"; } -.bi-arrow-down-square-fill::before { content: "\f125"; } -.bi-arrow-down-square::before { content: "\f126"; } -.bi-arrow-down-up::before { content: "\f127"; } -.bi-arrow-down::before { content: "\f128"; } -.bi-arrow-left-circle-fill::before { content: "\f129"; } -.bi-arrow-left-circle::before { content: "\f12a"; } -.bi-arrow-left-right::before { content: "\f12b"; } -.bi-arrow-left-short::before { content: "\f12c"; } -.bi-arrow-left-square-fill::before { content: "\f12d"; } -.bi-arrow-left-square::before { content: "\f12e"; } -.bi-arrow-left::before { content: "\f12f"; } -.bi-arrow-repeat::before { content: "\f130"; } -.bi-arrow-return-left::before { content: "\f131"; } -.bi-arrow-return-right::before { content: "\f132"; } -.bi-arrow-right-circle-fill::before { content: "\f133"; } -.bi-arrow-right-circle::before { content: "\f134"; } -.bi-arrow-right-short::before { content: "\f135"; } -.bi-arrow-right-square-fill::before { content: "\f136"; } -.bi-arrow-right-square::before { content: "\f137"; } -.bi-arrow-right::before { content: "\f138"; } -.bi-arrow-up-circle-fill::before { content: "\f139"; } -.bi-arrow-up-circle::before { content: "\f13a"; } -.bi-arrow-up-left-circle-fill::before { content: "\f13b"; } -.bi-arrow-up-left-circle::before { content: "\f13c"; } -.bi-arrow-up-left-square-fill::before { content: "\f13d"; } -.bi-arrow-up-left-square::before { content: "\f13e"; } -.bi-arrow-up-left::before { content: "\f13f"; } -.bi-arrow-up-right-circle-fill::before { content: "\f140"; } -.bi-arrow-up-right-circle::before { content: "\f141"; } -.bi-arrow-up-right-square-fill::before { content: "\f142"; } -.bi-arrow-up-right-square::before { content: "\f143"; } -.bi-arrow-up-right::before { content: "\f144"; } -.bi-arrow-up-short::before { content: "\f145"; } -.bi-arrow-up-square-fill::before { content: "\f146"; } -.bi-arrow-up-square::before { content: "\f147"; } -.bi-arrow-up::before { content: "\f148"; } -.bi-arrows-angle-contract::before { content: "\f149"; } -.bi-arrows-angle-expand::before { content: "\f14a"; } -.bi-arrows-collapse::before { content: "\f14b"; } -.bi-arrows-expand::before { content: "\f14c"; } -.bi-arrows-fullscreen::before { content: "\f14d"; } -.bi-arrows-move::before { content: "\f14e"; } -.bi-aspect-ratio-fill::before { content: "\f14f"; } -.bi-aspect-ratio::before { content: "\f150"; } -.bi-asterisk::before { content: "\f151"; } -.bi-at::before { content: "\f152"; } -.bi-award-fill::before { content: "\f153"; } -.bi-award::before { content: "\f154"; } -.bi-back::before { content: "\f155"; } -.bi-backspace-fill::before { content: "\f156"; } -.bi-backspace-reverse-fill::before { content: "\f157"; } -.bi-backspace-reverse::before { content: "\f158"; } -.bi-backspace::before { content: "\f159"; } -.bi-badge-3d-fill::before { content: "\f15a"; } -.bi-badge-3d::before { content: "\f15b"; } -.bi-badge-4k-fill::before { content: "\f15c"; } -.bi-badge-4k::before { content: "\f15d"; } -.bi-badge-8k-fill::before { content: "\f15e"; } -.bi-badge-8k::before { content: "\f15f"; } -.bi-badge-ad-fill::before { content: "\f160"; } -.bi-badge-ad::before { content: "\f161"; } -.bi-badge-ar-fill::before { content: "\f162"; } -.bi-badge-ar::before { content: "\f163"; } -.bi-badge-cc-fill::before { content: "\f164"; } -.bi-badge-cc::before { content: "\f165"; } -.bi-badge-hd-fill::before { content: "\f166"; } -.bi-badge-hd::before { content: "\f167"; } -.bi-badge-tm-fill::before { content: "\f168"; } -.bi-badge-tm::before { content: "\f169"; } -.bi-badge-vo-fill::before { content: "\f16a"; } -.bi-badge-vo::before { content: "\f16b"; } -.bi-badge-vr-fill::before { content: "\f16c"; } -.bi-badge-vr::before { content: "\f16d"; } -.bi-badge-wc-fill::before { content: "\f16e"; } -.bi-badge-wc::before { content: "\f16f"; } -.bi-bag-check-fill::before { content: "\f170"; } -.bi-bag-check::before { content: "\f171"; } -.bi-bag-dash-fill::before { content: "\f172"; } -.bi-bag-dash::before { content: "\f173"; } -.bi-bag-fill::before { content: "\f174"; } -.bi-bag-plus-fill::before { content: "\f175"; } -.bi-bag-plus::before { content: "\f176"; } -.bi-bag-x-fill::before { content: "\f177"; } -.bi-bag-x::before { content: "\f178"; } -.bi-bag::before { content: "\f179"; } -.bi-bar-chart-fill::before { content: "\f17a"; } -.bi-bar-chart-line-fill::before { content: "\f17b"; } -.bi-bar-chart-line::before { content: "\f17c"; } -.bi-bar-chart-steps::before { content: "\f17d"; } -.bi-bar-chart::before { content: "\f17e"; } -.bi-basket-fill::before { content: "\f17f"; } -.bi-basket::before { content: "\f180"; } -.bi-basket2-fill::before { content: "\f181"; } -.bi-basket2::before { content: "\f182"; } -.bi-basket3-fill::before { content: "\f183"; } -.bi-basket3::before { content: "\f184"; } -.bi-battery-charging::before { content: "\f185"; } -.bi-battery-full::before { content: "\f186"; } -.bi-battery-half::before { content: "\f187"; } -.bi-battery::before { content: "\f188"; } -.bi-bell-fill::before { content: "\f189"; } -.bi-bell::before { content: "\f18a"; } -.bi-bezier::before { content: "\f18b"; } -.bi-bezier2::before { content: "\f18c"; } -.bi-bicycle::before { content: "\f18d"; } -.bi-binoculars-fill::before { content: "\f18e"; } -.bi-binoculars::before { content: "\f18f"; } -.bi-blockquote-left::before { content: "\f190"; } -.bi-blockquote-right::before { content: "\f191"; } -.bi-book-fill::before { content: "\f192"; } -.bi-book-half::before { content: "\f193"; } -.bi-book::before { content: "\f194"; } -.bi-bookmark-check-fill::before { content: "\f195"; } -.bi-bookmark-check::before { content: "\f196"; } -.bi-bookmark-dash-fill::before { content: "\f197"; } -.bi-bookmark-dash::before { content: "\f198"; } -.bi-bookmark-fill::before { content: "\f199"; } -.bi-bookmark-heart-fill::before { content: "\f19a"; } -.bi-bookmark-heart::before { content: "\f19b"; } -.bi-bookmark-plus-fill::before { content: "\f19c"; } -.bi-bookmark-plus::before { content: "\f19d"; } -.bi-bookmark-star-fill::before { content: "\f19e"; } -.bi-bookmark-star::before { content: "\f19f"; } -.bi-bookmark-x-fill::before { content: "\f1a0"; } -.bi-bookmark-x::before { content: "\f1a1"; } -.bi-bookmark::before { content: "\f1a2"; } -.bi-bookmarks-fill::before { content: "\f1a3"; } -.bi-bookmarks::before { content: "\f1a4"; } -.bi-bookshelf::before { content: "\f1a5"; } -.bi-bootstrap-fill::before { content: "\f1a6"; } -.bi-bootstrap-reboot::before { content: "\f1a7"; } -.bi-bootstrap::before { content: "\f1a8"; } -.bi-border-all::before { content: "\f1a9"; } -.bi-border-bottom::before { content: "\f1aa"; } -.bi-border-center::before { content: "\f1ab"; } -.bi-border-inner::before { content: "\f1ac"; } -.bi-border-left::before { content: "\f1ad"; } -.bi-border-middle::before { content: "\f1ae"; } -.bi-border-outer::before { content: "\f1af"; } -.bi-border-right::before { content: "\f1b0"; } -.bi-border-style::before { content: "\f1b1"; } -.bi-border-top::before { content: "\f1b2"; } -.bi-border-width::before { content: "\f1b3"; } -.bi-border::before { content: "\f1b4"; } -.bi-bounding-box-circles::before { content: "\f1b5"; } -.bi-bounding-box::before { content: "\f1b6"; } -.bi-box-arrow-down-left::before { content: "\f1b7"; } -.bi-box-arrow-down-right::before { content: "\f1b8"; } -.bi-box-arrow-down::before { content: "\f1b9"; } -.bi-box-arrow-in-down-left::before { content: "\f1ba"; } -.bi-box-arrow-in-down-right::before { content: "\f1bb"; } -.bi-box-arrow-in-down::before { content: "\f1bc"; } -.bi-box-arrow-in-left::before { content: "\f1bd"; } -.bi-box-arrow-in-right::before { content: "\f1be"; } -.bi-box-arrow-in-up-left::before { content: "\f1bf"; } -.bi-box-arrow-in-up-right::before { content: "\f1c0"; } -.bi-box-arrow-in-up::before { content: "\f1c1"; } -.bi-box-arrow-left::before { content: "\f1c2"; } -.bi-box-arrow-right::before { content: "\f1c3"; } -.bi-box-arrow-up-left::before { content: "\f1c4"; } -.bi-box-arrow-up-right::before { content: "\f1c5"; } -.bi-box-arrow-up::before { content: "\f1c6"; } -.bi-box-seam::before { content: "\f1c7"; } -.bi-box::before { content: "\f1c8"; } -.bi-braces::before { content: "\f1c9"; } -.bi-bricks::before { content: "\f1ca"; } -.bi-briefcase-fill::before { content: "\f1cb"; } -.bi-briefcase::before { content: "\f1cc"; } -.bi-brightness-alt-high-fill::before { content: "\f1cd"; } -.bi-brightness-alt-high::before { content: "\f1ce"; } -.bi-brightness-alt-low-fill::before { content: "\f1cf"; } -.bi-brightness-alt-low::before { content: "\f1d0"; } -.bi-brightness-high-fill::before { content: "\f1d1"; } -.bi-brightness-high::before { content: "\f1d2"; } -.bi-brightness-low-fill::before { content: "\f1d3"; } -.bi-brightness-low::before { content: "\f1d4"; } -.bi-broadcast-pin::before { content: "\f1d5"; } -.bi-broadcast::before { content: "\f1d6"; } -.bi-brush-fill::before { content: "\f1d7"; } -.bi-brush::before { content: "\f1d8"; } -.bi-bucket-fill::before { content: "\f1d9"; } -.bi-bucket::before { content: "\f1da"; } -.bi-bug-fill::before { content: "\f1db"; } -.bi-bug::before { content: "\f1dc"; } -.bi-building::before { content: "\f1dd"; } -.bi-bullseye::before { content: "\f1de"; } -.bi-calculator-fill::before { content: "\f1df"; } -.bi-calculator::before { content: "\f1e0"; } -.bi-calendar-check-fill::before { content: "\f1e1"; } -.bi-calendar-check::before { content: "\f1e2"; } -.bi-calendar-date-fill::before { content: "\f1e3"; } -.bi-calendar-date::before { content: "\f1e4"; } -.bi-calendar-day-fill::before { content: "\f1e5"; } -.bi-calendar-day::before { content: "\f1e6"; } -.bi-calendar-event-fill::before { content: "\f1e7"; } -.bi-calendar-event::before { content: "\f1e8"; } -.bi-calendar-fill::before { content: "\f1e9"; } -.bi-calendar-minus-fill::before { content: "\f1ea"; } -.bi-calendar-minus::before { content: "\f1eb"; } -.bi-calendar-month-fill::before { content: "\f1ec"; } -.bi-calendar-month::before { content: "\f1ed"; } -.bi-calendar-plus-fill::before { content: "\f1ee"; } -.bi-calendar-plus::before { content: "\f1ef"; } -.bi-calendar-range-fill::before { content: "\f1f0"; } -.bi-calendar-range::before { content: "\f1f1"; } -.bi-calendar-week-fill::before { content: "\f1f2"; } -.bi-calendar-week::before { content: "\f1f3"; } -.bi-calendar-x-fill::before { content: "\f1f4"; } -.bi-calendar-x::before { content: "\f1f5"; } -.bi-calendar::before { content: "\f1f6"; } -.bi-calendar2-check-fill::before { content: "\f1f7"; } -.bi-calendar2-check::before { content: "\f1f8"; } -.bi-calendar2-date-fill::before { content: "\f1f9"; } -.bi-calendar2-date::before { content: "\f1fa"; } -.bi-calendar2-day-fill::before { content: "\f1fb"; } -.bi-calendar2-day::before { content: "\f1fc"; } -.bi-calendar2-event-fill::before { content: "\f1fd"; } -.bi-calendar2-event::before { content: "\f1fe"; } -.bi-calendar2-fill::before { content: "\f1ff"; } -.bi-calendar2-minus-fill::before { content: "\f200"; } -.bi-calendar2-minus::before { content: "\f201"; } -.bi-calendar2-month-fill::before { content: "\f202"; } -.bi-calendar2-month::before { content: "\f203"; } -.bi-calendar2-plus-fill::before { content: "\f204"; } -.bi-calendar2-plus::before { content: "\f205"; } -.bi-calendar2-range-fill::before { content: "\f206"; } -.bi-calendar2-range::before { content: "\f207"; } -.bi-calendar2-week-fill::before { content: "\f208"; } -.bi-calendar2-week::before { content: "\f209"; } -.bi-calendar2-x-fill::before { content: "\f20a"; } -.bi-calendar2-x::before { content: "\f20b"; } -.bi-calendar2::before { content: "\f20c"; } -.bi-calendar3-event-fill::before { content: "\f20d"; } -.bi-calendar3-event::before { content: "\f20e"; } -.bi-calendar3-fill::before { content: "\f20f"; } -.bi-calendar3-range-fill::before { content: "\f210"; } -.bi-calendar3-range::before { content: "\f211"; } -.bi-calendar3-week-fill::before { content: "\f212"; } -.bi-calendar3-week::before { content: "\f213"; } -.bi-calendar3::before { content: "\f214"; } -.bi-calendar4-event::before { content: "\f215"; } -.bi-calendar4-range::before { content: "\f216"; } -.bi-calendar4-week::before { content: "\f217"; } -.bi-calendar4::before { content: "\f218"; } -.bi-camera-fill::before { content: "\f219"; } -.bi-camera-reels-fill::before { content: "\f21a"; } -.bi-camera-reels::before { content: "\f21b"; } -.bi-camera-video-fill::before { content: "\f21c"; } -.bi-camera-video-off-fill::before { content: "\f21d"; } -.bi-camera-video-off::before { content: "\f21e"; } -.bi-camera-video::before { content: "\f21f"; } -.bi-camera::before { content: "\f220"; } -.bi-camera2::before { content: "\f221"; } -.bi-capslock-fill::before { content: "\f222"; } -.bi-capslock::before { content: "\f223"; } -.bi-card-checklist::before { content: "\f224"; } -.bi-card-heading::before { content: "\f225"; } -.bi-card-image::before { content: "\f226"; } -.bi-card-list::before { content: "\f227"; } -.bi-card-text::before { content: "\f228"; } -.bi-caret-down-fill::before { content: "\f229"; } -.bi-caret-down-square-fill::before { content: "\f22a"; } -.bi-caret-down-square::before { content: "\f22b"; } -.bi-caret-down::before { content: "\f22c"; } -.bi-caret-left-fill::before { content: "\f22d"; } -.bi-caret-left-square-fill::before { content: "\f22e"; } -.bi-caret-left-square::before { content: "\f22f"; } -.bi-caret-left::before { content: "\f230"; } -.bi-caret-right-fill::before { content: "\f231"; } -.bi-caret-right-square-fill::before { content: "\f232"; } -.bi-caret-right-square::before { content: "\f233"; } -.bi-caret-right::before { content: "\f234"; } -.bi-caret-up-fill::before { content: "\f235"; } -.bi-caret-up-square-fill::before { content: "\f236"; } -.bi-caret-up-square::before { content: "\f237"; } -.bi-caret-up::before { content: "\f238"; } -.bi-cart-check-fill::before { content: "\f239"; } -.bi-cart-check::before { content: "\f23a"; } -.bi-cart-dash-fill::before { content: "\f23b"; } -.bi-cart-dash::before { content: "\f23c"; } -.bi-cart-fill::before { content: "\f23d"; } -.bi-cart-plus-fill::before { content: "\f23e"; } -.bi-cart-plus::before { content: "\f23f"; } -.bi-cart-x-fill::before { content: "\f240"; } -.bi-cart-x::before { content: "\f241"; } -.bi-cart::before { content: "\f242"; } -.bi-cart2::before { content: "\f243"; } -.bi-cart3::before { content: "\f244"; } -.bi-cart4::before { content: "\f245"; } -.bi-cash-stack::before { content: "\f246"; } -.bi-cash::before { content: "\f247"; } -.bi-cast::before { content: "\f248"; } -.bi-chat-dots-fill::before { content: "\f249"; } -.bi-chat-dots::before { content: "\f24a"; } -.bi-chat-fill::before { content: "\f24b"; } -.bi-chat-left-dots-fill::before { content: "\f24c"; } -.bi-chat-left-dots::before { content: "\f24d"; } -.bi-chat-left-fill::before { content: "\f24e"; } -.bi-chat-left-quote-fill::before { content: "\f24f"; } -.bi-chat-left-quote::before { content: "\f250"; } -.bi-chat-left-text-fill::before { content: "\f251"; } -.bi-chat-left-text::before { content: "\f252"; } -.bi-chat-left::before { content: "\f253"; } -.bi-chat-quote-fill::before { content: "\f254"; } -.bi-chat-quote::before { content: "\f255"; } -.bi-chat-right-dots-fill::before { content: "\f256"; } -.bi-chat-right-dots::before { content: "\f257"; } -.bi-chat-right-fill::before { content: "\f258"; } -.bi-chat-right-quote-fill::before { content: "\f259"; } -.bi-chat-right-quote::before { content: "\f25a"; } -.bi-chat-right-text-fill::before { content: "\f25b"; } -.bi-chat-right-text::before { content: "\f25c"; } -.bi-chat-right::before { content: "\f25d"; } -.bi-chat-square-dots-fill::before { content: "\f25e"; } -.bi-chat-square-dots::before { content: "\f25f"; } -.bi-chat-square-fill::before { content: "\f260"; } -.bi-chat-square-quote-fill::before { content: "\f261"; } -.bi-chat-square-quote::before { content: "\f262"; } -.bi-chat-square-text-fill::before { content: "\f263"; } -.bi-chat-square-text::before { content: "\f264"; } -.bi-chat-square::before { content: "\f265"; } -.bi-chat-text-fill::before { content: "\f266"; } -.bi-chat-text::before { content: "\f267"; } -.bi-chat::before { content: "\f268"; } -.bi-check-all::before { content: "\f269"; } -.bi-check-circle-fill::before { content: "\f26a"; } -.bi-check-circle::before { content: "\f26b"; } -.bi-check-square-fill::before { content: "\f26c"; } -.bi-check-square::before { content: "\f26d"; } -.bi-check::before { content: "\f26e"; } -.bi-check2-all::before { content: "\f26f"; } -.bi-check2-circle::before { content: "\f270"; } -.bi-check2-square::before { content: "\f271"; } -.bi-check2::before { content: "\f272"; } -.bi-chevron-bar-contract::before { content: "\f273"; } -.bi-chevron-bar-down::before { content: "\f274"; } -.bi-chevron-bar-expand::before { content: "\f275"; } -.bi-chevron-bar-left::before { content: "\f276"; } -.bi-chevron-bar-right::before { content: "\f277"; } -.bi-chevron-bar-up::before { content: "\f278"; } -.bi-chevron-compact-down::before { content: "\f279"; } -.bi-chevron-compact-left::before { content: "\f27a"; } -.bi-chevron-compact-right::before { content: "\f27b"; } -.bi-chevron-compact-up::before { content: "\f27c"; } -.bi-chevron-contract::before { content: "\f27d"; } -.bi-chevron-double-down::before { content: "\f27e"; } -.bi-chevron-double-left::before { content: "\f27f"; } -.bi-chevron-double-right::before { content: "\f280"; } -.bi-chevron-double-up::before { content: "\f281"; } -.bi-chevron-down::before { content: "\f282"; } -.bi-chevron-expand::before { content: "\f283"; } -.bi-chevron-left::before { content: "\f284"; } -.bi-chevron-right::before { content: "\f285"; } -.bi-chevron-up::before { content: "\f286"; } -.bi-circle-fill::before { content: "\f287"; } -.bi-circle-half::before { content: "\f288"; } -.bi-circle-square::before { content: "\f289"; } -.bi-circle::before { content: "\f28a"; } -.bi-clipboard-check::before { content: "\f28b"; } -.bi-clipboard-data::before { content: "\f28c"; } -.bi-clipboard-minus::before { content: "\f28d"; } -.bi-clipboard-plus::before { content: "\f28e"; } -.bi-clipboard-x::before { content: "\f28f"; } -.bi-clipboard::before { content: "\f290"; } -.bi-clock-fill::before { content: "\f291"; } -.bi-clock-history::before { content: "\f292"; } -.bi-clock::before { content: "\f293"; } -.bi-cloud-arrow-down-fill::before { content: "\f294"; } -.bi-cloud-arrow-down::before { content: "\f295"; } -.bi-cloud-arrow-up-fill::before { content: "\f296"; } -.bi-cloud-arrow-up::before { content: "\f297"; } -.bi-cloud-check-fill::before { content: "\f298"; } -.bi-cloud-check::before { content: "\f299"; } -.bi-cloud-download-fill::before { content: "\f29a"; } -.bi-cloud-download::before { content: "\f29b"; } -.bi-cloud-drizzle-fill::before { content: "\f29c"; } -.bi-cloud-drizzle::before { content: "\f29d"; } -.bi-cloud-fill::before { content: "\f29e"; } -.bi-cloud-fog-fill::before { content: "\f29f"; } -.bi-cloud-fog::before { content: "\f2a0"; } -.bi-cloud-fog2-fill::before { content: "\f2a1"; } -.bi-cloud-fog2::before { content: "\f2a2"; } -.bi-cloud-hail-fill::before { content: "\f2a3"; } -.bi-cloud-hail::before { content: "\f2a4"; } -.bi-cloud-haze-1::before { content: "\f2a5"; } -.bi-cloud-haze-fill::before { content: "\f2a6"; } -.bi-cloud-haze::before { content: "\f2a7"; } -.bi-cloud-haze2-fill::before { content: "\f2a8"; } -.bi-cloud-lightning-fill::before { content: "\f2a9"; } -.bi-cloud-lightning-rain-fill::before { content: "\f2aa"; } -.bi-cloud-lightning-rain::before { content: "\f2ab"; } -.bi-cloud-lightning::before { content: "\f2ac"; } -.bi-cloud-minus-fill::before { content: "\f2ad"; } -.bi-cloud-minus::before { content: "\f2ae"; } -.bi-cloud-moon-fill::before { content: "\f2af"; } -.bi-cloud-moon::before { content: "\f2b0"; } -.bi-cloud-plus-fill::before { content: "\f2b1"; } -.bi-cloud-plus::before { content: "\f2b2"; } -.bi-cloud-rain-fill::before { content: "\f2b3"; } -.bi-cloud-rain-heavy-fill::before { content: "\f2b4"; } -.bi-cloud-rain-heavy::before { content: "\f2b5"; } -.bi-cloud-rain::before { content: "\f2b6"; } -.bi-cloud-slash-fill::before { content: "\f2b7"; } -.bi-cloud-slash::before { content: "\f2b8"; } -.bi-cloud-sleet-fill::before { content: "\f2b9"; } -.bi-cloud-sleet::before { content: "\f2ba"; } -.bi-cloud-snow-fill::before { content: "\f2bb"; } -.bi-cloud-snow::before { content: "\f2bc"; } -.bi-cloud-sun-fill::before { content: "\f2bd"; } -.bi-cloud-sun::before { content: "\f2be"; } -.bi-cloud-upload-fill::before { content: "\f2bf"; } -.bi-cloud-upload::before { content: "\f2c0"; } -.bi-cloud::before { content: "\f2c1"; } -.bi-clouds-fill::before { content: "\f2c2"; } -.bi-clouds::before { content: "\f2c3"; } -.bi-cloudy-fill::before { content: "\f2c4"; } -.bi-cloudy::before { content: "\f2c5"; } -.bi-code-slash::before { content: "\f2c6"; } -.bi-code-square::before { content: "\f2c7"; } -.bi-code::before { content: "\f2c8"; } -.bi-collection-fill::before { content: "\f2c9"; } -.bi-collection-play-fill::before { content: "\f2ca"; } -.bi-collection-play::before { content: "\f2cb"; } -.bi-collection::before { content: "\f2cc"; } -.bi-columns-gap::before { content: "\f2cd"; } -.bi-columns::before { content: "\f2ce"; } -.bi-command::before { content: "\f2cf"; } -.bi-compass-fill::before { content: "\f2d0"; } -.bi-compass::before { content: "\f2d1"; } -.bi-cone-striped::before { content: "\f2d2"; } -.bi-cone::before { content: "\f2d3"; } -.bi-controller::before { content: "\f2d4"; } -.bi-cpu-fill::before { content: "\f2d5"; } -.bi-cpu::before { content: "\f2d6"; } -.bi-credit-card-2-back-fill::before { content: "\f2d7"; } -.bi-credit-card-2-back::before { content: "\f2d8"; } -.bi-credit-card-2-front-fill::before { content: "\f2d9"; } -.bi-credit-card-2-front::before { content: "\f2da"; } -.bi-credit-card-fill::before { content: "\f2db"; } -.bi-credit-card::before { content: "\f2dc"; } -.bi-crop::before { content: "\f2dd"; } -.bi-cup-fill::before { content: "\f2de"; } -.bi-cup-straw::before { content: "\f2df"; } -.bi-cup::before { content: "\f2e0"; } -.bi-cursor-fill::before { content: "\f2e1"; } -.bi-cursor-text::before { content: "\f2e2"; } -.bi-cursor::before { content: "\f2e3"; } -.bi-dash-circle-dotted::before { content: "\f2e4"; } -.bi-dash-circle-fill::before { content: "\f2e5"; } -.bi-dash-circle::before { content: "\f2e6"; } -.bi-dash-square-dotted::before { content: "\f2e7"; } -.bi-dash-square-fill::before { content: "\f2e8"; } -.bi-dash-square::before { content: "\f2e9"; } -.bi-dash::before { content: "\f2ea"; } -.bi-diagram-2-fill::before { content: "\f2eb"; } -.bi-diagram-2::before { content: "\f2ec"; } -.bi-diagram-3-fill::before { content: "\f2ed"; } -.bi-diagram-3::before { content: "\f2ee"; } -.bi-diamond-fill::before { content: "\f2ef"; } -.bi-diamond-half::before { content: "\f2f0"; } -.bi-diamond::before { content: "\f2f1"; } -.bi-dice-1-fill::before { content: "\f2f2"; } -.bi-dice-1::before { content: "\f2f3"; } -.bi-dice-2-fill::before { content: "\f2f4"; } -.bi-dice-2::before { content: "\f2f5"; } -.bi-dice-3-fill::before { content: "\f2f6"; } -.bi-dice-3::before { content: "\f2f7"; } -.bi-dice-4-fill::before { content: "\f2f8"; } -.bi-dice-4::before { content: "\f2f9"; } -.bi-dice-5-fill::before { content: "\f2fa"; } -.bi-dice-5::before { content: "\f2fb"; } -.bi-dice-6-fill::before { content: "\f2fc"; } -.bi-dice-6::before { content: "\f2fd"; } -.bi-disc-fill::before { content: "\f2fe"; } -.bi-disc::before { content: "\f2ff"; } -.bi-discord::before { content: "\f300"; } -.bi-display-fill::before { content: "\f301"; } -.bi-display::before { content: "\f302"; } -.bi-distribute-horizontal::before { content: "\f303"; } -.bi-distribute-vertical::before { content: "\f304"; } -.bi-door-closed-fill::before { content: "\f305"; } -.bi-door-closed::before { content: "\f306"; } -.bi-door-open-fill::before { content: "\f307"; } -.bi-door-open::before { content: "\f308"; } -.bi-dot::before { content: "\f309"; } -.bi-download::before { content: "\f30a"; } -.bi-droplet-fill::before { content: "\f30b"; } -.bi-droplet-half::before { content: "\f30c"; } -.bi-droplet::before { content: "\f30d"; } -.bi-earbuds::before { content: "\f30e"; } -.bi-easel-fill::before { content: "\f30f"; } -.bi-easel::before { content: "\f310"; } -.bi-egg-fill::before { content: "\f311"; } -.bi-egg-fried::before { content: "\f312"; } -.bi-egg::before { content: "\f313"; } -.bi-eject-fill::before { content: "\f314"; } -.bi-eject::before { content: "\f315"; } -.bi-emoji-angry-fill::before { content: "\f316"; } -.bi-emoji-angry::before { content: "\f317"; } -.bi-emoji-dizzy-fill::before { content: "\f318"; } -.bi-emoji-dizzy::before { content: "\f319"; } -.bi-emoji-expressionless-fill::before { content: "\f31a"; } -.bi-emoji-expressionless::before { content: "\f31b"; } -.bi-emoji-frown-fill::before { content: "\f31c"; } -.bi-emoji-frown::before { content: "\f31d"; } -.bi-emoji-heart-eyes-fill::before { content: "\f31e"; } -.bi-emoji-heart-eyes::before { content: "\f31f"; } -.bi-emoji-laughing-fill::before { content: "\f320"; } -.bi-emoji-laughing::before { content: "\f321"; } -.bi-emoji-neutral-fill::before { content: "\f322"; } -.bi-emoji-neutral::before { content: "\f323"; } -.bi-emoji-smile-fill::before { content: "\f324"; } -.bi-emoji-smile-upside-down-fill::before { content: "\f325"; } -.bi-emoji-smile-upside-down::before { content: "\f326"; } -.bi-emoji-smile::before { content: "\f327"; } -.bi-emoji-sunglasses-fill::before { content: "\f328"; } -.bi-emoji-sunglasses::before { content: "\f329"; } -.bi-emoji-wink-fill::before { content: "\f32a"; } -.bi-emoji-wink::before { content: "\f32b"; } -.bi-envelope-fill::before { content: "\f32c"; } -.bi-envelope-open-fill::before { content: "\f32d"; } -.bi-envelope-open::before { content: "\f32e"; } -.bi-envelope::before { content: "\f32f"; } -.bi-eraser-fill::before { content: "\f330"; } -.bi-eraser::before { content: "\f331"; } -.bi-exclamation-circle-fill::before { content: "\f332"; } -.bi-exclamation-circle::before { content: "\f333"; } -.bi-exclamation-diamond-fill::before { content: "\f334"; } -.bi-exclamation-diamond::before { content: "\f335"; } -.bi-exclamation-octagon-fill::before { content: "\f336"; } -.bi-exclamation-octagon::before { content: "\f337"; } -.bi-exclamation-square-fill::before { content: "\f338"; } -.bi-exclamation-square::before { content: "\f339"; } -.bi-exclamation-triangle-fill::before { content: "\f33a"; } -.bi-exclamation-triangle::before { content: "\f33b"; } -.bi-exclamation::before { content: "\f33c"; } -.bi-exclude::before { content: "\f33d"; } -.bi-eye-fill::before { content: "\f33e"; } -.bi-eye-slash-fill::before { content: "\f33f"; } -.bi-eye-slash::before { content: "\f340"; } -.bi-eye::before { content: "\f341"; } -.bi-eyedropper::before { content: "\f342"; } -.bi-eyeglasses::before { content: "\f343"; } -.bi-facebook::before { content: "\f344"; } -.bi-file-arrow-down-fill::before { content: "\f345"; } -.bi-file-arrow-down::before { content: "\f346"; } -.bi-file-arrow-up-fill::before { content: "\f347"; } -.bi-file-arrow-up::before { content: "\f348"; } -.bi-file-bar-graph-fill::before { content: "\f349"; } -.bi-file-bar-graph::before { content: "\f34a"; } -.bi-file-binary-fill::before { content: "\f34b"; } -.bi-file-binary::before { content: "\f34c"; } -.bi-file-break-fill::before { content: "\f34d"; } -.bi-file-break::before { content: "\f34e"; } -.bi-file-check-fill::before { content: "\f34f"; } -.bi-file-check::before { content: "\f350"; } -.bi-file-code-fill::before { content: "\f351"; } -.bi-file-code::before { content: "\f352"; } -.bi-file-diff-fill::before { content: "\f353"; } -.bi-file-diff::before { content: "\f354"; } -.bi-file-earmark-arrow-down-fill::before { content: "\f355"; } -.bi-file-earmark-arrow-down::before { content: "\f356"; } -.bi-file-earmark-arrow-up-fill::before { content: "\f357"; } -.bi-file-earmark-arrow-up::before { content: "\f358"; } -.bi-file-earmark-bar-graph-fill::before { content: "\f359"; } -.bi-file-earmark-bar-graph::before { content: "\f35a"; } -.bi-file-earmark-binary-fill::before { content: "\f35b"; } -.bi-file-earmark-binary::before { content: "\f35c"; } -.bi-file-earmark-break-fill::before { content: "\f35d"; } -.bi-file-earmark-break::before { content: "\f35e"; } -.bi-file-earmark-check-fill::before { content: "\f35f"; } -.bi-file-earmark-check::before { content: "\f360"; } -.bi-file-earmark-code-fill::before { content: "\f361"; } -.bi-file-earmark-code::before { content: "\f362"; } -.bi-file-earmark-diff-fill::before { content: "\f363"; } -.bi-file-earmark-diff::before { content: "\f364"; } -.bi-file-earmark-easel-fill::before { content: "\f365"; } -.bi-file-earmark-easel::before { content: "\f366"; } -.bi-file-earmark-excel-fill::before { content: "\f367"; } -.bi-file-earmark-excel::before { content: "\f368"; } -.bi-file-earmark-fill::before { content: "\f369"; } -.bi-file-earmark-font-fill::before { content: "\f36a"; } -.bi-file-earmark-font::before { content: "\f36b"; } -.bi-file-earmark-image-fill::before { content: "\f36c"; } -.bi-file-earmark-image::before { content: "\f36d"; } -.bi-file-earmark-lock-fill::before { content: "\f36e"; } -.bi-file-earmark-lock::before { content: "\f36f"; } -.bi-file-earmark-lock2-fill::before { content: "\f370"; } -.bi-file-earmark-lock2::before { content: "\f371"; } -.bi-file-earmark-medical-fill::before { content: "\f372"; } -.bi-file-earmark-medical::before { content: "\f373"; } -.bi-file-earmark-minus-fill::before { content: "\f374"; } -.bi-file-earmark-minus::before { content: "\f375"; } -.bi-file-earmark-music-fill::before { content: "\f376"; } -.bi-file-earmark-music::before { content: "\f377"; } -.bi-file-earmark-person-fill::before { content: "\f378"; } -.bi-file-earmark-person::before { content: "\f379"; } -.bi-file-earmark-play-fill::before { content: "\f37a"; } -.bi-file-earmark-play::before { content: "\f37b"; } -.bi-file-earmark-plus-fill::before { content: "\f37c"; } -.bi-file-earmark-plus::before { content: "\f37d"; } -.bi-file-earmark-post-fill::before { content: "\f37e"; } -.bi-file-earmark-post::before { content: "\f37f"; } -.bi-file-earmark-ppt-fill::before { content: "\f380"; } -.bi-file-earmark-ppt::before { content: "\f381"; } -.bi-file-earmark-richtext-fill::before { content: "\f382"; } -.bi-file-earmark-richtext::before { content: "\f383"; } -.bi-file-earmark-ruled-fill::before { content: "\f384"; } -.bi-file-earmark-ruled::before { content: "\f385"; } -.bi-file-earmark-slides-fill::before { content: "\f386"; } -.bi-file-earmark-slides::before { content: "\f387"; } -.bi-file-earmark-spreadsheet-fill::before { content: "\f388"; } -.bi-file-earmark-spreadsheet::before { content: "\f389"; } -.bi-file-earmark-text-fill::before { content: "\f38a"; } -.bi-file-earmark-text::before { content: "\f38b"; } -.bi-file-earmark-word-fill::before { content: "\f38c"; } -.bi-file-earmark-word::before { content: "\f38d"; } -.bi-file-earmark-x-fill::before { content: "\f38e"; } -.bi-file-earmark-x::before { content: "\f38f"; } -.bi-file-earmark-zip-fill::before { content: "\f390"; } -.bi-file-earmark-zip::before { content: "\f391"; } -.bi-file-earmark::before { content: "\f392"; } -.bi-file-easel-fill::before { content: "\f393"; } -.bi-file-easel::before { content: "\f394"; } -.bi-file-excel-fill::before { content: "\f395"; } -.bi-file-excel::before { content: "\f396"; } -.bi-file-fill::before { content: "\f397"; } -.bi-file-font-fill::before { content: "\f398"; } -.bi-file-font::before { content: "\f399"; } -.bi-file-image-fill::before { content: "\f39a"; } -.bi-file-image::before { content: "\f39b"; } -.bi-file-lock-fill::before { content: "\f39c"; } -.bi-file-lock::before { content: "\f39d"; } -.bi-file-lock2-fill::before { content: "\f39e"; } -.bi-file-lock2::before { content: "\f39f"; } -.bi-file-medical-fill::before { content: "\f3a0"; } -.bi-file-medical::before { content: "\f3a1"; } -.bi-file-minus-fill::before { content: "\f3a2"; } -.bi-file-minus::before { content: "\f3a3"; } -.bi-file-music-fill::before { content: "\f3a4"; } -.bi-file-music::before { content: "\f3a5"; } -.bi-file-person-fill::before { content: "\f3a6"; } -.bi-file-person::before { content: "\f3a7"; } -.bi-file-play-fill::before { content: "\f3a8"; } -.bi-file-play::before { content: "\f3a9"; } -.bi-file-plus-fill::before { content: "\f3aa"; } -.bi-file-plus::before { content: "\f3ab"; } -.bi-file-post-fill::before { content: "\f3ac"; } -.bi-file-post::before { content: "\f3ad"; } -.bi-file-ppt-fill::before { content: "\f3ae"; } -.bi-file-ppt::before { content: "\f3af"; } -.bi-file-richtext-fill::before { content: "\f3b0"; } -.bi-file-richtext::before { content: "\f3b1"; } -.bi-file-ruled-fill::before { content: "\f3b2"; } -.bi-file-ruled::before { content: "\f3b3"; } -.bi-file-slides-fill::before { content: "\f3b4"; } -.bi-file-slides::before { content: "\f3b5"; } -.bi-file-spreadsheet-fill::before { content: "\f3b6"; } -.bi-file-spreadsheet::before { content: "\f3b7"; } -.bi-file-text-fill::before { content: "\f3b8"; } -.bi-file-text::before { content: "\f3b9"; } -.bi-file-word-fill::before { content: "\f3ba"; } -.bi-file-word::before { content: "\f3bb"; } -.bi-file-x-fill::before { content: "\f3bc"; } -.bi-file-x::before { content: "\f3bd"; } -.bi-file-zip-fill::before { content: "\f3be"; } -.bi-file-zip::before { content: "\f3bf"; } -.bi-file::before { content: "\f3c0"; } -.bi-files-alt::before { content: "\f3c1"; } -.bi-files::before { content: "\f3c2"; } -.bi-film::before { content: "\f3c3"; } -.bi-filter-circle-fill::before { content: "\f3c4"; } -.bi-filter-circle::before { content: "\f3c5"; } -.bi-filter-left::before { content: "\f3c6"; } -.bi-filter-right::before { content: "\f3c7"; } -.bi-filter-square-fill::before { content: "\f3c8"; } -.bi-filter-square::before { content: "\f3c9"; } -.bi-filter::before { content: "\f3ca"; } -.bi-flag-fill::before { content: "\f3cb"; } -.bi-flag::before { content: "\f3cc"; } -.bi-flower1::before { content: "\f3cd"; } -.bi-flower2::before { content: "\f3ce"; } -.bi-flower3::before { content: "\f3cf"; } -.bi-folder-check::before { content: "\f3d0"; } -.bi-folder-fill::before { content: "\f3d1"; } -.bi-folder-minus::before { content: "\f3d2"; } -.bi-folder-plus::before { content: "\f3d3"; } -.bi-folder-symlink-fill::before { content: "\f3d4"; } -.bi-folder-symlink::before { content: "\f3d5"; } -.bi-folder-x::before { content: "\f3d6"; } -.bi-folder::before { content: "\f3d7"; } -.bi-folder2-open::before { content: "\f3d8"; } -.bi-folder2::before { content: "\f3d9"; } -.bi-fonts::before { content: "\f3da"; } -.bi-forward-fill::before { content: "\f3db"; } -.bi-forward::before { content: "\f3dc"; } -.bi-front::before { content: "\f3dd"; } -.bi-fullscreen-exit::before { content: "\f3de"; } -.bi-fullscreen::before { content: "\f3df"; } -.bi-funnel-fill::before { content: "\f3e0"; } -.bi-funnel::before { content: "\f3e1"; } -.bi-gear-fill::before { content: "\f3e2"; } -.bi-gear-wide-connected::before { content: "\f3e3"; } -.bi-gear-wide::before { content: "\f3e4"; } -.bi-gear::before { content: "\f3e5"; } -.bi-gem::before { content: "\f3e6"; } -.bi-geo-alt-fill::before { content: "\f3e7"; } -.bi-geo-alt::before { content: "\f3e8"; } -.bi-geo-fill::before { content: "\f3e9"; } -.bi-geo::before { content: "\f3ea"; } -.bi-gift-fill::before { content: "\f3eb"; } -.bi-gift::before { content: "\f3ec"; } -.bi-github::before { content: "\f3ed"; } -.bi-globe::before { content: "\f3ee"; } -.bi-globe2::before { content: "\f3ef"; } -.bi-google::before { content: "\f3f0"; } -.bi-graph-down::before { content: "\f3f1"; } -.bi-graph-up::before { content: "\f3f2"; } -.bi-grid-1x2-fill::before { content: "\f3f3"; } -.bi-grid-1x2::before { content: "\f3f4"; } -.bi-grid-3x2-gap-fill::before { content: "\f3f5"; } -.bi-grid-3x2-gap::before { content: "\f3f6"; } -.bi-grid-3x2::before { content: "\f3f7"; } -.bi-grid-3x3-gap-fill::before { content: "\f3f8"; } -.bi-grid-3x3-gap::before { content: "\f3f9"; } -.bi-grid-3x3::before { content: "\f3fa"; } -.bi-grid-fill::before { content: "\f3fb"; } -.bi-grid::before { content: "\f3fc"; } -.bi-grip-horizontal::before { content: "\f3fd"; } -.bi-grip-vertical::before { content: "\f3fe"; } -.bi-hammer::before { content: "\f3ff"; } -.bi-hand-index-fill::before { content: "\f400"; } -.bi-hand-index-thumb-fill::before { content: "\f401"; } -.bi-hand-index-thumb::before { content: "\f402"; } -.bi-hand-index::before { content: "\f403"; } -.bi-hand-thumbs-down-fill::before { content: "\f404"; } -.bi-hand-thumbs-down::before { content: "\f405"; } -.bi-hand-thumbs-up-fill::before { content: "\f406"; } -.bi-hand-thumbs-up::before { content: "\f407"; } -.bi-handbag-fill::before { content: "\f408"; } -.bi-handbag::before { content: "\f409"; } -.bi-hash::before { content: "\f40a"; } -.bi-hdd-fill::before { content: "\f40b"; } -.bi-hdd-network-fill::before { content: "\f40c"; } -.bi-hdd-network::before { content: "\f40d"; } -.bi-hdd-rack-fill::before { content: "\f40e"; } -.bi-hdd-rack::before { content: "\f40f"; } -.bi-hdd-stack-fill::before { content: "\f410"; } -.bi-hdd-stack::before { content: "\f411"; } -.bi-hdd::before { content: "\f412"; } -.bi-headphones::before { content: "\f413"; } -.bi-headset::before { content: "\f414"; } -.bi-heart-fill::before { content: "\f415"; } -.bi-heart-half::before { content: "\f416"; } -.bi-heart::before { content: "\f417"; } -.bi-heptagon-fill::before { content: "\f418"; } -.bi-heptagon-half::before { content: "\f419"; } -.bi-heptagon::before { content: "\f41a"; } -.bi-hexagon-fill::before { content: "\f41b"; } -.bi-hexagon-half::before { content: "\f41c"; } -.bi-hexagon::before { content: "\f41d"; } -.bi-hourglass-bottom::before { content: "\f41e"; } -.bi-hourglass-split::before { content: "\f41f"; } -.bi-hourglass-top::before { content: "\f420"; } -.bi-hourglass::before { content: "\f421"; } -.bi-house-door-fill::before { content: "\f422"; } -.bi-house-door::before { content: "\f423"; } -.bi-house-fill::before { content: "\f424"; } -.bi-house::before { content: "\f425"; } -.bi-hr::before { content: "\f426"; } -.bi-hurricane::before { content: "\f427"; } -.bi-image-alt::before { content: "\f428"; } -.bi-image-fill::before { content: "\f429"; } -.bi-image::before { content: "\f42a"; } -.bi-images::before { content: "\f42b"; } -.bi-inbox-fill::before { content: "\f42c"; } -.bi-inbox::before { content: "\f42d"; } -.bi-inboxes-fill::before { content: "\f42e"; } -.bi-inboxes::before { content: "\f42f"; } -.bi-info-circle-fill::before { content: "\f430"; } -.bi-info-circle::before { content: "\f431"; } -.bi-info-square-fill::before { content: "\f432"; } -.bi-info-square::before { content: "\f433"; } -.bi-info::before { content: "\f434"; } -.bi-input-cursor-text::before { content: "\f435"; } -.bi-input-cursor::before { content: "\f436"; } -.bi-instagram::before { content: "\f437"; } -.bi-intersect::before { content: "\f438"; } -.bi-journal-album::before { content: "\f439"; } -.bi-journal-arrow-down::before { content: "\f43a"; } -.bi-journal-arrow-up::before { content: "\f43b"; } -.bi-journal-bookmark-fill::before { content: "\f43c"; } -.bi-journal-bookmark::before { content: "\f43d"; } -.bi-journal-check::before { content: "\f43e"; } -.bi-journal-code::before { content: "\f43f"; } -.bi-journal-medical::before { content: "\f440"; } -.bi-journal-minus::before { content: "\f441"; } -.bi-journal-plus::before { content: "\f442"; } -.bi-journal-richtext::before { content: "\f443"; } -.bi-journal-text::before { content: "\f444"; } -.bi-journal-x::before { content: "\f445"; } -.bi-journal::before { content: "\f446"; } -.bi-journals::before { content: "\f447"; } -.bi-joystick::before { content: "\f448"; } -.bi-justify-left::before { content: "\f449"; } -.bi-justify-right::before { content: "\f44a"; } -.bi-justify::before { content: "\f44b"; } -.bi-kanban-fill::before { content: "\f44c"; } -.bi-kanban::before { content: "\f44d"; } -.bi-key-fill::before { content: "\f44e"; } -.bi-key::before { content: "\f44f"; } -.bi-keyboard-fill::before { content: "\f450"; } -.bi-keyboard::before { content: "\f451"; } -.bi-ladder::before { content: "\f452"; } -.bi-lamp-fill::before { content: "\f453"; } -.bi-lamp::before { content: "\f454"; } -.bi-laptop-fill::before { content: "\f455"; } -.bi-laptop::before { content: "\f456"; } -.bi-layer-backward::before { content: "\f457"; } -.bi-layer-forward::before { content: "\f458"; } -.bi-layers-fill::before { content: "\f459"; } -.bi-layers-half::before { content: "\f45a"; } -.bi-layers::before { content: "\f45b"; } -.bi-layout-sidebar-inset-reverse::before { content: "\f45c"; } -.bi-layout-sidebar-inset::before { content: "\f45d"; } -.bi-layout-sidebar-reverse::before { content: "\f45e"; } -.bi-layout-sidebar::before { content: "\f45f"; } -.bi-layout-split::before { content: "\f460"; } -.bi-layout-text-sidebar-reverse::before { content: "\f461"; } -.bi-layout-text-sidebar::before { content: "\f462"; } -.bi-layout-text-window-reverse::before { content: "\f463"; } -.bi-layout-text-window::before { content: "\f464"; } -.bi-layout-three-columns::before { content: "\f465"; } -.bi-layout-wtf::before { content: "\f466"; } -.bi-life-preserver::before { content: "\f467"; } -.bi-lightbulb-fill::before { content: "\f468"; } -.bi-lightbulb-off-fill::before { content: "\f469"; } -.bi-lightbulb-off::before { content: "\f46a"; } -.bi-lightbulb::before { content: "\f46b"; } -.bi-lightning-charge-fill::before { content: "\f46c"; } -.bi-lightning-charge::before { content: "\f46d"; } -.bi-lightning-fill::before { content: "\f46e"; } -.bi-lightning::before { content: "\f46f"; } -.bi-link-45deg::before { content: "\f470"; } -.bi-link::before { content: "\f471"; } -.bi-linkedin::before { content: "\f472"; } -.bi-list-check::before { content: "\f473"; } -.bi-list-nested::before { content: "\f474"; } -.bi-list-ol::before { content: "\f475"; } -.bi-list-stars::before { content: "\f476"; } -.bi-list-task::before { content: "\f477"; } -.bi-list-ul::before { content: "\f478"; } -.bi-list::before { content: "\f479"; } -.bi-lock-fill::before { content: "\f47a"; } -.bi-lock::before { content: "\f47b"; } -.bi-mailbox::before { content: "\f47c"; } -.bi-mailbox2::before { content: "\f47d"; } -.bi-map-fill::before { content: "\f47e"; } -.bi-map::before { content: "\f47f"; } -.bi-markdown-fill::before { content: "\f480"; } -.bi-markdown::before { content: "\f481"; } -.bi-mask::before { content: "\f482"; } -.bi-megaphone-fill::before { content: "\f483"; } -.bi-megaphone::before { content: "\f484"; } -.bi-menu-app-fill::before { content: "\f485"; } -.bi-menu-app::before { content: "\f486"; } -.bi-menu-button-fill::before { content: "\f487"; } -.bi-menu-button-wide-fill::before { content: "\f488"; } -.bi-menu-button-wide::before { content: "\f489"; } -.bi-menu-button::before { content: "\f48a"; } -.bi-menu-down::before { content: "\f48b"; } -.bi-menu-up::before { content: "\f48c"; } -.bi-mic-fill::before { content: "\f48d"; } -.bi-mic-mute-fill::before { content: "\f48e"; } -.bi-mic-mute::before { content: "\f48f"; } -.bi-mic::before { content: "\f490"; } -.bi-minecart-loaded::before { content: "\f491"; } -.bi-minecart::before { content: "\f492"; } -.bi-moisture::before { content: "\f493"; } -.bi-moon-fill::before { content: "\f494"; } -.bi-moon-stars-fill::before { content: "\f495"; } -.bi-moon-stars::before { content: "\f496"; } -.bi-moon::before { content: "\f497"; } -.bi-mouse-fill::before { content: "\f498"; } -.bi-mouse::before { content: "\f499"; } -.bi-mouse2-fill::before { content: "\f49a"; } -.bi-mouse2::before { content: "\f49b"; } -.bi-mouse3-fill::before { content: "\f49c"; } -.bi-mouse3::before { content: "\f49d"; } -.bi-music-note-beamed::before { content: "\f49e"; } -.bi-music-note-list::before { content: "\f49f"; } -.bi-music-note::before { content: "\f4a0"; } -.bi-music-player-fill::before { content: "\f4a1"; } -.bi-music-player::before { content: "\f4a2"; } -.bi-newspaper::before { content: "\f4a3"; } -.bi-node-minus-fill::before { content: "\f4a4"; } -.bi-node-minus::before { content: "\f4a5"; } -.bi-node-plus-fill::before { content: "\f4a6"; } -.bi-node-plus::before { content: "\f4a7"; } -.bi-nut-fill::before { content: "\f4a8"; } -.bi-nut::before { content: "\f4a9"; } -.bi-octagon-fill::before { content: "\f4aa"; } -.bi-octagon-half::before { content: "\f4ab"; } -.bi-octagon::before { content: "\f4ac"; } -.bi-option::before { content: "\f4ad"; } -.bi-outlet::before { content: "\f4ae"; } -.bi-paint-bucket::before { content: "\f4af"; } -.bi-palette-fill::before { content: "\f4b0"; } -.bi-palette::before { content: "\f4b1"; } -.bi-palette2::before { content: "\f4b2"; } -.bi-paperclip::before { content: "\f4b3"; } -.bi-paragraph::before { content: "\f4b4"; } -.bi-patch-check-fill::before { content: "\f4b5"; } -.bi-patch-check::before { content: "\f4b6"; } -.bi-patch-exclamation-fill::before { content: "\f4b7"; } -.bi-patch-exclamation::before { content: "\f4b8"; } -.bi-patch-minus-fill::before { content: "\f4b9"; } -.bi-patch-minus::before { content: "\f4ba"; } -.bi-patch-plus-fill::before { content: "\f4bb"; } -.bi-patch-plus::before { content: "\f4bc"; } -.bi-patch-question-fill::before { content: "\f4bd"; } -.bi-patch-question::before { content: "\f4be"; } -.bi-pause-btn-fill::before { content: "\f4bf"; } -.bi-pause-btn::before { content: "\f4c0"; } -.bi-pause-circle-fill::before { content: "\f4c1"; } -.bi-pause-circle::before { content: "\f4c2"; } -.bi-pause-fill::before { content: "\f4c3"; } -.bi-pause::before { content: "\f4c4"; } -.bi-peace-fill::before { content: "\f4c5"; } -.bi-peace::before { content: "\f4c6"; } -.bi-pen-fill::before { content: "\f4c7"; } -.bi-pen::before { content: "\f4c8"; } -.bi-pencil-fill::before { content: "\f4c9"; } -.bi-pencil-square::before { content: "\f4ca"; } -.bi-pencil::before { content: "\f4cb"; } -.bi-pentagon-fill::before { content: "\f4cc"; } -.bi-pentagon-half::before { content: "\f4cd"; } -.bi-pentagon::before { content: "\f4ce"; } -.bi-people-fill::before { content: "\f4cf"; } -.bi-people::before { content: "\f4d0"; } -.bi-percent::before { content: "\f4d1"; } -.bi-person-badge-fill::before { content: "\f4d2"; } -.bi-person-badge::before { content: "\f4d3"; } -.bi-person-bounding-box::before { content: "\f4d4"; } -.bi-person-check-fill::before { content: "\f4d5"; } -.bi-person-check::before { content: "\f4d6"; } -.bi-person-circle::before { content: "\f4d7"; } -.bi-person-dash-fill::before { content: "\f4d8"; } -.bi-person-dash::before { content: "\f4d9"; } -.bi-person-fill::before { content: "\f4da"; } -.bi-person-lines-fill::before { content: "\f4db"; } -.bi-person-plus-fill::before { content: "\f4dc"; } -.bi-person-plus::before { content: "\f4dd"; } -.bi-person-square::before { content: "\f4de"; } -.bi-person-x-fill::before { content: "\f4df"; } -.bi-person-x::before { content: "\f4e0"; } -.bi-person::before { content: "\f4e1"; } -.bi-phone-fill::before { content: "\f4e2"; } -.bi-phone-landscape-fill::before { content: "\f4e3"; } -.bi-phone-landscape::before { content: "\f4e4"; } -.bi-phone-vibrate-fill::before { content: "\f4e5"; } -.bi-phone-vibrate::before { content: "\f4e6"; } -.bi-phone::before { content: "\f4e7"; } -.bi-pie-chart-fill::before { content: "\f4e8"; } -.bi-pie-chart::before { content: "\f4e9"; } -.bi-pin-angle-fill::before { content: "\f4ea"; } -.bi-pin-angle::before { content: "\f4eb"; } -.bi-pin-fill::before { content: "\f4ec"; } -.bi-pin::before { content: "\f4ed"; } -.bi-pip-fill::before { content: "\f4ee"; } -.bi-pip::before { content: "\f4ef"; } -.bi-play-btn-fill::before { content: "\f4f0"; } -.bi-play-btn::before { content: "\f4f1"; } -.bi-play-circle-fill::before { content: "\f4f2"; } -.bi-play-circle::before { content: "\f4f3"; } -.bi-play-fill::before { content: "\f4f4"; } -.bi-play::before { content: "\f4f5"; } -.bi-plug-fill::before { content: "\f4f6"; } -.bi-plug::before { content: "\f4f7"; } -.bi-plus-circle-dotted::before { content: "\f4f8"; } -.bi-plus-circle-fill::before { content: "\f4f9"; } -.bi-plus-circle::before { content: "\f4fa"; } -.bi-plus-square-dotted::before { content: "\f4fb"; } -.bi-plus-square-fill::before { content: "\f4fc"; } -.bi-plus-square::before { content: "\f4fd"; } -.bi-plus::before { content: "\f4fe"; } -.bi-power::before { content: "\f4ff"; } -.bi-printer-fill::before { content: "\f500"; } -.bi-printer::before { content: "\f501"; } -.bi-puzzle-fill::before { content: "\f502"; } -.bi-puzzle::before { content: "\f503"; } -.bi-question-circle-fill::before { content: "\f504"; } -.bi-question-circle::before { content: "\f505"; } -.bi-question-diamond-fill::before { content: "\f506"; } -.bi-question-diamond::before { content: "\f507"; } -.bi-question-octagon-fill::before { content: "\f508"; } -.bi-question-octagon::before { content: "\f509"; } -.bi-question-square-fill::before { content: "\f50a"; } -.bi-question-square::before { content: "\f50b"; } -.bi-question::before { content: "\f50c"; } -.bi-rainbow::before { content: "\f50d"; } -.bi-receipt-cutoff::before { content: "\f50e"; } -.bi-receipt::before { content: "\f50f"; } -.bi-reception-0::before { content: "\f510"; } -.bi-reception-1::before { content: "\f511"; } -.bi-reception-2::before { content: "\f512"; } -.bi-reception-3::before { content: "\f513"; } -.bi-reception-4::before { content: "\f514"; } -.bi-record-btn-fill::before { content: "\f515"; } -.bi-record-btn::before { content: "\f516"; } -.bi-record-circle-fill::before { content: "\f517"; } -.bi-record-circle::before { content: "\f518"; } -.bi-record-fill::before { content: "\f519"; } -.bi-record::before { content: "\f51a"; } -.bi-record2-fill::before { content: "\f51b"; } -.bi-record2::before { content: "\f51c"; } -.bi-reply-all-fill::before { content: "\f51d"; } -.bi-reply-all::before { content: "\f51e"; } -.bi-reply-fill::before { content: "\f51f"; } -.bi-reply::before { content: "\f520"; } -.bi-rss-fill::before { content: "\f521"; } -.bi-rss::before { content: "\f522"; } -.bi-rulers::before { content: "\f523"; } -.bi-save-fill::before { content: "\f524"; } -.bi-save::before { content: "\f525"; } -.bi-save2-fill::before { content: "\f526"; } -.bi-save2::before { content: "\f527"; } -.bi-scissors::before { content: "\f528"; } -.bi-screwdriver::before { content: "\f529"; } -.bi-search::before { content: "\f52a"; } -.bi-segmented-nav::before { content: "\f52b"; } -.bi-server::before { content: "\f52c"; } -.bi-share-fill::before { content: "\f52d"; } -.bi-share::before { content: "\f52e"; } -.bi-shield-check::before { content: "\f52f"; } -.bi-shield-exclamation::before { content: "\f530"; } -.bi-shield-fill-check::before { content: "\f531"; } -.bi-shield-fill-exclamation::before { content: "\f532"; } -.bi-shield-fill-minus::before { content: "\f533"; } -.bi-shield-fill-plus::before { content: "\f534"; } -.bi-shield-fill-x::before { content: "\f535"; } -.bi-shield-fill::before { content: "\f536"; } -.bi-shield-lock-fill::before { content: "\f537"; } -.bi-shield-lock::before { content: "\f538"; } -.bi-shield-minus::before { content: "\f539"; } -.bi-shield-plus::before { content: "\f53a"; } -.bi-shield-shaded::before { content: "\f53b"; } -.bi-shield-slash-fill::before { content: "\f53c"; } -.bi-shield-slash::before { content: "\f53d"; } -.bi-shield-x::before { content: "\f53e"; } -.bi-shield::before { content: "\f53f"; } -.bi-shift-fill::before { content: "\f540"; } -.bi-shift::before { content: "\f541"; } -.bi-shop-window::before { content: "\f542"; } -.bi-shop::before { content: "\f543"; } -.bi-shuffle::before { content: "\f544"; } -.bi-signpost-2-fill::before { content: "\f545"; } -.bi-signpost-2::before { content: "\f546"; } -.bi-signpost-fill::before { content: "\f547"; } -.bi-signpost-split-fill::before { content: "\f548"; } -.bi-signpost-split::before { content: "\f549"; } -.bi-signpost::before { content: "\f54a"; } -.bi-sim-fill::before { content: "\f54b"; } -.bi-sim::before { content: "\f54c"; } -.bi-skip-backward-btn-fill::before { content: "\f54d"; } -.bi-skip-backward-btn::before { content: "\f54e"; } -.bi-skip-backward-circle-fill::before { content: "\f54f"; } -.bi-skip-backward-circle::before { content: "\f550"; } -.bi-skip-backward-fill::before { content: "\f551"; } -.bi-skip-backward::before { content: "\f552"; } -.bi-skip-end-btn-fill::before { content: "\f553"; } -.bi-skip-end-btn::before { content: "\f554"; } -.bi-skip-end-circle-fill::before { content: "\f555"; } -.bi-skip-end-circle::before { content: "\f556"; } -.bi-skip-end-fill::before { content: "\f557"; } -.bi-skip-end::before { content: "\f558"; } -.bi-skip-forward-btn-fill::before { content: "\f559"; } -.bi-skip-forward-btn::before { content: "\f55a"; } -.bi-skip-forward-circle-fill::before { content: "\f55b"; } -.bi-skip-forward-circle::before { content: "\f55c"; } -.bi-skip-forward-fill::before { content: "\f55d"; } -.bi-skip-forward::before { content: "\f55e"; } -.bi-skip-start-btn-fill::before { content: "\f55f"; } -.bi-skip-start-btn::before { content: "\f560"; } -.bi-skip-start-circle-fill::before { content: "\f561"; } -.bi-skip-start-circle::before { content: "\f562"; } -.bi-skip-start-fill::before { content: "\f563"; } -.bi-skip-start::before { content: "\f564"; } -.bi-slack::before { content: "\f565"; } -.bi-slash-circle-fill::before { content: "\f566"; } -.bi-slash-circle::before { content: "\f567"; } -.bi-slash-square-fill::before { content: "\f568"; } -.bi-slash-square::before { content: "\f569"; } -.bi-slash::before { content: "\f56a"; } -.bi-sliders::before { content: "\f56b"; } -.bi-smartwatch::before { content: "\f56c"; } -.bi-snow::before { content: "\f56d"; } -.bi-snow2::before { content: "\f56e"; } -.bi-snow3::before { content: "\f56f"; } -.bi-sort-alpha-down-alt::before { content: "\f570"; } -.bi-sort-alpha-down::before { content: "\f571"; } -.bi-sort-alpha-up-alt::before { content: "\f572"; } -.bi-sort-alpha-up::before { content: "\f573"; } -.bi-sort-down-alt::before { content: "\f574"; } -.bi-sort-down::before { content: "\f575"; } -.bi-sort-numeric-down-alt::before { content: "\f576"; } -.bi-sort-numeric-down::before { content: "\f577"; } -.bi-sort-numeric-up-alt::before { content: "\f578"; } -.bi-sort-numeric-up::before { content: "\f579"; } -.bi-sort-up-alt::before { content: "\f57a"; } -.bi-sort-up::before { content: "\f57b"; } -.bi-soundwave::before { content: "\f57c"; } -.bi-speaker-fill::before { content: "\f57d"; } -.bi-speaker::before { content: "\f57e"; } -.bi-speedometer::before { content: "\f57f"; } -.bi-speedometer2::before { content: "\f580"; } -.bi-spellcheck::before { content: "\f581"; } -.bi-square-fill::before { content: "\f582"; } -.bi-square-half::before { content: "\f583"; } -.bi-square::before { content: "\f584"; } -.bi-stack::before { content: "\f585"; } -.bi-star-fill::before { content: "\f586"; } -.bi-star-half::before { content: "\f587"; } -.bi-star::before { content: "\f588"; } -.bi-stars::before { content: "\f589"; } -.bi-stickies-fill::before { content: "\f58a"; } -.bi-stickies::before { content: "\f58b"; } -.bi-sticky-fill::before { content: "\f58c"; } -.bi-sticky::before { content: "\f58d"; } -.bi-stop-btn-fill::before { content: "\f58e"; } -.bi-stop-btn::before { content: "\f58f"; } -.bi-stop-circle-fill::before { content: "\f590"; } -.bi-stop-circle::before { content: "\f591"; } -.bi-stop-fill::before { content: "\f592"; } -.bi-stop::before { content: "\f593"; } -.bi-stoplights-fill::before { content: "\f594"; } -.bi-stoplights::before { content: "\f595"; } -.bi-stopwatch-fill::before { content: "\f596"; } -.bi-stopwatch::before { content: "\f597"; } -.bi-subtract::before { content: "\f598"; } -.bi-suit-club-fill::before { content: "\f599"; } -.bi-suit-club::before { content: "\f59a"; } -.bi-suit-diamond-fill::before { content: "\f59b"; } -.bi-suit-diamond::before { content: "\f59c"; } -.bi-suit-heart-fill::before { content: "\f59d"; } -.bi-suit-heart::before { content: "\f59e"; } -.bi-suit-spade-fill::before { content: "\f59f"; } -.bi-suit-spade::before { content: "\f5a0"; } -.bi-sun-fill::before { content: "\f5a1"; } -.bi-sun::before { content: "\f5a2"; } -.bi-sunglasses::before { content: "\f5a3"; } -.bi-sunrise-fill::before { content: "\f5a4"; } -.bi-sunrise::before { content: "\f5a5"; } -.bi-sunset-fill::before { content: "\f5a6"; } -.bi-sunset::before { content: "\f5a7"; } -.bi-symmetry-horizontal::before { content: "\f5a8"; } -.bi-symmetry-vertical::before { content: "\f5a9"; } -.bi-table::before { content: "\f5aa"; } -.bi-tablet-fill::before { content: "\f5ab"; } -.bi-tablet-landscape-fill::before { content: "\f5ac"; } -.bi-tablet-landscape::before { content: "\f5ad"; } -.bi-tablet::before { content: "\f5ae"; } -.bi-tag-fill::before { content: "\f5af"; } -.bi-tag::before { content: "\f5b0"; } -.bi-tags-fill::before { content: "\f5b1"; } -.bi-tags::before { content: "\f5b2"; } -.bi-telegram::before { content: "\f5b3"; } -.bi-telephone-fill::before { content: "\f5b4"; } -.bi-telephone-forward-fill::before { content: "\f5b5"; } -.bi-telephone-forward::before { content: "\f5b6"; } -.bi-telephone-inbound-fill::before { content: "\f5b7"; } -.bi-telephone-inbound::before { content: "\f5b8"; } -.bi-telephone-minus-fill::before { content: "\f5b9"; } -.bi-telephone-minus::before { content: "\f5ba"; } -.bi-telephone-outbound-fill::before { content: "\f5bb"; } -.bi-telephone-outbound::before { content: "\f5bc"; } -.bi-telephone-plus-fill::before { content: "\f5bd"; } -.bi-telephone-plus::before { content: "\f5be"; } -.bi-telephone-x-fill::before { content: "\f5bf"; } -.bi-telephone-x::before { content: "\f5c0"; } -.bi-telephone::before { content: "\f5c1"; } -.bi-terminal-fill::before { content: "\f5c2"; } -.bi-terminal::before { content: "\f5c3"; } -.bi-text-center::before { content: "\f5c4"; } -.bi-text-indent-left::before { content: "\f5c5"; } -.bi-text-indent-right::before { content: "\f5c6"; } -.bi-text-left::before { content: "\f5c7"; } -.bi-text-paragraph::before { content: "\f5c8"; } -.bi-text-right::before { content: "\f5c9"; } -.bi-textarea-resize::before { content: "\f5ca"; } -.bi-textarea-t::before { content: "\f5cb"; } -.bi-textarea::before { content: "\f5cc"; } -.bi-thermometer-half::before { content: "\f5cd"; } -.bi-thermometer-high::before { content: "\f5ce"; } -.bi-thermometer-low::before { content: "\f5cf"; } -.bi-thermometer-snow::before { content: "\f5d0"; } -.bi-thermometer-sun::before { content: "\f5d1"; } -.bi-thermometer::before { content: "\f5d2"; } -.bi-three-dots-vertical::before { content: "\f5d3"; } -.bi-three-dots::before { content: "\f5d4"; } -.bi-toggle-off::before { content: "\f5d5"; } -.bi-toggle-on::before { content: "\f5d6"; } -.bi-toggle2-off::before { content: "\f5d7"; } -.bi-toggle2-on::before { content: "\f5d8"; } -.bi-toggles::before { content: "\f5d9"; } -.bi-toggles2::before { content: "\f5da"; } -.bi-tools::before { content: "\f5db"; } -.bi-tornado::before { content: "\f5dc"; } -.bi-trash-fill::before { content: "\f5dd"; } -.bi-trash::before { content: "\f5de"; } -.bi-trash2-fill::before { content: "\f5df"; } -.bi-trash2::before { content: "\f5e0"; } -.bi-tree-fill::before { content: "\f5e1"; } -.bi-tree::before { content: "\f5e2"; } -.bi-triangle-fill::before { content: "\f5e3"; } -.bi-triangle-half::before { content: "\f5e4"; } -.bi-triangle::before { content: "\f5e5"; } -.bi-trophy-fill::before { content: "\f5e6"; } -.bi-trophy::before { content: "\f5e7"; } -.bi-tropical-storm::before { content: "\f5e8"; } -.bi-truck-flatbed::before { content: "\f5e9"; } -.bi-truck::before { content: "\f5ea"; } -.bi-tsunami::before { content: "\f5eb"; } -.bi-tv-fill::before { content: "\f5ec"; } -.bi-tv::before { content: "\f5ed"; } -.bi-twitch::before { content: "\f5ee"; } -.bi-twitter::before { content: "\f5ef"; } -.bi-type-bold::before { content: "\f5f0"; } -.bi-type-h1::before { content: "\f5f1"; } -.bi-type-h2::before { content: "\f5f2"; } -.bi-type-h3::before { content: "\f5f3"; } -.bi-type-italic::before { content: "\f5f4"; } -.bi-type-strikethrough::before { content: "\f5f5"; } -.bi-type-underline::before { content: "\f5f6"; } -.bi-type::before { content: "\f5f7"; } -.bi-ui-checks-grid::before { content: "\f5f8"; } -.bi-ui-checks::before { content: "\f5f9"; } -.bi-ui-radios-grid::before { content: "\f5fa"; } -.bi-ui-radios::before { content: "\f5fb"; } -.bi-umbrella-fill::before { content: "\f5fc"; } -.bi-umbrella::before { content: "\f5fd"; } -.bi-union::before { content: "\f5fe"; } -.bi-unlock-fill::before { content: "\f5ff"; } -.bi-unlock::before { content: "\f600"; } -.bi-upc-scan::before { content: "\f601"; } -.bi-upc::before { content: "\f602"; } -.bi-upload::before { content: "\f603"; } -.bi-vector-pen::before { content: "\f604"; } -.bi-view-list::before { content: "\f605"; } -.bi-view-stacked::before { content: "\f606"; } -.bi-vinyl-fill::before { content: "\f607"; } -.bi-vinyl::before { content: "\f608"; } -.bi-voicemail::before { content: "\f609"; } -.bi-volume-down-fill::before { content: "\f60a"; } -.bi-volume-down::before { content: "\f60b"; } -.bi-volume-mute-fill::before { content: "\f60c"; } -.bi-volume-mute::before { content: "\f60d"; } -.bi-volume-off-fill::before { content: "\f60e"; } -.bi-volume-off::before { content: "\f60f"; } -.bi-volume-up-fill::before { content: "\f610"; } -.bi-volume-up::before { content: "\f611"; } -.bi-vr::before { content: "\f612"; } -.bi-wallet-fill::before { content: "\f613"; } -.bi-wallet::before { content: "\f614"; } -.bi-wallet2::before { content: "\f615"; } -.bi-watch::before { content: "\f616"; } -.bi-water::before { content: "\f617"; } -.bi-whatsapp::before { content: "\f618"; } -.bi-wifi-1::before { content: "\f619"; } -.bi-wifi-2::before { content: "\f61a"; } -.bi-wifi-off::before { content: "\f61b"; } -.bi-wifi::before { content: "\f61c"; } -.bi-wind::before { content: "\f61d"; } -.bi-window-dock::before { content: "\f61e"; } -.bi-window-sidebar::before { content: "\f61f"; } -.bi-window::before { content: "\f620"; } -.bi-wrench::before { content: "\f621"; } -.bi-x-circle-fill::before { content: "\f622"; } -.bi-x-circle::before { content: "\f623"; } -.bi-x-diamond-fill::before { content: "\f624"; } -.bi-x-diamond::before { content: "\f625"; } -.bi-x-octagon-fill::before { content: "\f626"; } -.bi-x-octagon::before { content: "\f627"; } -.bi-x-square-fill::before { content: "\f628"; } -.bi-x-square::before { content: "\f629"; } -.bi-x::before { content: "\f62a"; } -.bi-youtube::before { content: "\f62b"; } -.bi-zoom-in::before { content: "\f62c"; } -.bi-zoom-out::before { content: "\f62d"; } -.bi-bank::before { content: "\f62e"; } -.bi-bank2::before { content: "\f62f"; } -.bi-bell-slash-fill::before { content: "\f630"; } -.bi-bell-slash::before { content: "\f631"; } -.bi-cash-coin::before { content: "\f632"; } -.bi-check-lg::before { content: "\f633"; } -.bi-coin::before { content: "\f634"; } -.bi-currency-bitcoin::before { content: "\f635"; } -.bi-currency-dollar::before { content: "\f636"; } -.bi-currency-euro::before { content: "\f637"; } -.bi-currency-exchange::before { content: "\f638"; } -.bi-currency-pound::before { content: "\f639"; } -.bi-currency-yen::before { content: "\f63a"; } -.bi-dash-lg::before { content: "\f63b"; } -.bi-exclamation-lg::before { content: "\f63c"; } -.bi-file-earmark-pdf-fill::before { content: "\f63d"; } -.bi-file-earmark-pdf::before { content: "\f63e"; } -.bi-file-pdf-fill::before { content: "\f63f"; } -.bi-file-pdf::before { content: "\f640"; } -.bi-gender-ambiguous::before { content: "\f641"; } -.bi-gender-female::before { content: "\f642"; } -.bi-gender-male::before { content: "\f643"; } -.bi-gender-trans::before { content: "\f644"; } -.bi-headset-vr::before { content: "\f645"; } -.bi-info-lg::before { content: "\f646"; } -.bi-mastodon::before { content: "\f647"; } -.bi-messenger::before { content: "\f648"; } -.bi-piggy-bank-fill::before { content: "\f649"; } -.bi-piggy-bank::before { content: "\f64a"; } -.bi-pin-map-fill::before { content: "\f64b"; } -.bi-pin-map::before { content: "\f64c"; } -.bi-plus-lg::before { content: "\f64d"; } -.bi-question-lg::before { content: "\f64e"; } -.bi-recycle::before { content: "\f64f"; } -.bi-reddit::before { content: "\f650"; } -.bi-safe-fill::before { content: "\f651"; } -.bi-safe2-fill::before { content: "\f652"; } -.bi-safe2::before { content: "\f653"; } -.bi-sd-card-fill::before { content: "\f654"; } -.bi-sd-card::before { content: "\f655"; } -.bi-skype::before { content: "\f656"; } -.bi-slash-lg::before { content: "\f657"; } -.bi-translate::before { content: "\f658"; } -.bi-x-lg::before { content: "\f659"; } -.bi-safe::before { content: "\f65a"; } -.bi-apple::before { content: "\f65b"; } -.bi-microsoft::before { content: "\f65d"; } -.bi-windows::before { content: "\f65e"; } -.bi-behance::before { content: "\f65c"; } -.bi-dribbble::before { content: "\f65f"; } -.bi-line::before { content: "\f660"; } -.bi-medium::before { content: "\f661"; } -.bi-paypal::before { content: "\f662"; } -.bi-pinterest::before { content: "\f663"; } -.bi-signal::before { content: "\f664"; } -.bi-snapchat::before { content: "\f665"; } -.bi-spotify::before { content: "\f666"; } -.bi-stack-overflow::before { content: "\f667"; } -.bi-strava::before { content: "\f668"; } -.bi-wordpress::before { content: "\f669"; } -.bi-vimeo::before { content: "\f66a"; } -.bi-activity::before { content: "\f66b"; } -.bi-easel2-fill::before { content: "\f66c"; } -.bi-easel2::before { content: "\f66d"; } -.bi-easel3-fill::before { content: "\f66e"; } -.bi-easel3::before { content: "\f66f"; } -.bi-fan::before { content: "\f670"; } -.bi-fingerprint::before { content: "\f671"; } -.bi-graph-down-arrow::before { content: "\f672"; } -.bi-graph-up-arrow::before { content: "\f673"; } -.bi-hypnotize::before { content: "\f674"; } -.bi-magic::before { content: "\f675"; } -.bi-person-rolodex::before { content: "\f676"; } -.bi-person-video::before { content: "\f677"; } -.bi-person-video2::before { content: "\f678"; } -.bi-person-video3::before { content: "\f679"; } -.bi-person-workspace::before { content: "\f67a"; } -.bi-radioactive::before { content: "\f67b"; } -.bi-webcam-fill::before { content: "\f67c"; } -.bi-webcam::before { content: "\f67d"; } -.bi-yin-yang::before { content: "\f67e"; } -.bi-bandaid-fill::before { content: "\f680"; } -.bi-bandaid::before { content: "\f681"; } -.bi-bluetooth::before { content: "\f682"; } -.bi-body-text::before { content: "\f683"; } -.bi-boombox::before { content: "\f684"; } -.bi-boxes::before { content: "\f685"; } -.bi-dpad-fill::before { content: "\f686"; } -.bi-dpad::before { content: "\f687"; } -.bi-ear-fill::before { content: "\f688"; } -.bi-ear::before { content: "\f689"; } -.bi-envelope-check-1::before { content: "\f68a"; } -.bi-envelope-check-fill::before { content: "\f68b"; } -.bi-envelope-check::before { content: "\f68c"; } -.bi-envelope-dash-1::before { content: "\f68d"; } -.bi-envelope-dash-fill::before { content: "\f68e"; } -.bi-envelope-dash::before { content: "\f68f"; } -.bi-envelope-exclamation-1::before { content: "\f690"; } -.bi-envelope-exclamation-fill::before { content: "\f691"; } -.bi-envelope-exclamation::before { content: "\f692"; } -.bi-envelope-plus-fill::before { content: "\f693"; } -.bi-envelope-plus::before { content: "\f694"; } -.bi-envelope-slash-1::before { content: "\f695"; } -.bi-envelope-slash-fill::before { content: "\f696"; } -.bi-envelope-slash::before { content: "\f697"; } -.bi-envelope-x-1::before { content: "\f698"; } -.bi-envelope-x-fill::before { content: "\f699"; } -.bi-envelope-x::before { content: "\f69a"; } -.bi-explicit-fill::before { content: "\f69b"; } -.bi-explicit::before { content: "\f69c"; } -.bi-git::before { content: "\f69d"; } -.bi-infinity::before { content: "\f69e"; } -.bi-list-columns-reverse::before { content: "\f69f"; } -.bi-list-columns::before { content: "\f6a0"; } -.bi-meta::before { content: "\f6a1"; } -.bi-mortorboard-fill::before { content: "\f6a2"; } -.bi-mortorboard::before { content: "\f6a3"; } -.bi-nintendo-switch::before { content: "\f6a4"; } -.bi-pc-display-horizontal::before { content: "\f6a5"; } -.bi-pc-display::before { content: "\f6a6"; } -.bi-pc-horizontal::before { content: "\f6a7"; } -.bi-pc::before { content: "\f6a8"; } -.bi-playstation::before { content: "\f6a9"; } -.bi-plus-slash-minus::before { content: "\f6aa"; } -.bi-projector-fill::before { content: "\f6ab"; } -.bi-projector::before { content: "\f6ac"; } -.bi-qr-code-scan::before { content: "\f6ad"; } -.bi-qr-code::before { content: "\f6ae"; } -.bi-quora::before { content: "\f6af"; } -.bi-quote::before { content: "\f6b0"; } -.bi-robot::before { content: "\f6b1"; } -.bi-send-check-fill::before { content: "\f6b2"; } -.bi-send-check::before { content: "\f6b3"; } -.bi-send-dash-fill::before { content: "\f6b4"; } -.bi-send-dash::before { content: "\f6b5"; } -.bi-send-exclamation-1::before { content: "\f6b6"; } -.bi-send-exclamation-fill::before { content: "\f6b7"; } -.bi-send-exclamation::before { content: "\f6b8"; } -.bi-send-fill::before { content: "\f6b9"; } -.bi-send-plus-fill::before { content: "\f6ba"; } -.bi-send-plus::before { content: "\f6bb"; } -.bi-send-slash-fill::before { content: "\f6bc"; } -.bi-send-slash::before { content: "\f6bd"; } -.bi-send-x-fill::before { content: "\f6be"; } -.bi-send-x::before { content: "\f6bf"; } -.bi-send::before { content: "\f6c0"; } -.bi-steam::before { content: "\f6c1"; } -.bi-terminal-dash-1::before { content: "\f6c2"; } -.bi-terminal-dash::before { content: "\f6c3"; } -.bi-terminal-plus::before { content: "\f6c4"; } -.bi-terminal-split::before { content: "\f6c5"; } -.bi-ticket-detailed-fill::before { content: "\f6c6"; } -.bi-ticket-detailed::before { content: "\f6c7"; } -.bi-ticket-fill::before { content: "\f6c8"; } -.bi-ticket-perforated-fill::before { content: "\f6c9"; } -.bi-ticket-perforated::before { content: "\f6ca"; } -.bi-ticket::before { content: "\f6cb"; } -.bi-tiktok::before { content: "\f6cc"; } -.bi-window-dash::before { content: "\f6cd"; } -.bi-window-desktop::before { content: "\f6ce"; } -.bi-window-fullscreen::before { content: "\f6cf"; } -.bi-window-plus::before { content: "\f6d0"; } -.bi-window-split::before { content: "\f6d1"; } -.bi-window-stack::before { content: "\f6d2"; } -.bi-window-x::before { content: "\f6d3"; } -.bi-xbox::before { content: "\f6d4"; } -.bi-ethernet::before { content: "\f6d5"; } -.bi-hdmi-fill::before { content: "\f6d6"; } -.bi-hdmi::before { content: "\f6d7"; } -.bi-usb-c-fill::before { content: "\f6d8"; } -.bi-usb-c::before { content: "\f6d9"; } -.bi-usb-fill::before { content: "\f6da"; } -.bi-usb-plug-fill::before { content: "\f6db"; } -.bi-usb-plug::before { content: "\f6dc"; } -.bi-usb-symbol::before { content: "\f6dd"; } -.bi-usb::before { content: "\f6de"; } -.bi-boombox-fill::before { content: "\f6df"; } -.bi-displayport-1::before { content: "\f6e0"; } -.bi-displayport::before { content: "\f6e1"; } -.bi-gpu-card::before { content: "\f6e2"; } -.bi-memory::before { content: "\f6e3"; } -.bi-modem-fill::before { content: "\f6e4"; } -.bi-modem::before { content: "\f6e5"; } -.bi-motherboard-fill::before { content: "\f6e6"; } -.bi-motherboard::before { content: "\f6e7"; } -.bi-optical-audio-fill::before { content: "\f6e8"; } -.bi-optical-audio::before { content: "\f6e9"; } -.bi-pci-card::before { content: "\f6ea"; } -.bi-router-fill::before { content: "\f6eb"; } -.bi-router::before { content: "\f6ec"; } -.bi-ssd-fill::before { content: "\f6ed"; } -.bi-ssd::before { content: "\f6ee"; } -.bi-thunderbolt-fill::before { content: "\f6ef"; } -.bi-thunderbolt::before { content: "\f6f0"; } -.bi-usb-drive-fill::before { content: "\f6f1"; } -.bi-usb-drive::before { content: "\f6f2"; } -.bi-usb-micro-fill::before { content: "\f6f3"; } -.bi-usb-micro::before { content: "\f6f4"; } -.bi-usb-mini-fill::before { content: "\f6f5"; } -.bi-usb-mini::before { content: "\f6f6"; } -.bi-cloud-haze2::before { content: "\f6f7"; } -.bi-device-hdd-fill::before { content: "\f6f8"; } -.bi-device-hdd::before { content: "\f6f9"; } -.bi-device-ssd-fill::before { content: "\f6fa"; } -.bi-device-ssd::before { content: "\f6fb"; } -.bi-displayport-fill::before { content: "\f6fc"; } -.bi-mortarboard-fill::before { content: "\f6fd"; } -.bi-mortarboard::before { content: "\f6fe"; } -.bi-terminal-x::before { content: "\f6ff"; } -.bi-arrow-through-heart-fill::before { content: "\f700"; } -.bi-arrow-through-heart::before { content: "\f701"; } -.bi-badge-sd-fill::before { content: "\f702"; } -.bi-badge-sd::before { content: "\f703"; } -.bi-bag-heart-fill::before { content: "\f704"; } -.bi-bag-heart::before { content: "\f705"; } -.bi-balloon-fill::before { content: "\f706"; } -.bi-balloon-heart-fill::before { content: "\f707"; } -.bi-balloon-heart::before { content: "\f708"; } -.bi-balloon::before { content: "\f709"; } -.bi-box2-fill::before { content: "\f70a"; } -.bi-box2-heart-fill::before { content: "\f70b"; } -.bi-box2-heart::before { content: "\f70c"; } -.bi-box2::before { content: "\f70d"; } -.bi-braces-asterisk::before { content: "\f70e"; } -.bi-calendar-heart-fill::before { content: "\f70f"; } -.bi-calendar-heart::before { content: "\f710"; } -.bi-calendar2-heart-fill::before { content: "\f711"; } -.bi-calendar2-heart::before { content: "\f712"; } -.bi-chat-heart-fill::before { content: "\f713"; } -.bi-chat-heart::before { content: "\f714"; } -.bi-chat-left-heart-fill::before { content: "\f715"; } -.bi-chat-left-heart::before { content: "\f716"; } -.bi-chat-right-heart-fill::before { content: "\f717"; } -.bi-chat-right-heart::before { content: "\f718"; } -.bi-chat-square-heart-fill::before { content: "\f719"; } -.bi-chat-square-heart::before { content: "\f71a"; } -.bi-clipboard-check-fill::before { content: "\f71b"; } -.bi-clipboard-data-fill::before { content: "\f71c"; } -.bi-clipboard-fill::before { content: "\f71d"; } -.bi-clipboard-heart-fill::before { content: "\f71e"; } -.bi-clipboard-heart::before { content: "\f71f"; } -.bi-clipboard-minus-fill::before { content: "\f720"; } -.bi-clipboard-plus-fill::before { content: "\f721"; } -.bi-clipboard-pulse::before { content: "\f722"; } -.bi-clipboard-x-fill::before { content: "\f723"; } -.bi-clipboard2-check-fill::before { content: "\f724"; } -.bi-clipboard2-check::before { content: "\f725"; } -.bi-clipboard2-data-fill::before { content: "\f726"; } -.bi-clipboard2-data::before { content: "\f727"; } -.bi-clipboard2-fill::before { content: "\f728"; } -.bi-clipboard2-heart-fill::before { content: "\f729"; } -.bi-clipboard2-heart::before { content: "\f72a"; } -.bi-clipboard2-minus-fill::before { content: "\f72b"; } -.bi-clipboard2-minus::before { content: "\f72c"; } -.bi-clipboard2-plus-fill::before { content: "\f72d"; } -.bi-clipboard2-plus::before { content: "\f72e"; } -.bi-clipboard2-pulse-fill::before { content: "\f72f"; } -.bi-clipboard2-pulse::before { content: "\f730"; } -.bi-clipboard2-x-fill::before { content: "\f731"; } -.bi-clipboard2-x::before { content: "\f732"; } -.bi-clipboard2::before { content: "\f733"; } -.bi-emoji-kiss-fill::before { content: "\f734"; } -.bi-emoji-kiss::before { content: "\f735"; } -.bi-envelope-heart-fill::before { content: "\f736"; } -.bi-envelope-heart::before { content: "\f737"; } -.bi-envelope-open-heart-fill::before { content: "\f738"; } -.bi-envelope-open-heart::before { content: "\f739"; } -.bi-envelope-paper-fill::before { content: "\f73a"; } -.bi-envelope-paper-heart-fill::before { content: "\f73b"; } -.bi-envelope-paper-heart::before { content: "\f73c"; } -.bi-envelope-paper::before { content: "\f73d"; } -.bi-filetype-aac::before { content: "\f73e"; } -.bi-filetype-ai::before { content: "\f73f"; } -.bi-filetype-bmp::before { content: "\f740"; } -.bi-filetype-cs::before { content: "\f741"; } -.bi-filetype-css::before { content: "\f742"; } -.bi-filetype-csv::before { content: "\f743"; } -.bi-filetype-doc::before { content: "\f744"; } -.bi-filetype-docx::before { content: "\f745"; } -.bi-filetype-exe::before { content: "\f746"; } -.bi-filetype-gif::before { content: "\f747"; } -.bi-filetype-heic::before { content: "\f748"; } -.bi-filetype-html::before { content: "\f749"; } -.bi-filetype-java::before { content: "\f74a"; } -.bi-filetype-jpg::before { content: "\f74b"; } -.bi-filetype-js::before { content: "\f74c"; } -.bi-filetype-jsx::before { content: "\f74d"; } -.bi-filetype-key::before { content: "\f74e"; } -.bi-filetype-m4p::before { content: "\f74f"; } -.bi-filetype-md::before { content: "\f750"; } -.bi-filetype-mdx::before { content: "\f751"; } -.bi-filetype-mov::before { content: "\f752"; } -.bi-filetype-mp3::before { content: "\f753"; } -.bi-filetype-mp4::before { content: "\f754"; } -.bi-filetype-otf::before { content: "\f755"; } -.bi-filetype-pdf::before { content: "\f756"; } -.bi-filetype-php::before { content: "\f757"; } -.bi-filetype-png::before { content: "\f758"; } -.bi-filetype-ppt-1::before { content: "\f759"; } -.bi-filetype-ppt::before { content: "\f75a"; } -.bi-filetype-psd::before { content: "\f75b"; } -.bi-filetype-py::before { content: "\f75c"; } -.bi-filetype-raw::before { content: "\f75d"; } -.bi-filetype-rb::before { content: "\f75e"; } -.bi-filetype-sass::before { content: "\f75f"; } -.bi-filetype-scss::before { content: "\f760"; } -.bi-filetype-sh::before { content: "\f761"; } -.bi-filetype-svg::before { content: "\f762"; } -.bi-filetype-tiff::before { content: "\f763"; } -.bi-filetype-tsx::before { content: "\f764"; } -.bi-filetype-ttf::before { content: "\f765"; } -.bi-filetype-txt::before { content: "\f766"; } -.bi-filetype-wav::before { content: "\f767"; } -.bi-filetype-woff::before { content: "\f768"; } -.bi-filetype-xls-1::before { content: "\f769"; } -.bi-filetype-xls::before { content: "\f76a"; } -.bi-filetype-xml::before { content: "\f76b"; } -.bi-filetype-yml::before { content: "\f76c"; } -.bi-heart-arrow::before { content: "\f76d"; } -.bi-heart-pulse-fill::before { content: "\f76e"; } -.bi-heart-pulse::before { content: "\f76f"; } -.bi-heartbreak-fill::before { content: "\f770"; } -.bi-heartbreak::before { content: "\f771"; } -.bi-hearts::before { content: "\f772"; } -.bi-hospital-fill::before { content: "\f773"; } -.bi-hospital::before { content: "\f774"; } -.bi-house-heart-fill::before { content: "\f775"; } -.bi-house-heart::before { content: "\f776"; } -.bi-incognito::before { content: "\f777"; } -.bi-magnet-fill::before { content: "\f778"; } -.bi-magnet::before { content: "\f779"; } -.bi-person-heart::before { content: "\f77a"; } -.bi-person-hearts::before { content: "\f77b"; } -.bi-phone-flip::before { content: "\f77c"; } -.bi-plugin::before { content: "\f77d"; } -.bi-postage-fill::before { content: "\f77e"; } -.bi-postage-heart-fill::before { content: "\f77f"; } -.bi-postage-heart::before { content: "\f780"; } -.bi-postage::before { content: "\f781"; } -.bi-postcard-fill::before { content: "\f782"; } -.bi-postcard-heart-fill::before { content: "\f783"; } -.bi-postcard-heart::before { content: "\f784"; } -.bi-postcard::before { content: "\f785"; } -.bi-search-heart-fill::before { content: "\f786"; } -.bi-search-heart::before { content: "\f787"; } -.bi-sliders2-vertical::before { content: "\f788"; } -.bi-sliders2::before { content: "\f789"; } -.bi-trash3-fill::before { content: "\f78a"; } -.bi-trash3::before { content: "\f78b"; } -.bi-valentine::before { content: "\f78c"; } -.bi-valentine2::before { content: "\f78d"; } -.bi-wrench-adjustable-circle-fill::before { content: "\f78e"; } -.bi-wrench-adjustable-circle::before { content: "\f78f"; } -.bi-wrench-adjustable::before { content: "\f790"; } -.bi-filetype-json::before { content: "\f791"; } -.bi-filetype-pptx::before { content: "\f792"; } -.bi-filetype-xlsx::before { content: "\f793"; } diff --git a/docs/site_libs/bootstrap/bootstrap-icons.woff b/docs/site_libs/bootstrap/bootstrap-icons.woff deleted file mode 100644 index b26ccd1a..00000000 Binary files a/docs/site_libs/bootstrap/bootstrap-icons.woff and /dev/null differ diff --git a/docs/site_libs/bootstrap/bootstrap.min.css b/docs/site_libs/bootstrap/bootstrap.min.css deleted file mode 100644 index 96256fdd..00000000 --- a/docs/site_libs/bootstrap/bootstrap.min.css +++ /dev/null @@ -1,10 +0,0 @@ -/*! - * Bootstrap v5.1.3 (https://getbootstrap.com/) - * Copyright 2011-2021 The Bootstrap Authors - * Copyright 2011-2021 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */@import"https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@300;400;700&display=swap";:root{--bs-blue: #2780e3;--bs-indigo: #6610f2;--bs-purple: #613d7c;--bs-pink: #e83e8c;--bs-red: #ff0039;--bs-orange: #f0ad4e;--bs-yellow: #ff7518;--bs-green: #3fb618;--bs-teal: #20c997;--bs-cyan: #9954bb;--bs-white: #fff;--bs-gray: #6c757d;--bs-gray-dark: #373a3c;--bs-gray-100: #f8f9fa;--bs-gray-200: #e9ecef;--bs-gray-300: #dee2e6;--bs-gray-400: #ced4da;--bs-gray-500: #adb5bd;--bs-gray-600: #6c757d;--bs-gray-700: #495057;--bs-gray-800: #373a3c;--bs-gray-900: #212529;--bs-default: #373a3c;--bs-primary: #2780e3;--bs-secondary: #373a3c;--bs-success: #3fb618;--bs-info: #9954bb;--bs-warning: #ff7518;--bs-danger: #ff0039;--bs-light: #f8f9fa;--bs-dark: #373a3c;--bs-default-rgb: 55, 58, 60;--bs-primary-rgb: 39, 128, 227;--bs-secondary-rgb: 55, 58, 60;--bs-success-rgb: 63, 182, 24;--bs-info-rgb: 153, 84, 187;--bs-warning-rgb: 255, 117, 24;--bs-danger-rgb: 255, 0, 57;--bs-light-rgb: 248, 249, 250;--bs-dark-rgb: 55, 58, 60;--bs-white-rgb: 255, 255, 255;--bs-black-rgb: 0, 0, 0;--bs-body-color-rgb: 55, 58, 60;--bs-body-bg-rgb: 255, 255, 255;--bs-font-sans-serif: "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-root-font-size: 18px;--bs-body-font-family: var(--bs-font-sans-serif);--bs-body-font-size: 1rem;--bs-body-font-weight: 400;--bs-body-line-height: 1.5;--bs-body-color: #373a3c;--bs-body-bg: #fff}*,*::before,*::after{box-sizing:border-box}:root{font-size:var(--bs-root-font-size)}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h6,.h6,h5,.h5,h4,.h4,h3,.h3,h2,.h2,h1,.h1{margin-top:0;margin-bottom:.5rem;font-weight:400;line-height:1.2}h1,.h1{font-size:calc(1.345rem + 1.14vw)}@media(min-width: 1200px){h1,.h1{font-size:2.2rem}}h2,.h2{font-size:calc(1.3rem + 0.6vw)}@media(min-width: 1200px){h2,.h2{font-size:1.75rem}}h3,.h3{font-size:calc(1.275rem + 0.3vw)}@media(min-width: 1200px){h3,.h3{font-size:1.5rem}}h4,.h4{font-size:1.25rem}h5,.h5{font-size:1.1rem}h6,.h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title],abbr[data-bs-original-title]{text-decoration:underline dotted;-webkit-text-decoration:underline dotted;-moz-text-decoration:underline dotted;-ms-text-decoration:underline dotted;-o-text-decoration:underline dotted;cursor:help;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}ol,ul,dl{margin-top:0;margin-bottom:1rem}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem;padding:.625rem 1.25rem;border-left:.25rem solid #e9ecef}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}b,strong{font-weight:bolder}small,.small{font-size:0.875em}mark,.mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:0.75em;line-height:0;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}a{color:#2780e3;text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}a:hover{color:#1f66b6}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}pre,code,kbd,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr /* rtl:ignore */;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:0.875em;color:#000;background-color:#f7f7f7;padding:.5rem;border:1px solid #dee2e6}pre code{background-color:transparent;font-size:inherit;color:inherit;word-break:normal}code{font-size:0.875em;color:#9954bb;background-color:#f7f7f7;padding:.125rem .25rem;word-wrap:break-word}a>code{color:inherit}kbd{padding:.4rem .4rem;font-size:0.875em;color:#fff;background-color:#212529}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}thead,tbody,tfoot,tr,td,th{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}input,button,select,optgroup,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button:not(:disabled),[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + 0.3vw);line-height:inherit}@media(min-width: 1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-text,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none !important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:0.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:0.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:0.875em;color:#6c757d}.grid{display:grid;grid-template-rows:repeat(var(--bs-rows, 1), 1fr);grid-template-columns:repeat(var(--bs-columns, 12), 1fr);gap:var(--bs-gap, 1.5rem)}.grid .g-col-1{grid-column:auto/span 1}.grid .g-col-2{grid-column:auto/span 2}.grid .g-col-3{grid-column:auto/span 3}.grid .g-col-4{grid-column:auto/span 4}.grid .g-col-5{grid-column:auto/span 5}.grid .g-col-6{grid-column:auto/span 6}.grid .g-col-7{grid-column:auto/span 7}.grid .g-col-8{grid-column:auto/span 8}.grid .g-col-9{grid-column:auto/span 9}.grid .g-col-10{grid-column:auto/span 10}.grid .g-col-11{grid-column:auto/span 11}.grid .g-col-12{grid-column:auto/span 12}.grid .g-start-1{grid-column-start:1}.grid .g-start-2{grid-column-start:2}.grid .g-start-3{grid-column-start:3}.grid .g-start-4{grid-column-start:4}.grid .g-start-5{grid-column-start:5}.grid .g-start-6{grid-column-start:6}.grid .g-start-7{grid-column-start:7}.grid .g-start-8{grid-column-start:8}.grid .g-start-9{grid-column-start:9}.grid .g-start-10{grid-column-start:10}.grid .g-start-11{grid-column-start:11}@media(min-width: 576px){.grid .g-col-sm-1{grid-column:auto/span 1}.grid .g-col-sm-2{grid-column:auto/span 2}.grid .g-col-sm-3{grid-column:auto/span 3}.grid .g-col-sm-4{grid-column:auto/span 4}.grid .g-col-sm-5{grid-column:auto/span 5}.grid .g-col-sm-6{grid-column:auto/span 6}.grid .g-col-sm-7{grid-column:auto/span 7}.grid .g-col-sm-8{grid-column:auto/span 8}.grid .g-col-sm-9{grid-column:auto/span 9}.grid .g-col-sm-10{grid-column:auto/span 10}.grid .g-col-sm-11{grid-column:auto/span 11}.grid .g-col-sm-12{grid-column:auto/span 12}.grid .g-start-sm-1{grid-column-start:1}.grid .g-start-sm-2{grid-column-start:2}.grid .g-start-sm-3{grid-column-start:3}.grid .g-start-sm-4{grid-column-start:4}.grid .g-start-sm-5{grid-column-start:5}.grid .g-start-sm-6{grid-column-start:6}.grid .g-start-sm-7{grid-column-start:7}.grid .g-start-sm-8{grid-column-start:8}.grid .g-start-sm-9{grid-column-start:9}.grid .g-start-sm-10{grid-column-start:10}.grid .g-start-sm-11{grid-column-start:11}}@media(min-width: 768px){.grid .g-col-md-1{grid-column:auto/span 1}.grid .g-col-md-2{grid-column:auto/span 2}.grid .g-col-md-3{grid-column:auto/span 3}.grid .g-col-md-4{grid-column:auto/span 4}.grid .g-col-md-5{grid-column:auto/span 5}.grid .g-col-md-6{grid-column:auto/span 6}.grid .g-col-md-7{grid-column:auto/span 7}.grid .g-col-md-8{grid-column:auto/span 8}.grid .g-col-md-9{grid-column:auto/span 9}.grid .g-col-md-10{grid-column:auto/span 10}.grid .g-col-md-11{grid-column:auto/span 11}.grid .g-col-md-12{grid-column:auto/span 12}.grid .g-start-md-1{grid-column-start:1}.grid .g-start-md-2{grid-column-start:2}.grid .g-start-md-3{grid-column-start:3}.grid .g-start-md-4{grid-column-start:4}.grid .g-start-md-5{grid-column-start:5}.grid .g-start-md-6{grid-column-start:6}.grid .g-start-md-7{grid-column-start:7}.grid .g-start-md-8{grid-column-start:8}.grid .g-start-md-9{grid-column-start:9}.grid .g-start-md-10{grid-column-start:10}.grid .g-start-md-11{grid-column-start:11}}@media(min-width: 992px){.grid .g-col-lg-1{grid-column:auto/span 1}.grid .g-col-lg-2{grid-column:auto/span 2}.grid .g-col-lg-3{grid-column:auto/span 3}.grid .g-col-lg-4{grid-column:auto/span 4}.grid .g-col-lg-5{grid-column:auto/span 5}.grid .g-col-lg-6{grid-column:auto/span 6}.grid .g-col-lg-7{grid-column:auto/span 7}.grid .g-col-lg-8{grid-column:auto/span 8}.grid .g-col-lg-9{grid-column:auto/span 9}.grid .g-col-lg-10{grid-column:auto/span 10}.grid .g-col-lg-11{grid-column:auto/span 11}.grid .g-col-lg-12{grid-column:auto/span 12}.grid .g-start-lg-1{grid-column-start:1}.grid .g-start-lg-2{grid-column-start:2}.grid .g-start-lg-3{grid-column-start:3}.grid .g-start-lg-4{grid-column-start:4}.grid .g-start-lg-5{grid-column-start:5}.grid .g-start-lg-6{grid-column-start:6}.grid .g-start-lg-7{grid-column-start:7}.grid .g-start-lg-8{grid-column-start:8}.grid .g-start-lg-9{grid-column-start:9}.grid .g-start-lg-10{grid-column-start:10}.grid .g-start-lg-11{grid-column-start:11}}@media(min-width: 1200px){.grid .g-col-xl-1{grid-column:auto/span 1}.grid .g-col-xl-2{grid-column:auto/span 2}.grid .g-col-xl-3{grid-column:auto/span 3}.grid .g-col-xl-4{grid-column:auto/span 4}.grid .g-col-xl-5{grid-column:auto/span 5}.grid .g-col-xl-6{grid-column:auto/span 6}.grid .g-col-xl-7{grid-column:auto/span 7}.grid .g-col-xl-8{grid-column:auto/span 8}.grid .g-col-xl-9{grid-column:auto/span 9}.grid .g-col-xl-10{grid-column:auto/span 10}.grid .g-col-xl-11{grid-column:auto/span 11}.grid .g-col-xl-12{grid-column:auto/span 12}.grid .g-start-xl-1{grid-column-start:1}.grid .g-start-xl-2{grid-column-start:2}.grid .g-start-xl-3{grid-column-start:3}.grid .g-start-xl-4{grid-column-start:4}.grid .g-start-xl-5{grid-column-start:5}.grid .g-start-xl-6{grid-column-start:6}.grid .g-start-xl-7{grid-column-start:7}.grid .g-start-xl-8{grid-column-start:8}.grid .g-start-xl-9{grid-column-start:9}.grid .g-start-xl-10{grid-column-start:10}.grid .g-start-xl-11{grid-column-start:11}}@media(min-width: 1400px){.grid .g-col-xxl-1{grid-column:auto/span 1}.grid .g-col-xxl-2{grid-column:auto/span 2}.grid .g-col-xxl-3{grid-column:auto/span 3}.grid .g-col-xxl-4{grid-column:auto/span 4}.grid .g-col-xxl-5{grid-column:auto/span 5}.grid .g-col-xxl-6{grid-column:auto/span 6}.grid .g-col-xxl-7{grid-column:auto/span 7}.grid .g-col-xxl-8{grid-column:auto/span 8}.grid .g-col-xxl-9{grid-column:auto/span 9}.grid .g-col-xxl-10{grid-column:auto/span 10}.grid .g-col-xxl-11{grid-column:auto/span 11}.grid .g-col-xxl-12{grid-column:auto/span 12}.grid .g-start-xxl-1{grid-column-start:1}.grid .g-start-xxl-2{grid-column-start:2}.grid .g-start-xxl-3{grid-column-start:3}.grid .g-start-xxl-4{grid-column-start:4}.grid .g-start-xxl-5{grid-column-start:5}.grid .g-start-xxl-6{grid-column-start:6}.grid .g-start-xxl-7{grid-column-start:7}.grid .g-start-xxl-8{grid-column-start:8}.grid .g-start-xxl-9{grid-column-start:9}.grid .g-start-xxl-10{grid-column-start:10}.grid .g-start-xxl-11{grid-column-start:11}}.table{--bs-table-bg: transparent;--bs-table-accent-bg: transparent;--bs-table-striped-color: #373a3c;--bs-table-striped-bg: rgba(0, 0, 0, 0.05);--bs-table-active-color: #373a3c;--bs-table-active-bg: rgba(0, 0, 0, 0.1);--bs-table-hover-color: #373a3c;--bs-table-hover-bg: rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;color:#373a3c;vertical-align:top;border-color:#dee2e6}.table>:not(caption)>*>*{padding:.5rem .5rem;background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-accent-bg)}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table>:not(:first-child){border-top:2px solid currentColor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-accent-bg: var(--bs-table-striped-bg);color:var(--bs-table-striped-color)}.table-active{--bs-table-accent-bg: var(--bs-table-active-bg);color:var(--bs-table-active-color)}.table-hover>tbody>tr:hover>*{--bs-table-accent-bg: var(--bs-table-hover-bg);color:var(--bs-table-hover-color)}.table-primary{--bs-table-bg: #d4e6f9;--bs-table-striped-bg: #c9dbed;--bs-table-striped-color: #000;--bs-table-active-bg: #bfcfe0;--bs-table-active-color: #000;--bs-table-hover-bg: #c4d5e6;--bs-table-hover-color: #000;color:#000;border-color:#bfcfe0}.table-secondary{--bs-table-bg: #d7d8d8;--bs-table-striped-bg: #cccdcd;--bs-table-striped-color: #000;--bs-table-active-bg: #c2c2c2;--bs-table-active-color: #000;--bs-table-hover-bg: #c7c8c8;--bs-table-hover-color: #000;color:#000;border-color:#c2c2c2}.table-success{--bs-table-bg: #d9f0d1;--bs-table-striped-bg: #cee4c7;--bs-table-striped-color: #000;--bs-table-active-bg: #c3d8bc;--bs-table-active-color: #000;--bs-table-hover-bg: #c9dec1;--bs-table-hover-color: #000;color:#000;border-color:#c3d8bc}.table-info{--bs-table-bg: #ebddf1;--bs-table-striped-bg: #dfd2e5;--bs-table-striped-color: #000;--bs-table-active-bg: #d4c7d9;--bs-table-active-color: #000;--bs-table-hover-bg: #d9ccdf;--bs-table-hover-color: #000;color:#000;border-color:#d4c7d9}.table-warning{--bs-table-bg: #ffe3d1;--bs-table-striped-bg: #f2d8c7;--bs-table-striped-color: #000;--bs-table-active-bg: #e6ccbc;--bs-table-active-color: #000;--bs-table-hover-bg: #ecd2c1;--bs-table-hover-color: #000;color:#000;border-color:#e6ccbc}.table-danger{--bs-table-bg: #ffccd7;--bs-table-striped-bg: #f2c2cc;--bs-table-striped-color: #000;--bs-table-active-bg: #e6b8c2;--bs-table-active-color: #000;--bs-table-hover-bg: #ecbdc7;--bs-table-hover-color: #000;color:#000;border-color:#e6b8c2}.table-light{--bs-table-bg: #f8f9fa;--bs-table-striped-bg: #ecedee;--bs-table-striped-color: #000;--bs-table-active-bg: #dfe0e1;--bs-table-active-color: #000;--bs-table-hover-bg: #e5e6e7;--bs-table-hover-color: #000;color:#000;border-color:#dfe0e1}.table-dark{--bs-table-bg: #373a3c;--bs-table-striped-bg: #414446;--bs-table-striped-color: #fff;--bs-table-active-bg: #4b4e50;--bs-table-active-color: #fff;--bs-table-hover-bg: #46494b;--bs-table-hover-color: #fff;color:#fff;border-color:#4b4e50}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media(max-width: 575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label,.shiny-input-container .control-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(0.375rem + 1px);padding-bottom:calc(0.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(0.5rem + 1px);padding-bottom:calc(0.5rem + 1px);font-size:1.25rem}.col-form-label-sm{padding-top:calc(0.25rem + 1px);padding-bottom:calc(0.25rem + 1px);font-size:0.875rem}.form-text{margin-top:.25rem;font-size:0.875em;color:#6c757d}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#373a3c;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;border-radius:0;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:#373a3c;background-color:#fff;border-color:#93c0f1;outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.form-control::-webkit-date-and-time-value{height:1.5em}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-0.375rem -0.75rem;margin-inline-end:.75rem;color:#373a3c;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#dde0e3}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-0.375rem -0.75rem;margin-inline-end:.75rem;color:#373a3c;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control::-webkit-file-upload-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:#dde0e3}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#373a3c;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-sm,.form-control-plaintext.form-control-lg{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + 0.5rem + 2px);padding:.25rem .5rem;font-size:0.875rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.25rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-0.5rem -1rem;margin-inline-end:1rem}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-0.5rem -1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + 0.75rem + 2px)}textarea.form-control-sm{min-height:calc(1.5em + 0.5rem + 2px)}textarea.form-control-lg{min-height:calc(1.5em + 1rem + 2px)}.form-control-color{width:3rem;height:auto;padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{height:1.5em}.form-control-color::-webkit-color-swatch{height:1.5em}.form-select{display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;-moz-padding-start:calc(0.75rem - 3px);font-size:1rem;font-weight:400;line-height:1.5;color:#373a3c;background-color:#fff;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23373a3c' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #ced4da;border-radius:0;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}@media(prefers-reduced-motion: reduce){.form-select{transition:none}}.form-select:focus{border-color:#93c0f1;outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:#e9ecef}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #373a3c}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:0.875rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem}.form-check,.shiny-input-container .checkbox,.shiny-input-container .radio{display:block;min-height:1.5rem;padding-left:0;margin-bottom:.125rem}.form-check .form-check-input,.form-check .shiny-input-container .checkbox input,.form-check .shiny-input-container .radio input,.shiny-input-container .checkbox .form-check-input,.shiny-input-container .checkbox .shiny-input-container .checkbox input,.shiny-input-container .checkbox .shiny-input-container .radio input,.shiny-input-container .radio .form-check-input,.shiny-input-container .radio .shiny-input-container .checkbox input,.shiny-input-container .radio .shiny-input-container .radio input{float:left;margin-left:0}.form-check-input,.shiny-input-container .checkbox input,.shiny-input-container .checkbox-inline input,.shiny-input-container .radio input,.shiny-input-container .radio-inline input{width:1em;height:1em;margin-top:.25em;vertical-align:top;background-color:#fff;background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid rgba(0,0,0,.25);appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;color-adjust:exact;-webkit-print-color-adjust:exact}.form-check-input[type=radio],.shiny-input-container .checkbox input[type=radio],.shiny-input-container .checkbox-inline input[type=radio],.shiny-input-container .radio input[type=radio],.shiny-input-container .radio-inline input[type=radio]{border-radius:50%}.form-check-input:active,.shiny-input-container .checkbox input:active,.shiny-input-container .checkbox-inline input:active,.shiny-input-container .radio input:active,.shiny-input-container .radio-inline input:active{filter:brightness(90%)}.form-check-input:focus,.shiny-input-container .checkbox input:focus,.shiny-input-container .checkbox-inline input:focus,.shiny-input-container .radio input:focus,.shiny-input-container .radio-inline input:focus{border-color:#93c0f1;outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.form-check-input:checked,.shiny-input-container .checkbox input:checked,.shiny-input-container .checkbox-inline input:checked,.shiny-input-container .radio input:checked,.shiny-input-container .radio-inline input:checked{background-color:#2780e3;border-color:#2780e3}.form-check-input:checked[type=checkbox],.shiny-input-container .checkbox input:checked[type=checkbox],.shiny-input-container .checkbox-inline input:checked[type=checkbox],.shiny-input-container .radio input:checked[type=checkbox],.shiny-input-container .radio-inline input:checked[type=checkbox]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio],.shiny-input-container .checkbox input:checked[type=radio],.shiny-input-container .checkbox-inline input:checked[type=radio],.shiny-input-container .radio input:checked[type=radio],.shiny-input-container .radio-inline input:checked[type=radio]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate,.shiny-input-container .checkbox input[type=checkbox]:indeterminate,.shiny-input-container .checkbox-inline input[type=checkbox]:indeterminate,.shiny-input-container .radio input[type=checkbox]:indeterminate,.shiny-input-container .radio-inline input[type=checkbox]:indeterminate{background-color:#2780e3;border-color:#2780e3;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled,.shiny-input-container .checkbox input:disabled,.shiny-input-container .checkbox-inline input:disabled,.shiny-input-container .radio input:disabled,.shiny-input-container .radio-inline input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input[disabled]~.form-check-label,.form-check-input[disabled]~span,.form-check-input:disabled~.form-check-label,.form-check-input:disabled~span,.shiny-input-container .checkbox input[disabled]~.form-check-label,.shiny-input-container .checkbox input[disabled]~span,.shiny-input-container .checkbox input:disabled~.form-check-label,.shiny-input-container .checkbox input:disabled~span,.shiny-input-container .checkbox-inline input[disabled]~.form-check-label,.shiny-input-container .checkbox-inline input[disabled]~span,.shiny-input-container .checkbox-inline input:disabled~.form-check-label,.shiny-input-container .checkbox-inline input:disabled~span,.shiny-input-container .radio input[disabled]~.form-check-label,.shiny-input-container .radio input[disabled]~span,.shiny-input-container .radio input:disabled~.form-check-label,.shiny-input-container .radio input:disabled~span,.shiny-input-container .radio-inline input[disabled]~.form-check-label,.shiny-input-container .radio-inline input[disabled]~span,.shiny-input-container .radio-inline input:disabled~.form-check-label,.shiny-input-container .radio-inline input:disabled~span{opacity:.5}.form-check-label,.shiny-input-container .checkbox label,.shiny-input-container .checkbox-inline label,.shiny-input-container .radio label,.shiny-input-container .radio-inline label{cursor:pointer}.form-switch{padding-left:2.5em}.form-switch .form-check-input{width:2em;margin-left:-2.5em;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");background-position:left center;transition:background-position .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2393c0f1'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-check-inline,.shiny-input-container .checkbox-inline,.shiny-input-container .radio-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.btn-check[disabled]+.btn,.btn-check:disabled+.btn{pointer-events:none;filter:none;opacity:.65}.form-range{width:100%;height:1.5rem;padding:0;background-color:transparent;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(39,128,227,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(39,128,227,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-0.25rem;background-color:#2780e3;border:0;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}@media(prefers-reduced-motion: reduce){.form-range::-webkit-slider-thumb{transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#bed9f7}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent}.form-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#2780e3;border:0;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}@media(prefers-reduced-motion: reduce){.form-range::-moz-range-thumb{transition:none}}.form-range::-moz-range-thumb:active{background-color:#bed9f7}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.form-range:disabled::-moz-range-thumb{background-color:#adb5bd}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-select{height:calc(3.5rem + 2px);line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;height:100%;padding:1rem .75rem;pointer-events:none;border:1px solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media(prefers-reduced-motion: reduce){.form-floating>label{transition:none}}.form-floating>.form-control{padding:1rem .75rem}.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{opacity:.65;transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control:-webkit-autofill~label{opacity:.65;transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.input-group{position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:stretch;-webkit-align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus{z-index:3}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:3}.input-group-text{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#373a3c;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da}.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text,.input-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem}.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text,.input-group-sm>.btn{padding:.25rem .5rem;font-size:0.875rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:-1px}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#3fb618}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:rgba(63,182,24,.9)}.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip,.is-valid~.valid-feedback,.is-valid~.valid-tooltip{display:block}.was-validated .form-control:valid,.form-control.is-valid{border-color:#3fb618;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%233fb618' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:valid:focus,.form-control.is-valid:focus{border-color:#3fb618;box-shadow:0 0 0 .25rem rgba(63,182,24,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:valid,.form-select.is-valid{border-color:#3fb618}.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"],.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23373a3c' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%233fb618' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:valid:focus,.form-select.is-valid:focus{border-color:#3fb618;box-shadow:0 0 0 .25rem rgba(63,182,24,.25)}.was-validated .form-check-input:valid,.form-check-input.is-valid{border-color:#3fb618}.was-validated .form-check-input:valid:checked,.form-check-input.is-valid:checked{background-color:#3fb618}.was-validated .form-check-input:valid:focus,.form-check-input.is-valid:focus{box-shadow:0 0 0 .25rem rgba(63,182,24,.25)}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:#3fb618}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.was-validated .input-group .form-control:valid,.input-group .form-control.is-valid,.was-validated .input-group .form-select:valid,.input-group .form-select.is-valid{z-index:1}.was-validated .input-group .form-control:valid:focus,.input-group .form-control.is-valid:focus,.was-validated .input-group .form-select:valid:focus,.input-group .form-select.is-valid:focus{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#ff0039}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:rgba(255,0,57,.9)}.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip,.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip{display:block}.was-validated .form-control:invalid,.form-control.is-invalid{border-color:#ff0039;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23ff0039'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23ff0039' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus{border-color:#ff0039;box-shadow:0 0 0 .25rem rgba(255,0,57,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:invalid,.form-select.is-invalid{border-color:#ff0039}.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"],.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23373a3c' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23ff0039'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23ff0039' stroke='none'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:invalid:focus,.form-select.is-invalid:focus{border-color:#ff0039;box-shadow:0 0 0 .25rem rgba(255,0,57,.25)}.was-validated .form-check-input:invalid,.form-check-input.is-invalid{border-color:#ff0039}.was-validated .form-check-input:invalid:checked,.form-check-input.is-invalid:checked{background-color:#ff0039}.was-validated .form-check-input:invalid:focus,.form-check-input.is-invalid:focus{box-shadow:0 0 0 .25rem rgba(255,0,57,.25)}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:#ff0039}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.was-validated .input-group .form-control:invalid,.input-group .form-control.is-invalid,.was-validated .input-group .form-select:invalid,.input-group .form-select.is-invalid{z-index:2}.was-validated .input-group .form-control:invalid:focus,.input-group .form-control.is-invalid:focus,.was-validated .input-group .form-select:invalid:focus,.input-group .form-select.is-invalid:focus{z-index:3}.btn{display:inline-block;font-weight:400;line-height:1.5;color:#373a3c;text-align:center;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;vertical-align:middle;cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.btn{transition:none}}.btn:hover{color:#373a3c}.btn-check:focus+.btn,.btn:focus{outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.btn:disabled,.btn.disabled,fieldset:disabled .btn{pointer-events:none;opacity:.65}.btn-default{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-default:hover{color:#fff;background-color:#2f3133;border-color:#2c2e30}.btn-check:focus+.btn-default,.btn-default:focus{color:#fff;background-color:#2f3133;border-color:#2c2e30;box-shadow:0 0 0 .25rem rgba(85,88,89,.5)}.btn-check:checked+.btn-default,.btn-check:active+.btn-default,.btn-default:active,.btn-default.active,.show>.btn-default.dropdown-toggle{color:#fff;background-color:#2c2e30;border-color:#292c2d}.btn-check:checked+.btn-default:focus,.btn-check:active+.btn-default:focus,.btn-default:active:focus,.btn-default.active:focus,.show>.btn-default.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(85,88,89,.5)}.btn-default:disabled,.btn-default.disabled{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-primary{color:#fff;background-color:#2780e3;border-color:#2780e3}.btn-primary:hover{color:#fff;background-color:#216dc1;border-color:#1f66b6}.btn-check:focus+.btn-primary,.btn-primary:focus{color:#fff;background-color:#216dc1;border-color:#1f66b6;box-shadow:0 0 0 .25rem rgba(71,147,231,.5)}.btn-check:checked+.btn-primary,.btn-check:active+.btn-primary,.btn-primary:active,.btn-primary.active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#1f66b6;border-color:#1d60aa}.btn-check:checked+.btn-primary:focus,.btn-check:active+.btn-primary:focus,.btn-primary:active:focus,.btn-primary.active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(71,147,231,.5)}.btn-primary:disabled,.btn-primary.disabled{color:#fff;background-color:#2780e3;border-color:#2780e3}.btn-secondary{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-secondary:hover{color:#fff;background-color:#2f3133;border-color:#2c2e30}.btn-check:focus+.btn-secondary,.btn-secondary:focus{color:#fff;background-color:#2f3133;border-color:#2c2e30;box-shadow:0 0 0 .25rem rgba(85,88,89,.5)}.btn-check:checked+.btn-secondary,.btn-check:active+.btn-secondary,.btn-secondary:active,.btn-secondary.active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#2c2e30;border-color:#292c2d}.btn-check:checked+.btn-secondary:focus,.btn-check:active+.btn-secondary:focus,.btn-secondary:active:focus,.btn-secondary.active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(85,88,89,.5)}.btn-secondary:disabled,.btn-secondary.disabled{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-success{color:#fff;background-color:#3fb618;border-color:#3fb618}.btn-success:hover{color:#fff;background-color:#369b14;border-color:#329213}.btn-check:focus+.btn-success,.btn-success:focus{color:#fff;background-color:#369b14;border-color:#329213;box-shadow:0 0 0 .25rem rgba(92,193,59,.5)}.btn-check:checked+.btn-success,.btn-check:active+.btn-success,.btn-success:active,.btn-success.active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#329213;border-color:#2f8912}.btn-check:checked+.btn-success:focus,.btn-check:active+.btn-success:focus,.btn-success:active:focus,.btn-success.active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(92,193,59,.5)}.btn-success:disabled,.btn-success.disabled{color:#fff;background-color:#3fb618;border-color:#3fb618}.btn-info{color:#fff;background-color:#9954bb;border-color:#9954bb}.btn-info:hover{color:#fff;background-color:#82479f;border-color:#7a4396}.btn-check:focus+.btn-info,.btn-info:focus{color:#fff;background-color:#82479f;border-color:#7a4396;box-shadow:0 0 0 .25rem rgba(168,110,197,.5)}.btn-check:checked+.btn-info,.btn-check:active+.btn-info,.btn-info:active,.btn-info.active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#7a4396;border-color:#733f8c}.btn-check:checked+.btn-info:focus,.btn-check:active+.btn-info:focus,.btn-info:active:focus,.btn-info.active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(168,110,197,.5)}.btn-info:disabled,.btn-info.disabled{color:#fff;background-color:#9954bb;border-color:#9954bb}.btn-warning{color:#fff;background-color:#ff7518;border-color:#ff7518}.btn-warning:hover{color:#fff;background-color:#d96314;border-color:#cc5e13}.btn-check:focus+.btn-warning,.btn-warning:focus{color:#fff;background-color:#d96314;border-color:#cc5e13;box-shadow:0 0 0 .25rem rgba(255,138,59,.5)}.btn-check:checked+.btn-warning,.btn-check:active+.btn-warning,.btn-warning:active,.btn-warning.active,.show>.btn-warning.dropdown-toggle{color:#fff;background-color:#cc5e13;border-color:#bf5812}.btn-check:checked+.btn-warning:focus,.btn-check:active+.btn-warning:focus,.btn-warning:active:focus,.btn-warning.active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(255,138,59,.5)}.btn-warning:disabled,.btn-warning.disabled{color:#fff;background-color:#ff7518;border-color:#ff7518}.btn-danger{color:#fff;background-color:#ff0039;border-color:#ff0039}.btn-danger:hover{color:#fff;background-color:#d90030;border-color:#cc002e}.btn-check:focus+.btn-danger,.btn-danger:focus{color:#fff;background-color:#d90030;border-color:#cc002e;box-shadow:0 0 0 .25rem rgba(255,38,87,.5)}.btn-check:checked+.btn-danger,.btn-check:active+.btn-danger,.btn-danger:active,.btn-danger.active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#cc002e;border-color:#bf002b}.btn-check:checked+.btn-danger:focus,.btn-check:active+.btn-danger:focus,.btn-danger:active:focus,.btn-danger.active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(255,38,87,.5)}.btn-danger:disabled,.btn-danger.disabled{color:#fff;background-color:#ff0039;border-color:#ff0039}.btn-light{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:focus+.btn-light,.btn-light:focus{color:#000;background-color:#f9fafb;border-color:#f9fafb;box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-check:checked+.btn-light,.btn-check:active+.btn-light,.btn-light:active,.btn-light.active,.show>.btn-light.dropdown-toggle{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:checked+.btn-light:focus,.btn-check:active+.btn-light:focus,.btn-light:active:focus,.btn-light.active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-light:disabled,.btn-light.disabled{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-dark{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-dark:hover{color:#fff;background-color:#2f3133;border-color:#2c2e30}.btn-check:focus+.btn-dark,.btn-dark:focus{color:#fff;background-color:#2f3133;border-color:#2c2e30;box-shadow:0 0 0 .25rem rgba(85,88,89,.5)}.btn-check:checked+.btn-dark,.btn-check:active+.btn-dark,.btn-dark:active,.btn-dark.active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#2c2e30;border-color:#292c2d}.btn-check:checked+.btn-dark:focus,.btn-check:active+.btn-dark:focus,.btn-dark:active:focus,.btn-dark.active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(85,88,89,.5)}.btn-dark:disabled,.btn-dark.disabled{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-outline-default{color:#373a3c;border-color:#373a3c;background-color:transparent}.btn-outline-default:hover{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-check:focus+.btn-outline-default,.btn-outline-default:focus{box-shadow:0 0 0 .25rem rgba(55,58,60,.5)}.btn-check:checked+.btn-outline-default,.btn-check:active+.btn-outline-default,.btn-outline-default:active,.btn-outline-default.active,.btn-outline-default.dropdown-toggle.show{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-check:checked+.btn-outline-default:focus,.btn-check:active+.btn-outline-default:focus,.btn-outline-default:active:focus,.btn-outline-default.active:focus,.btn-outline-default.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(55,58,60,.5)}.btn-outline-default:disabled,.btn-outline-default.disabled{color:#373a3c;background-color:transparent}.btn-outline-primary{color:#2780e3;border-color:#2780e3;background-color:transparent}.btn-outline-primary:hover{color:#fff;background-color:#2780e3;border-color:#2780e3}.btn-check:focus+.btn-outline-primary,.btn-outline-primary:focus{box-shadow:0 0 0 .25rem rgba(39,128,227,.5)}.btn-check:checked+.btn-outline-primary,.btn-check:active+.btn-outline-primary,.btn-outline-primary:active,.btn-outline-primary.active,.btn-outline-primary.dropdown-toggle.show{color:#fff;background-color:#2780e3;border-color:#2780e3}.btn-check:checked+.btn-outline-primary:focus,.btn-check:active+.btn-outline-primary:focus,.btn-outline-primary:active:focus,.btn-outline-primary.active:focus,.btn-outline-primary.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(39,128,227,.5)}.btn-outline-primary:disabled,.btn-outline-primary.disabled{color:#2780e3;background-color:transparent}.btn-outline-secondary{color:#373a3c;border-color:#373a3c;background-color:transparent}.btn-outline-secondary:hover{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-check:focus+.btn-outline-secondary,.btn-outline-secondary:focus{box-shadow:0 0 0 .25rem rgba(55,58,60,.5)}.btn-check:checked+.btn-outline-secondary,.btn-check:active+.btn-outline-secondary,.btn-outline-secondary:active,.btn-outline-secondary.active,.btn-outline-secondary.dropdown-toggle.show{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-check:checked+.btn-outline-secondary:focus,.btn-check:active+.btn-outline-secondary:focus,.btn-outline-secondary:active:focus,.btn-outline-secondary.active:focus,.btn-outline-secondary.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(55,58,60,.5)}.btn-outline-secondary:disabled,.btn-outline-secondary.disabled{color:#373a3c;background-color:transparent}.btn-outline-success{color:#3fb618;border-color:#3fb618;background-color:transparent}.btn-outline-success:hover{color:#fff;background-color:#3fb618;border-color:#3fb618}.btn-check:focus+.btn-outline-success,.btn-outline-success:focus{box-shadow:0 0 0 .25rem rgba(63,182,24,.5)}.btn-check:checked+.btn-outline-success,.btn-check:active+.btn-outline-success,.btn-outline-success:active,.btn-outline-success.active,.btn-outline-success.dropdown-toggle.show{color:#fff;background-color:#3fb618;border-color:#3fb618}.btn-check:checked+.btn-outline-success:focus,.btn-check:active+.btn-outline-success:focus,.btn-outline-success:active:focus,.btn-outline-success.active:focus,.btn-outline-success.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(63,182,24,.5)}.btn-outline-success:disabled,.btn-outline-success.disabled{color:#3fb618;background-color:transparent}.btn-outline-info{color:#9954bb;border-color:#9954bb;background-color:transparent}.btn-outline-info:hover{color:#fff;background-color:#9954bb;border-color:#9954bb}.btn-check:focus+.btn-outline-info,.btn-outline-info:focus{box-shadow:0 0 0 .25rem rgba(153,84,187,.5)}.btn-check:checked+.btn-outline-info,.btn-check:active+.btn-outline-info,.btn-outline-info:active,.btn-outline-info.active,.btn-outline-info.dropdown-toggle.show{color:#fff;background-color:#9954bb;border-color:#9954bb}.btn-check:checked+.btn-outline-info:focus,.btn-check:active+.btn-outline-info:focus,.btn-outline-info:active:focus,.btn-outline-info.active:focus,.btn-outline-info.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(153,84,187,.5)}.btn-outline-info:disabled,.btn-outline-info.disabled{color:#9954bb;background-color:transparent}.btn-outline-warning{color:#ff7518;border-color:#ff7518;background-color:transparent}.btn-outline-warning:hover{color:#fff;background-color:#ff7518;border-color:#ff7518}.btn-check:focus+.btn-outline-warning,.btn-outline-warning:focus{box-shadow:0 0 0 .25rem rgba(255,117,24,.5)}.btn-check:checked+.btn-outline-warning,.btn-check:active+.btn-outline-warning,.btn-outline-warning:active,.btn-outline-warning.active,.btn-outline-warning.dropdown-toggle.show{color:#fff;background-color:#ff7518;border-color:#ff7518}.btn-check:checked+.btn-outline-warning:focus,.btn-check:active+.btn-outline-warning:focus,.btn-outline-warning:active:focus,.btn-outline-warning.active:focus,.btn-outline-warning.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(255,117,24,.5)}.btn-outline-warning:disabled,.btn-outline-warning.disabled{color:#ff7518;background-color:transparent}.btn-outline-danger{color:#ff0039;border-color:#ff0039;background-color:transparent}.btn-outline-danger:hover{color:#fff;background-color:#ff0039;border-color:#ff0039}.btn-check:focus+.btn-outline-danger,.btn-outline-danger:focus{box-shadow:0 0 0 .25rem rgba(255,0,57,.5)}.btn-check:checked+.btn-outline-danger,.btn-check:active+.btn-outline-danger,.btn-outline-danger:active,.btn-outline-danger.active,.btn-outline-danger.dropdown-toggle.show{color:#fff;background-color:#ff0039;border-color:#ff0039}.btn-check:checked+.btn-outline-danger:focus,.btn-check:active+.btn-outline-danger:focus,.btn-outline-danger:active:focus,.btn-outline-danger.active:focus,.btn-outline-danger.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(255,0,57,.5)}.btn-outline-danger:disabled,.btn-outline-danger.disabled{color:#ff0039;background-color:transparent}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa;background-color:transparent}.btn-outline-light:hover{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:focus+.btn-outline-light,.btn-outline-light:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-check:checked+.btn-outline-light,.btn-check:active+.btn-outline-light,.btn-outline-light:active,.btn-outline-light.active,.btn-outline-light.dropdown-toggle.show{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:checked+.btn-outline-light:focus,.btn-check:active+.btn-outline-light:focus,.btn-outline-light:active:focus,.btn-outline-light.active:focus,.btn-outline-light.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-outline-light:disabled,.btn-outline-light.disabled{color:#f8f9fa;background-color:transparent}.btn-outline-dark{color:#373a3c;border-color:#373a3c;background-color:transparent}.btn-outline-dark:hover{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-check:focus+.btn-outline-dark,.btn-outline-dark:focus{box-shadow:0 0 0 .25rem rgba(55,58,60,.5)}.btn-check:checked+.btn-outline-dark,.btn-check:active+.btn-outline-dark,.btn-outline-dark:active,.btn-outline-dark.active,.btn-outline-dark.dropdown-toggle.show{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-check:checked+.btn-outline-dark:focus,.btn-check:active+.btn-outline-dark:focus,.btn-outline-dark:active:focus,.btn-outline-dark.active:focus,.btn-outline-dark.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(55,58,60,.5)}.btn-outline-dark:disabled,.btn-outline-dark.disabled{color:#373a3c;background-color:transparent}.btn-link{font-weight:400;color:#2780e3;text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}.btn-link:hover{color:#1f66b6}.btn-link:disabled,.btn-link.disabled{color:#6c757d}.btn-lg,.btn-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem;border-radius:0}.btn-sm,.btn-group-sm>.btn{padding:.25rem .5rem;font-size:0.875rem;border-radius:0}.fade{transition:opacity .15s linear}@media(prefers-reduced-motion: reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .2s ease}@media(prefers-reduced-motion: reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media(prefers-reduced-motion: reduce){.collapsing.collapse-horizontal{transition:none}}.dropup,.dropend,.dropdown,.dropstart{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;z-index:1000;display:none;min-width:10rem;padding:.5rem 0;margin:0;font-size:1rem;color:#373a3c;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:.125rem}.dropdown-menu-start{--bs-position: start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position: end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media(min-width: 576px){.dropdown-menu-sm-start{--bs-position: start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position: end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 768px){.dropdown-menu-md-start{--bs-position: start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position: end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 992px){.dropdown-menu-lg-start{--bs-position: start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position: end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1200px){.dropdown-menu-xl-start{--bs-position: start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position: end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1400px){.dropdown-menu-xxl-start{--bs-position: start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position: end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid rgba(0,0,0,.15)}.dropdown-item{display:block;width:100%;padding:.25rem 1rem;clear:both;font-weight:400;color:#212529;text-align:inherit;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:hover,.dropdown-item:focus{color:#1e2125;background-color:#e9ecef}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#2780e3}.dropdown-item.disabled,.dropdown-item:disabled{color:#adb5bd;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1rem;margin-bottom:0;font-size:0.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1rem;color:#212529}.dropdown-menu-dark{color:#dee2e6;background-color:#373a3c;border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item{color:#dee2e6}.dropdown-menu-dark .dropdown-item:hover,.dropdown-menu-dark .dropdown-item:focus{color:#fff;background-color:rgba(255,255,255,.15)}.dropdown-menu-dark .dropdown-item.active,.dropdown-menu-dark .dropdown-item:active{color:#fff;background-color:#2780e3}.dropdown-menu-dark .dropdown-item.disabled,.dropdown-menu-dark .dropdown-item:disabled{color:#adb5bd}.dropdown-menu-dark .dropdown-divider{border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item-text{color:#dee2e6}.dropdown-menu-dark .dropdown-header{color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto}.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn:hover,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-toolbar{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;justify-content:flex-start;-webkit-justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:not(:first-child),.btn-group>.btn-group:not(:first-child){margin-left:-1px}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-sm+.dropdown-toggle-split,.btn-group-sm>.btn+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;-webkit-flex-direction:column;align-items:flex-start;-webkit-align-items:flex-start;justify-content:center;-webkit-justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child){margin-top:-1px}.nav{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem;color:#2780e3;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media(prefers-reduced-motion: reduce){.nav-link{transition:none}}.nav-link:hover,.nav-link:focus{color:#1f66b6}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-link{margin-bottom:-1px;background:none;border:1px solid transparent}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{border-color:#e9ecef #e9ecef #dee2e6;isolation:isolate}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px}.nav-pills .nav-link{background:none;border:0}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#2780e3}.nav-fill>.nav-link,.nav-fill .nav-item{flex:1 1 auto;-webkit-flex:1 1 auto;text-align:center}.nav-justified>.nav-link,.nav-justified .nav-item{flex-basis:0;-webkit-flex-basis:0;flex-grow:1;-webkit-flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding-top:.5rem;padding-bottom:.5rem}.navbar>.container-xxl,.navbar>.container-xl,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container,.navbar>.container-fluid{display:flex;display:-webkit-flex;flex-wrap:inherit;-webkit-flex-wrap:inherit;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between}.navbar-brand{padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap}.navbar-nav{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;-webkit-flex-basis:100%;flex-grow:1;-webkit-flex-grow:1;align-items:center;-webkit-align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;transition:box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 .25rem}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height, 75vh);overflow-y:auto}@media(min-width: 576px){.navbar-expand-sm{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas-header{display:none}.navbar-expand-sm .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-sm .offcanvas-top,.navbar-expand-sm .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-sm .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 768px){.navbar-expand-md{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas-header{display:none}.navbar-expand-md .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-md .offcanvas-top,.navbar-expand-md .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-md .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 992px){.navbar-expand-lg{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas-header{display:none}.navbar-expand-lg .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-lg .offcanvas-top,.navbar-expand-lg .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-lg .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1200px){.navbar-expand-xl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas-header{display:none}.navbar-expand-xl .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-xl .offcanvas-top,.navbar-expand-xl .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-xl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1400px){.navbar-expand-xxl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-xxl .offcanvas-top,.navbar-expand-xxl .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-xxl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas-header{display:none}.navbar-expand .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand .offcanvas-top,.navbar-expand .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}.navbar-light{background-color:#2780e3}.navbar-light .navbar-brand{color:#fdfeff}.navbar-light .navbar-brand:hover,.navbar-light .navbar-brand:focus{color:#fdfeff}.navbar-light .navbar-nav .nav-link{color:#fdfeff}.navbar-light .navbar-nav .nav-link:hover,.navbar-light .navbar-nav .nav-link:focus{color:rgba(253,254,255,.8)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(253,254,255,.75)}.navbar-light .navbar-nav .show>.nav-link,.navbar-light .navbar-nav .nav-link.active{color:#fdfeff}.navbar-light .navbar-toggler{color:#fdfeff;border-color:rgba(253,254,255,.4)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfeff' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:#fdfeff}.navbar-light .navbar-text a,.navbar-light .navbar-text a:hover,.navbar-light .navbar-text a:focus{color:#fdfeff}.navbar-dark{background-color:#2780e3}.navbar-dark .navbar-brand{color:#fdfeff}.navbar-dark .navbar-brand:hover,.navbar-dark .navbar-brand:focus{color:#fdfeff}.navbar-dark .navbar-nav .nav-link{color:#fdfeff}.navbar-dark .navbar-nav .nav-link:hover,.navbar-dark .navbar-nav .nav-link:focus{color:rgba(253,254,255,.8)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(253,254,255,.75)}.navbar-dark .navbar-nav .show>.nav-link,.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active{color:#fdfeff}.navbar-dark .navbar-toggler{color:#fdfeff;border-color:rgba(253,254,255,.4)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfeff' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:#fdfeff}.navbar-dark .navbar-text a,.navbar-dark .navbar-text a:hover,.navbar-dark .navbar-text a:focus{color:#fdfeff}.card{position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0}.card>.list-group:last-child{border-bottom-width:0}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;-webkit-flex:1 1 auto;padding:1rem 1rem}.card-title{margin-bottom:.5rem}.card-subtitle{margin-top:-0.25rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:1rem}.card-header{padding:.5rem 1rem;margin-bottom:0;background-color:#adb5bd;border-bottom:1px solid rgba(0,0,0,.125)}.card-footer{padding:.5rem 1rem;background-color:#adb5bd;border-top:1px solid rgba(0,0,0,.125)}.card-header-tabs{margin-right:-0.5rem;margin-bottom:-0.5rem;margin-left:-0.5rem;border-bottom:0}.card-header-pills{margin-right:-0.5rem;margin-left:-0.5rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem}.card-img,.card-img-top,.card-img-bottom{width:100%}.card-group>.card{margin-bottom:.75rem}@media(min-width: 576px){.card-group{display:flex;display:-webkit-flex;flex-flow:row wrap;-webkit-flex-flow:row wrap}.card-group>.card{flex:1 0 0%;-webkit-flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}}.accordion-button{position:relative;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;width:100%;padding:1rem 1.25rem;font-size:1rem;color:#373a3c;text-align:left;background-color:#fff;border:0;overflow-anchor:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,border-radius .15s ease}@media(prefers-reduced-motion: reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:#2373cc;background-color:#e9f2fc;box-shadow:inset 0 -1px 0 rgba(0,0,0,.125)}.accordion-button:not(.collapsed)::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%232373cc'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");transform:rotate(-180deg)}.accordion-button::after{flex-shrink:0;-webkit-flex-shrink:0;width:1.25rem;height:1.25rem;margin-left:auto;content:"";background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23373a3c'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-size:1.25rem;transition:transform .2s ease-in-out}@media(prefers-reduced-motion: reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:#93c0f1;outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.accordion-header{margin-bottom:0}.accordion-item{background-color:#fff;border:1px solid rgba(0,0,0,.125)}.accordion-item:not(:first-of-type){border-top:0}.accordion-body{padding:1rem 1.25rem}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.breadcrumb{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding:0 0;margin-bottom:1rem;list-style:none}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:.5rem;color:#6c757d;content:var(--bs-breadcrumb-divider, "/") /* rtl: var(--bs-breadcrumb-divider, "/") */}.breadcrumb-item.active{color:#6c757d}.pagination{display:flex;display:-webkit-flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;color:#2780e3;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:#fff;border:1px solid #dee2e6;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:#1f66b6;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:3;color:#1f66b6;background-color:#e9ecef;outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.page-item:not(:first-child) .page-link{margin-left:-1px}.page-item.active .page-link{z-index:3;color:#fff;background-color:#2780e3;border-color:#2780e3}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;background-color:#fff;border-color:#dee2e6}.page-link{padding:.375rem .75rem}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:0.875rem}.badge{display:inline-block;padding:.35em .65em;font-size:0.75em;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{position:relative;padding:1rem 1rem;margin-bottom:1rem;border:0 solid transparent}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-default{color:#212324;background-color:#d7d8d8;border-color:#c3c4c5}.alert-default .alert-link{color:#1a1c1d}.alert-primary{color:#174d88;background-color:#d4e6f9;border-color:#bed9f7}.alert-primary .alert-link{color:#123e6d}.alert-secondary{color:#212324;background-color:#d7d8d8;border-color:#c3c4c5}.alert-secondary .alert-link{color:#1a1c1d}.alert-success{color:#266d0e;background-color:#d9f0d1;border-color:#c5e9ba}.alert-success .alert-link{color:#1e570b}.alert-info{color:#5c3270;background-color:#ebddf1;border-color:#e0cceb}.alert-info .alert-link{color:#4a285a}.alert-warning{color:#99460e;background-color:#ffe3d1;border-color:#ffd6ba}.alert-warning .alert-link{color:#7a380b}.alert-danger{color:#902;background-color:#ffccd7;border-color:#ffb3c4}.alert-danger .alert-link{color:#7a001b}.alert-light{color:#959596;background-color:#fefefe;border-color:#fdfdfe}.alert-light .alert-link{color:#777778}.alert-dark{color:#212324;background-color:#d7d8d8;border-color:#c3c4c5}.alert-dark .alert-link{color:#1a1c1d}@keyframes progress-bar-stripes{0%{background-position-x:.5rem}}.progress{display:flex;display:-webkit-flex;height:.5rem;overflow:hidden;font-size:0.75rem;background-color:#e9ecef}.progress-bar{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;justify-content:center;-webkit-justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#2780e3;transition:width .6s ease}@media(prefers-reduced-motion: reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-size:.5rem .5rem}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media(prefers-reduced-motion: reduce){.progress-bar-animated{animation:none}}.list-group{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>li::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#373a3c;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.5rem 1rem;color:#212529;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#2780e3;border-color:#2780e3}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media(min-width: 576px){.list-group-horizontal-sm{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 768px){.list-group-horizontal-md{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 992px){.list-group-horizontal-lg{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 1200px){.list-group-horizontal-xl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 1400px){.list-group-horizontal-xxl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-default{color:#212324;background-color:#d7d8d8}.list-group-item-default.list-group-item-action:hover,.list-group-item-default.list-group-item-action:focus{color:#212324;background-color:#c2c2c2}.list-group-item-default.list-group-item-action.active{color:#fff;background-color:#212324;border-color:#212324}.list-group-item-primary{color:#174d88;background-color:#d4e6f9}.list-group-item-primary.list-group-item-action:hover,.list-group-item-primary.list-group-item-action:focus{color:#174d88;background-color:#bfcfe0}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#174d88;border-color:#174d88}.list-group-item-secondary{color:#212324;background-color:#d7d8d8}.list-group-item-secondary.list-group-item-action:hover,.list-group-item-secondary.list-group-item-action:focus{color:#212324;background-color:#c2c2c2}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#212324;border-color:#212324}.list-group-item-success{color:#266d0e;background-color:#d9f0d1}.list-group-item-success.list-group-item-action:hover,.list-group-item-success.list-group-item-action:focus{color:#266d0e;background-color:#c3d8bc}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#266d0e;border-color:#266d0e}.list-group-item-info{color:#5c3270;background-color:#ebddf1}.list-group-item-info.list-group-item-action:hover,.list-group-item-info.list-group-item-action:focus{color:#5c3270;background-color:#d4c7d9}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#5c3270;border-color:#5c3270}.list-group-item-warning{color:#99460e;background-color:#ffe3d1}.list-group-item-warning.list-group-item-action:hover,.list-group-item-warning.list-group-item-action:focus{color:#99460e;background-color:#e6ccbc}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#99460e;border-color:#99460e}.list-group-item-danger{color:#902;background-color:#ffccd7}.list-group-item-danger.list-group-item-action:hover,.list-group-item-danger.list-group-item-action:focus{color:#902;background-color:#e6b8c2}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#902;border-color:#902}.list-group-item-light{color:#959596;background-color:#fefefe}.list-group-item-light.list-group-item-action:hover,.list-group-item-light.list-group-item-action:focus{color:#959596;background-color:#e5e5e5}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#959596;border-color:#959596}.list-group-item-dark{color:#212324;background-color:#d7d8d8}.list-group-item-dark.list-group-item-action:hover,.list-group-item-dark.list-group-item-action:focus{color:#212324;background-color:#c2c2c2}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#212324;border-color:#212324}.btn-close{box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:#000;background:transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;border:0;opacity:.5}.btn-close:hover{color:#000;text-decoration:none;opacity:.75}.btn-close:focus{outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25);opacity:1}.btn-close:disabled,.btn-close.disabled{pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;opacity:.25}.btn-close-white{filter:invert(1) grayscale(100%) brightness(200%)}.toast{width:350px;max-width:100%;font-size:0.875rem;pointer-events:auto;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .5rem 1rem rgba(0,0,0,.15)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{width:max-content;width:-webkit-max-content;width:-moz-max-content;width:-ms-max-content;width:-o-max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:.75rem}.toast-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:.5rem .75rem;color:#6c757d;background-color:rgba(255,255,255,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05)}.toast-header .btn-close{margin-right:-0.375rem;margin-left:.75rem}.toast-body{padding:.75rem;word-wrap:break-word}.modal{position:fixed;top:0;left:0;z-index:1055;display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0, -50px)}@media(prefers-reduced-motion: reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;min-height:calc(100% - 1rem)}.modal-content{position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1050;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;display:-webkit-flex;flex-shrink:0;-webkit-flex-shrink:0;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #dee2e6}.modal-header .btn-close{padding:.5rem .5rem;margin:-0.5rem -0.5rem -0.5rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;padding:1rem}.modal-footer{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;flex-shrink:0;-webkit-flex-shrink:0;align-items:center;-webkit-align-items:center;justify-content:flex-end;-webkit-justify-content:flex-end;padding:.75rem;border-top:1px solid #dee2e6}.modal-footer>*{margin:.25rem}@media(min-width: 576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{height:calc(100% - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-sm{max-width:300px}}@media(min-width: 992px){.modal-lg,.modal-xl{max-width:800px}}@media(min-width: 1200px){.modal-xl{max-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0}.modal-fullscreen .modal-body{overflow-y:auto}@media(max-width: 575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media(max-width: 767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media(max-width: 991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media(max-width: 1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media(max-width: 1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{position:absolute;z-index:1080;display:block;margin:0;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:0.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .tooltip-arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-top,.bs-tooltip-auto[data-popper-placement^=top]{padding:.4rem 0}.bs-tooltip-top .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow{bottom:0}.bs-tooltip-top .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before{top:-1px;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-end,.bs-tooltip-auto[data-popper-placement^=right]{padding:0 .4rem}.bs-tooltip-end .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-end .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before{right:-1px;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-bottom,.bs-tooltip-auto[data-popper-placement^=bottom]{padding:.4rem 0}.bs-tooltip-bottom .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow{top:0}.bs-tooltip-bottom .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before{bottom:-1px;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-start,.bs-tooltip-auto[data-popper-placement^=left]{padding:0 .4rem}.bs-tooltip-start .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-start .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before{left:-1px;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000}.popover{position:absolute;top:0;left:0 /* rtl:ignore */;z-index:1070;display:block;max-width:276px;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:0.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2)}.popover .popover-arrow{position:absolute;display:block;width:1rem;height:.5rem}.popover .popover-arrow::before,.popover .popover-arrow::after{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-top>.popover-arrow,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow{bottom:calc(-0.5rem - 1px)}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-end>.popover-arrow,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow{left:calc(-0.5rem - 1px);width:.5rem;height:1rem}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-bottom>.popover-arrow,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow{top:calc(-0.5rem - 1px)}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#fff}.bs-popover-bottom .popover-header::before,.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-0.5rem;content:"";border-bottom:1px solid #f0f0f0}.bs-popover-start>.popover-arrow,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow{right:calc(-0.5rem - 1px);width:.5rem;height:1rem}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem 1rem;margin-bottom:0;font-size:1rem;background-color:#f0f0f0;border-bottom:1px solid rgba(0,0,0,.2)}.popover-header:empty{display:none}.popover-body{padding:1rem 1rem;color:#373a3c}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y;-webkit-touch-action:pan-y;-moz-touch-action:pan-y;-ms-touch-action:pan-y;-o-touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;backface-visibility:hidden;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-o-backface-visibility:hidden;transition:transform .6s ease-in-out}@media(prefers-reduced-motion: reduce){.carousel-item{transition:none}}.carousel-item.active,.carousel-item-next,.carousel-item-prev{display:block}.carousel-item-next:not(.carousel-item-start),.active.carousel-item-end{transform:translateX(100%)}.carousel-item-prev:not(.carousel-item-end),.active.carousel-item-start{transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item.active,.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end{z-index:1;opacity:1}.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{z-index:0;opacity:0;transition:opacity 0s .6s}@media(prefers-reduced-motion: reduce){.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{transition:none}}.carousel-control-prev,.carousel-control-next{position:absolute;top:0;bottom:0;z-index:1;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:center;-webkit-justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:none;border:0;opacity:.5;transition:opacity .15s ease}@media(prefers-reduced-motion: reduce){.carousel-control-prev,.carousel-control-next{transition:none}}.carousel-control-prev:hover,.carousel-control-prev:focus,.carousel-control-next:hover,.carousel-control-next:focus{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-prev-icon,.carousel-control-next-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;display:-webkit-flex;justify-content:center;-webkit-justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%;list-style:none}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;-webkit-flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media(prefers-reduced-motion: reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-prev-icon,.carousel-dark .carousel-control-next-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}@keyframes spinner-border{to{transform:rotate(360deg) /* rtl:ignore */}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:-0.125em;border:.25em solid currentColor;border-right-color:transparent;border-radius:50%;animation:.75s linear infinite spinner-border}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:-0.125em;background-color:currentColor;border-radius:50%;opacity:0;animation:.75s linear infinite spinner-grow}.spinner-grow-sm{width:1rem;height:1rem}@media(prefers-reduced-motion: reduce){.spinner-border,.spinner-grow{animation-duration:1.5s;-webkit-animation-duration:1.5s;-moz-animation-duration:1.5s;-ms-animation-duration:1.5s;-o-animation-duration:1.5s}}.offcanvas{position:fixed;bottom:0;z-index:1045;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;visibility:hidden;background-color:#fff;background-clip:padding-box;outline:0;transition:transform .3s ease-in-out}@media(prefers-reduced-motion: reduce){.offcanvas{transition:none}}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:1rem 1rem}.offcanvas-header .btn-close{padding:.5rem .5rem;margin-top:-0.5rem;margin-right:-0.5rem;margin-bottom:-0.5rem}.offcanvas-title{margin-bottom:0;line-height:1.5}.offcanvas-body{flex-grow:1;-webkit-flex-grow:1;padding:1rem 1rem;overflow-y:auto}.offcanvas-start{top:0;left:0;width:400px;border-right:1px solid rgba(0,0,0,.2);transform:translateX(-100%)}.offcanvas-end{top:0;right:0;width:400px;border-left:1px solid rgba(0,0,0,.2);transform:translateX(100%)}.offcanvas-top{top:0;right:0;left:0;height:30vh;max-height:100%;border-bottom:1px solid rgba(0,0,0,.2);transform:translateY(-100%)}.offcanvas-bottom{right:0;left:0;height:30vh;max-height:100%;border-top:1px solid rgba(0,0,0,.2);transform:translateY(100%)}.offcanvas.show{transform:none}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentColor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);-webkit-mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);mask-size:200% 100%;-webkit-mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{mask-position:-200% 0%;-webkit-mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.link-default{color:#373a3c}.link-default:hover,.link-default:focus{color:#2c2e30}.link-primary{color:#2780e3}.link-primary:hover,.link-primary:focus{color:#1f66b6}.link-secondary{color:#373a3c}.link-secondary:hover,.link-secondary:focus{color:#2c2e30}.link-success{color:#3fb618}.link-success:hover,.link-success:focus{color:#329213}.link-info{color:#9954bb}.link-info:hover,.link-info:focus{color:#7a4396}.link-warning{color:#ff7518}.link-warning:hover,.link-warning:focus{color:#cc5e13}.link-danger{color:#ff0039}.link-danger:hover,.link-danger:focus{color:#cc002e}.link-light{color:#f8f9fa}.link-light:hover,.link-light:focus{color:#f9fafb}.link-dark{color:#373a3c}.link-dark:hover,.link-dark:focus{color:#2c2e30}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio: 100%}.ratio-4x3{--bs-aspect-ratio: calc(3 / 4 * 100%)}.ratio-16x9{--bs-aspect-ratio: calc(9 / 16 * 100%)}.ratio-21x9{--bs-aspect-ratio: calc(9 / 21 * 100%)}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:sticky;top:0;z-index:1020}@media(min-width: 576px){.sticky-sm-top{position:sticky;top:0;z-index:1020}}@media(min-width: 768px){.sticky-md-top{position:sticky;top:0;z-index:1020}}@media(min-width: 992px){.sticky-lg-top{position:sticky;top:0;z-index:1020}}@media(min-width: 1200px){.sticky-xl-top{position:sticky;top:0;z-index:1020}}@media(min-width: 1400px){.sticky-xxl-top{position:sticky;top:0;z-index:1020}}.hstack{display:flex;display:-webkit-flex;flex-direction:row;-webkit-flex-direction:row;align-items:center;-webkit-align-items:center;align-self:stretch;-webkit-align-self:stretch}.vstack{display:flex;display:-webkit-flex;flex:1 1 auto;-webkit-flex:1 1 auto;flex-direction:column;-webkit-flex-direction:column;align-self:stretch;-webkit-align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;-webkit-align-self:stretch;width:1px;min-height:1em;background-color:currentColor;opacity:.25}.align-baseline{vertical-align:baseline !important}.align-top{vertical-align:top !important}.align-middle{vertical-align:middle !important}.align-bottom{vertical-align:bottom !important}.align-text-bottom{vertical-align:text-bottom !important}.align-text-top{vertical-align:text-top !important}.float-start{float:left !important}.float-end{float:right !important}.float-none{float:none !important}.opacity-0{opacity:0 !important}.opacity-25{opacity:.25 !important}.opacity-50{opacity:.5 !important}.opacity-75{opacity:.75 !important}.opacity-100{opacity:1 !important}.overflow-auto{overflow:auto !important}.overflow-hidden{overflow:hidden !important}.overflow-visible{overflow:visible !important}.overflow-scroll{overflow:scroll !important}.d-inline{display:inline !important}.d-inline-block{display:inline-block !important}.d-block{display:block !important}.d-grid{display:grid !important}.d-table{display:table !important}.d-table-row{display:table-row !important}.d-table-cell{display:table-cell !important}.d-flex{display:flex !important}.d-inline-flex{display:inline-flex !important}.d-none{display:none !important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15) !important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075) !important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175) !important}.shadow-none{box-shadow:none !important}.position-static{position:static !important}.position-relative{position:relative !important}.position-absolute{position:absolute !important}.position-fixed{position:fixed !important}.position-sticky{position:sticky !important}.top-0{top:0 !important}.top-50{top:50% !important}.top-100{top:100% !important}.bottom-0{bottom:0 !important}.bottom-50{bottom:50% !important}.bottom-100{bottom:100% !important}.start-0{left:0 !important}.start-50{left:50% !important}.start-100{left:100% !important}.end-0{right:0 !important}.end-50{right:50% !important}.end-100{right:100% !important}.translate-middle{transform:translate(-50%, -50%) !important}.translate-middle-x{transform:translateX(-50%) !important}.translate-middle-y{transform:translateY(-50%) !important}.border{border:1px solid #dee2e6 !important}.border-0{border:0 !important}.border-top{border-top:1px solid #dee2e6 !important}.border-top-0{border-top:0 !important}.border-end{border-right:1px solid #dee2e6 !important}.border-end-0{border-right:0 !important}.border-bottom{border-bottom:1px solid #dee2e6 !important}.border-bottom-0{border-bottom:0 !important}.border-start{border-left:1px solid #dee2e6 !important}.border-start-0{border-left:0 !important}.border-default{border-color:#373a3c !important}.border-primary{border-color:#2780e3 !important}.border-secondary{border-color:#373a3c !important}.border-success{border-color:#3fb618 !important}.border-info{border-color:#9954bb !important}.border-warning{border-color:#ff7518 !important}.border-danger{border-color:#ff0039 !important}.border-light{border-color:#f8f9fa !important}.border-dark{border-color:#373a3c !important}.border-white{border-color:#fff !important}.border-1{border-width:1px !important}.border-2{border-width:2px !important}.border-3{border-width:3px !important}.border-4{border-width:4px !important}.border-5{border-width:5px !important}.w-25{width:25% !important}.w-50{width:50% !important}.w-75{width:75% !important}.w-100{width:100% !important}.w-auto{width:auto !important}.mw-100{max-width:100% !important}.vw-100{width:100vw !important}.min-vw-100{min-width:100vw !important}.h-25{height:25% !important}.h-50{height:50% !important}.h-75{height:75% !important}.h-100{height:100% !important}.h-auto{height:auto !important}.mh-100{max-height:100% !important}.vh-100{height:100vh !important}.min-vh-100{min-height:100vh !important}.flex-fill{flex:1 1 auto !important}.flex-row{flex-direction:row !important}.flex-column{flex-direction:column !important}.flex-row-reverse{flex-direction:row-reverse !important}.flex-column-reverse{flex-direction:column-reverse !important}.flex-grow-0{flex-grow:0 !important}.flex-grow-1{flex-grow:1 !important}.flex-shrink-0{flex-shrink:0 !important}.flex-shrink-1{flex-shrink:1 !important}.flex-wrap{flex-wrap:wrap !important}.flex-nowrap{flex-wrap:nowrap !important}.flex-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-0{gap:0 !important}.gap-1{gap:.25rem !important}.gap-2{gap:.5rem !important}.gap-3{gap:1rem !important}.gap-4{gap:1.5rem !important}.gap-5{gap:3rem !important}.justify-content-start{justify-content:flex-start !important}.justify-content-end{justify-content:flex-end !important}.justify-content-center{justify-content:center !important}.justify-content-between{justify-content:space-between !important}.justify-content-around{justify-content:space-around !important}.justify-content-evenly{justify-content:space-evenly !important}.align-items-start{align-items:flex-start !important}.align-items-end{align-items:flex-end !important}.align-items-center{align-items:center !important}.align-items-baseline{align-items:baseline !important}.align-items-stretch{align-items:stretch !important}.align-content-start{align-content:flex-start !important}.align-content-end{align-content:flex-end !important}.align-content-center{align-content:center !important}.align-content-between{align-content:space-between !important}.align-content-around{align-content:space-around !important}.align-content-stretch{align-content:stretch !important}.align-self-auto{align-self:auto !important}.align-self-start{align-self:flex-start !important}.align-self-end{align-self:flex-end !important}.align-self-center{align-self:center !important}.align-self-baseline{align-self:baseline !important}.align-self-stretch{align-self:stretch !important}.order-first{order:-1 !important}.order-0{order:0 !important}.order-1{order:1 !important}.order-2{order:2 !important}.order-3{order:3 !important}.order-4{order:4 !important}.order-5{order:5 !important}.order-last{order:6 !important}.m-0{margin:0 !important}.m-1{margin:.25rem !important}.m-2{margin:.5rem !important}.m-3{margin:1rem !important}.m-4{margin:1.5rem !important}.m-5{margin:3rem !important}.m-auto{margin:auto !important}.mx-0{margin-right:0 !important;margin-left:0 !important}.mx-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-3{margin-right:1rem !important;margin-left:1rem !important}.mx-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-5{margin-right:3rem !important;margin-left:3rem !important}.mx-auto{margin-right:auto !important;margin-left:auto !important}.my-0{margin-top:0 !important;margin-bottom:0 !important}.my-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-0{margin-top:0 !important}.mt-1{margin-top:.25rem !important}.mt-2{margin-top:.5rem !important}.mt-3{margin-top:1rem !important}.mt-4{margin-top:1.5rem !important}.mt-5{margin-top:3rem !important}.mt-auto{margin-top:auto !important}.me-0{margin-right:0 !important}.me-1{margin-right:.25rem !important}.me-2{margin-right:.5rem !important}.me-3{margin-right:1rem !important}.me-4{margin-right:1.5rem !important}.me-5{margin-right:3rem !important}.me-auto{margin-right:auto !important}.mb-0{margin-bottom:0 !important}.mb-1{margin-bottom:.25rem !important}.mb-2{margin-bottom:.5rem !important}.mb-3{margin-bottom:1rem !important}.mb-4{margin-bottom:1.5rem !important}.mb-5{margin-bottom:3rem !important}.mb-auto{margin-bottom:auto !important}.ms-0{margin-left:0 !important}.ms-1{margin-left:.25rem !important}.ms-2{margin-left:.5rem !important}.ms-3{margin-left:1rem !important}.ms-4{margin-left:1.5rem !important}.ms-5{margin-left:3rem !important}.ms-auto{margin-left:auto !important}.p-0{padding:0 !important}.p-1{padding:.25rem !important}.p-2{padding:.5rem !important}.p-3{padding:1rem !important}.p-4{padding:1.5rem !important}.p-5{padding:3rem !important}.px-0{padding-right:0 !important;padding-left:0 !important}.px-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-3{padding-right:1rem !important;padding-left:1rem !important}.px-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-5{padding-right:3rem !important;padding-left:3rem !important}.py-0{padding-top:0 !important;padding-bottom:0 !important}.py-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-0{padding-top:0 !important}.pt-1{padding-top:.25rem !important}.pt-2{padding-top:.5rem !important}.pt-3{padding-top:1rem !important}.pt-4{padding-top:1.5rem !important}.pt-5{padding-top:3rem !important}.pe-0{padding-right:0 !important}.pe-1{padding-right:.25rem !important}.pe-2{padding-right:.5rem !important}.pe-3{padding-right:1rem !important}.pe-4{padding-right:1.5rem !important}.pe-5{padding-right:3rem !important}.pb-0{padding-bottom:0 !important}.pb-1{padding-bottom:.25rem !important}.pb-2{padding-bottom:.5rem !important}.pb-3{padding-bottom:1rem !important}.pb-4{padding-bottom:1.5rem !important}.pb-5{padding-bottom:3rem !important}.ps-0{padding-left:0 !important}.ps-1{padding-left:.25rem !important}.ps-2{padding-left:.5rem !important}.ps-3{padding-left:1rem !important}.ps-4{padding-left:1.5rem !important}.ps-5{padding-left:3rem !important}.font-monospace{font-family:var(--bs-font-monospace) !important}.fs-1{font-size:calc(1.345rem + 1.14vw) !important}.fs-2{font-size:calc(1.3rem + 0.6vw) !important}.fs-3{font-size:calc(1.275rem + 0.3vw) !important}.fs-4{font-size:1.25rem !important}.fs-5{font-size:1.1rem !important}.fs-6{font-size:1rem !important}.fst-italic{font-style:italic !important}.fst-normal{font-style:normal !important}.fw-light{font-weight:300 !important}.fw-lighter{font-weight:lighter !important}.fw-normal{font-weight:400 !important}.fw-bold{font-weight:700 !important}.fw-bolder{font-weight:bolder !important}.lh-1{line-height:1 !important}.lh-sm{line-height:1.25 !important}.lh-base{line-height:1.5 !important}.lh-lg{line-height:2 !important}.text-start{text-align:left !important}.text-end{text-align:right !important}.text-center{text-align:center !important}.text-decoration-none{text-decoration:none !important}.text-decoration-underline{text-decoration:underline !important}.text-decoration-line-through{text-decoration:line-through !important}.text-lowercase{text-transform:lowercase !important}.text-uppercase{text-transform:uppercase !important}.text-capitalize{text-transform:capitalize !important}.text-wrap{white-space:normal !important}.text-nowrap{white-space:nowrap !important}.text-break{word-wrap:break-word !important;word-break:break-word !important}.text-default{--bs-text-opacity: 1;color:rgba(var(--bs-default-rgb), var(--bs-text-opacity)) !important}.text-primary{--bs-text-opacity: 1;color:rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important}.text-secondary{--bs-text-opacity: 1;color:rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important}.text-success{--bs-text-opacity: 1;color:rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important}.text-info{--bs-text-opacity: 1;color:rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important}.text-warning{--bs-text-opacity: 1;color:rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important}.text-danger{--bs-text-opacity: 1;color:rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important}.text-light{--bs-text-opacity: 1;color:rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important}.text-dark{--bs-text-opacity: 1;color:rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important}.text-black{--bs-text-opacity: 1;color:rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important}.text-white{--bs-text-opacity: 1;color:rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important}.text-body{--bs-text-opacity: 1;color:rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important}.text-muted{--bs-text-opacity: 1;color:#6c757d !important}.text-black-50{--bs-text-opacity: 1;color:rgba(0,0,0,.5) !important}.text-white-50{--bs-text-opacity: 1;color:rgba(255,255,255,.5) !important}.text-reset{--bs-text-opacity: 1;color:inherit !important}.text-opacity-25{--bs-text-opacity: 0.25}.text-opacity-50{--bs-text-opacity: 0.5}.text-opacity-75{--bs-text-opacity: 0.75}.text-opacity-100{--bs-text-opacity: 1}.bg-default{--bs-bg-opacity: 1;background-color:rgba(var(--bs-default-rgb), var(--bs-bg-opacity)) !important}.bg-primary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important}.bg-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important}.bg-success{--bs-bg-opacity: 1;background-color:rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important}.bg-info{--bs-bg-opacity: 1;background-color:rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important}.bg-warning{--bs-bg-opacity: 1;background-color:rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important}.bg-danger{--bs-bg-opacity: 1;background-color:rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important}.bg-light{--bs-bg-opacity: 1;background-color:rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important}.bg-dark{--bs-bg-opacity: 1;background-color:rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important}.bg-black{--bs-bg-opacity: 1;background-color:rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important}.bg-white{--bs-bg-opacity: 1;background-color:rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important}.bg-body{--bs-bg-opacity: 1;background-color:rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important}.bg-transparent{--bs-bg-opacity: 1;background-color:transparent !important}.bg-opacity-10{--bs-bg-opacity: 0.1}.bg-opacity-25{--bs-bg-opacity: 0.25}.bg-opacity-50{--bs-bg-opacity: 0.5}.bg-opacity-75{--bs-bg-opacity: 0.75}.bg-opacity-100{--bs-bg-opacity: 1}.bg-gradient{background-image:var(--bs-gradient) !important}.user-select-all{user-select:all !important}.user-select-auto{user-select:auto !important}.user-select-none{user-select:none !important}.pe-none{pointer-events:none !important}.pe-auto{pointer-events:auto !important}.rounded{border-radius:.25rem !important}.rounded-0{border-radius:0 !important}.rounded-1{border-radius:.2em !important}.rounded-2{border-radius:.25rem !important}.rounded-3{border-radius:.3rem !important}.rounded-circle{border-radius:50% !important}.rounded-pill{border-radius:50rem !important}.rounded-top{border-top-left-radius:.25rem !important;border-top-right-radius:.25rem !important}.rounded-end{border-top-right-radius:.25rem !important;border-bottom-right-radius:.25rem !important}.rounded-bottom{border-bottom-right-radius:.25rem !important;border-bottom-left-radius:.25rem !important}.rounded-start{border-bottom-left-radius:.25rem !important;border-top-left-radius:.25rem !important}.visible{visibility:visible !important}.invisible{visibility:hidden !important}@media(min-width: 576px){.float-sm-start{float:left !important}.float-sm-end{float:right !important}.float-sm-none{float:none !important}.d-sm-inline{display:inline !important}.d-sm-inline-block{display:inline-block !important}.d-sm-block{display:block !important}.d-sm-grid{display:grid !important}.d-sm-table{display:table !important}.d-sm-table-row{display:table-row !important}.d-sm-table-cell{display:table-cell !important}.d-sm-flex{display:flex !important}.d-sm-inline-flex{display:inline-flex !important}.d-sm-none{display:none !important}.flex-sm-fill{flex:1 1 auto !important}.flex-sm-row{flex-direction:row !important}.flex-sm-column{flex-direction:column !important}.flex-sm-row-reverse{flex-direction:row-reverse !important}.flex-sm-column-reverse{flex-direction:column-reverse !important}.flex-sm-grow-0{flex-grow:0 !important}.flex-sm-grow-1{flex-grow:1 !important}.flex-sm-shrink-0{flex-shrink:0 !important}.flex-sm-shrink-1{flex-shrink:1 !important}.flex-sm-wrap{flex-wrap:wrap !important}.flex-sm-nowrap{flex-wrap:nowrap !important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-sm-0{gap:0 !important}.gap-sm-1{gap:.25rem !important}.gap-sm-2{gap:.5rem !important}.gap-sm-3{gap:1rem !important}.gap-sm-4{gap:1.5rem !important}.gap-sm-5{gap:3rem !important}.justify-content-sm-start{justify-content:flex-start !important}.justify-content-sm-end{justify-content:flex-end !important}.justify-content-sm-center{justify-content:center !important}.justify-content-sm-between{justify-content:space-between !important}.justify-content-sm-around{justify-content:space-around !important}.justify-content-sm-evenly{justify-content:space-evenly !important}.align-items-sm-start{align-items:flex-start !important}.align-items-sm-end{align-items:flex-end !important}.align-items-sm-center{align-items:center !important}.align-items-sm-baseline{align-items:baseline !important}.align-items-sm-stretch{align-items:stretch !important}.align-content-sm-start{align-content:flex-start !important}.align-content-sm-end{align-content:flex-end !important}.align-content-sm-center{align-content:center !important}.align-content-sm-between{align-content:space-between !important}.align-content-sm-around{align-content:space-around !important}.align-content-sm-stretch{align-content:stretch !important}.align-self-sm-auto{align-self:auto !important}.align-self-sm-start{align-self:flex-start !important}.align-self-sm-end{align-self:flex-end !important}.align-self-sm-center{align-self:center !important}.align-self-sm-baseline{align-self:baseline !important}.align-self-sm-stretch{align-self:stretch !important}.order-sm-first{order:-1 !important}.order-sm-0{order:0 !important}.order-sm-1{order:1 !important}.order-sm-2{order:2 !important}.order-sm-3{order:3 !important}.order-sm-4{order:4 !important}.order-sm-5{order:5 !important}.order-sm-last{order:6 !important}.m-sm-0{margin:0 !important}.m-sm-1{margin:.25rem !important}.m-sm-2{margin:.5rem !important}.m-sm-3{margin:1rem !important}.m-sm-4{margin:1.5rem !important}.m-sm-5{margin:3rem !important}.m-sm-auto{margin:auto !important}.mx-sm-0{margin-right:0 !important;margin-left:0 !important}.mx-sm-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-sm-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-sm-3{margin-right:1rem !important;margin-left:1rem !important}.mx-sm-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-sm-5{margin-right:3rem !important;margin-left:3rem !important}.mx-sm-auto{margin-right:auto !important;margin-left:auto !important}.my-sm-0{margin-top:0 !important;margin-bottom:0 !important}.my-sm-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-sm-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-sm-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-sm-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-sm-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-sm-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-sm-0{margin-top:0 !important}.mt-sm-1{margin-top:.25rem !important}.mt-sm-2{margin-top:.5rem !important}.mt-sm-3{margin-top:1rem !important}.mt-sm-4{margin-top:1.5rem !important}.mt-sm-5{margin-top:3rem !important}.mt-sm-auto{margin-top:auto !important}.me-sm-0{margin-right:0 !important}.me-sm-1{margin-right:.25rem !important}.me-sm-2{margin-right:.5rem !important}.me-sm-3{margin-right:1rem !important}.me-sm-4{margin-right:1.5rem !important}.me-sm-5{margin-right:3rem !important}.me-sm-auto{margin-right:auto !important}.mb-sm-0{margin-bottom:0 !important}.mb-sm-1{margin-bottom:.25rem !important}.mb-sm-2{margin-bottom:.5rem !important}.mb-sm-3{margin-bottom:1rem !important}.mb-sm-4{margin-bottom:1.5rem !important}.mb-sm-5{margin-bottom:3rem !important}.mb-sm-auto{margin-bottom:auto !important}.ms-sm-0{margin-left:0 !important}.ms-sm-1{margin-left:.25rem !important}.ms-sm-2{margin-left:.5rem !important}.ms-sm-3{margin-left:1rem !important}.ms-sm-4{margin-left:1.5rem !important}.ms-sm-5{margin-left:3rem !important}.ms-sm-auto{margin-left:auto !important}.p-sm-0{padding:0 !important}.p-sm-1{padding:.25rem !important}.p-sm-2{padding:.5rem !important}.p-sm-3{padding:1rem !important}.p-sm-4{padding:1.5rem !important}.p-sm-5{padding:3rem !important}.px-sm-0{padding-right:0 !important;padding-left:0 !important}.px-sm-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-sm-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-sm-3{padding-right:1rem !important;padding-left:1rem !important}.px-sm-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-sm-5{padding-right:3rem !important;padding-left:3rem !important}.py-sm-0{padding-top:0 !important;padding-bottom:0 !important}.py-sm-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-sm-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-sm-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-sm-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-sm-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-sm-0{padding-top:0 !important}.pt-sm-1{padding-top:.25rem !important}.pt-sm-2{padding-top:.5rem !important}.pt-sm-3{padding-top:1rem !important}.pt-sm-4{padding-top:1.5rem !important}.pt-sm-5{padding-top:3rem !important}.pe-sm-0{padding-right:0 !important}.pe-sm-1{padding-right:.25rem !important}.pe-sm-2{padding-right:.5rem !important}.pe-sm-3{padding-right:1rem !important}.pe-sm-4{padding-right:1.5rem !important}.pe-sm-5{padding-right:3rem !important}.pb-sm-0{padding-bottom:0 !important}.pb-sm-1{padding-bottom:.25rem !important}.pb-sm-2{padding-bottom:.5rem !important}.pb-sm-3{padding-bottom:1rem !important}.pb-sm-4{padding-bottom:1.5rem !important}.pb-sm-5{padding-bottom:3rem !important}.ps-sm-0{padding-left:0 !important}.ps-sm-1{padding-left:.25rem !important}.ps-sm-2{padding-left:.5rem !important}.ps-sm-3{padding-left:1rem !important}.ps-sm-4{padding-left:1.5rem !important}.ps-sm-5{padding-left:3rem !important}.text-sm-start{text-align:left !important}.text-sm-end{text-align:right !important}.text-sm-center{text-align:center !important}}@media(min-width: 768px){.float-md-start{float:left !important}.float-md-end{float:right !important}.float-md-none{float:none !important}.d-md-inline{display:inline !important}.d-md-inline-block{display:inline-block !important}.d-md-block{display:block !important}.d-md-grid{display:grid !important}.d-md-table{display:table !important}.d-md-table-row{display:table-row !important}.d-md-table-cell{display:table-cell !important}.d-md-flex{display:flex !important}.d-md-inline-flex{display:inline-flex !important}.d-md-none{display:none !important}.flex-md-fill{flex:1 1 auto !important}.flex-md-row{flex-direction:row !important}.flex-md-column{flex-direction:column !important}.flex-md-row-reverse{flex-direction:row-reverse !important}.flex-md-column-reverse{flex-direction:column-reverse !important}.flex-md-grow-0{flex-grow:0 !important}.flex-md-grow-1{flex-grow:1 !important}.flex-md-shrink-0{flex-shrink:0 !important}.flex-md-shrink-1{flex-shrink:1 !important}.flex-md-wrap{flex-wrap:wrap !important}.flex-md-nowrap{flex-wrap:nowrap !important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-md-0{gap:0 !important}.gap-md-1{gap:.25rem !important}.gap-md-2{gap:.5rem !important}.gap-md-3{gap:1rem !important}.gap-md-4{gap:1.5rem !important}.gap-md-5{gap:3rem !important}.justify-content-md-start{justify-content:flex-start !important}.justify-content-md-end{justify-content:flex-end !important}.justify-content-md-center{justify-content:center !important}.justify-content-md-between{justify-content:space-between !important}.justify-content-md-around{justify-content:space-around !important}.justify-content-md-evenly{justify-content:space-evenly !important}.align-items-md-start{align-items:flex-start !important}.align-items-md-end{align-items:flex-end !important}.align-items-md-center{align-items:center !important}.align-items-md-baseline{align-items:baseline !important}.align-items-md-stretch{align-items:stretch !important}.align-content-md-start{align-content:flex-start !important}.align-content-md-end{align-content:flex-end !important}.align-content-md-center{align-content:center !important}.align-content-md-between{align-content:space-between !important}.align-content-md-around{align-content:space-around !important}.align-content-md-stretch{align-content:stretch !important}.align-self-md-auto{align-self:auto !important}.align-self-md-start{align-self:flex-start !important}.align-self-md-end{align-self:flex-end !important}.align-self-md-center{align-self:center !important}.align-self-md-baseline{align-self:baseline !important}.align-self-md-stretch{align-self:stretch !important}.order-md-first{order:-1 !important}.order-md-0{order:0 !important}.order-md-1{order:1 !important}.order-md-2{order:2 !important}.order-md-3{order:3 !important}.order-md-4{order:4 !important}.order-md-5{order:5 !important}.order-md-last{order:6 !important}.m-md-0{margin:0 !important}.m-md-1{margin:.25rem !important}.m-md-2{margin:.5rem !important}.m-md-3{margin:1rem !important}.m-md-4{margin:1.5rem !important}.m-md-5{margin:3rem !important}.m-md-auto{margin:auto !important}.mx-md-0{margin-right:0 !important;margin-left:0 !important}.mx-md-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-md-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-md-3{margin-right:1rem !important;margin-left:1rem !important}.mx-md-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-md-5{margin-right:3rem !important;margin-left:3rem !important}.mx-md-auto{margin-right:auto !important;margin-left:auto !important}.my-md-0{margin-top:0 !important;margin-bottom:0 !important}.my-md-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-md-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-md-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-md-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-md-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-md-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-md-0{margin-top:0 !important}.mt-md-1{margin-top:.25rem !important}.mt-md-2{margin-top:.5rem !important}.mt-md-3{margin-top:1rem !important}.mt-md-4{margin-top:1.5rem !important}.mt-md-5{margin-top:3rem !important}.mt-md-auto{margin-top:auto !important}.me-md-0{margin-right:0 !important}.me-md-1{margin-right:.25rem !important}.me-md-2{margin-right:.5rem !important}.me-md-3{margin-right:1rem !important}.me-md-4{margin-right:1.5rem !important}.me-md-5{margin-right:3rem !important}.me-md-auto{margin-right:auto !important}.mb-md-0{margin-bottom:0 !important}.mb-md-1{margin-bottom:.25rem !important}.mb-md-2{margin-bottom:.5rem !important}.mb-md-3{margin-bottom:1rem !important}.mb-md-4{margin-bottom:1.5rem !important}.mb-md-5{margin-bottom:3rem !important}.mb-md-auto{margin-bottom:auto !important}.ms-md-0{margin-left:0 !important}.ms-md-1{margin-left:.25rem !important}.ms-md-2{margin-left:.5rem !important}.ms-md-3{margin-left:1rem !important}.ms-md-4{margin-left:1.5rem !important}.ms-md-5{margin-left:3rem !important}.ms-md-auto{margin-left:auto !important}.p-md-0{padding:0 !important}.p-md-1{padding:.25rem !important}.p-md-2{padding:.5rem !important}.p-md-3{padding:1rem !important}.p-md-4{padding:1.5rem !important}.p-md-5{padding:3rem !important}.px-md-0{padding-right:0 !important;padding-left:0 !important}.px-md-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-md-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-md-3{padding-right:1rem !important;padding-left:1rem !important}.px-md-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-md-5{padding-right:3rem !important;padding-left:3rem !important}.py-md-0{padding-top:0 !important;padding-bottom:0 !important}.py-md-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-md-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-md-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-md-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-md-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-md-0{padding-top:0 !important}.pt-md-1{padding-top:.25rem !important}.pt-md-2{padding-top:.5rem !important}.pt-md-3{padding-top:1rem !important}.pt-md-4{padding-top:1.5rem !important}.pt-md-5{padding-top:3rem !important}.pe-md-0{padding-right:0 !important}.pe-md-1{padding-right:.25rem !important}.pe-md-2{padding-right:.5rem !important}.pe-md-3{padding-right:1rem !important}.pe-md-4{padding-right:1.5rem !important}.pe-md-5{padding-right:3rem !important}.pb-md-0{padding-bottom:0 !important}.pb-md-1{padding-bottom:.25rem !important}.pb-md-2{padding-bottom:.5rem !important}.pb-md-3{padding-bottom:1rem !important}.pb-md-4{padding-bottom:1.5rem !important}.pb-md-5{padding-bottom:3rem !important}.ps-md-0{padding-left:0 !important}.ps-md-1{padding-left:.25rem !important}.ps-md-2{padding-left:.5rem !important}.ps-md-3{padding-left:1rem !important}.ps-md-4{padding-left:1.5rem !important}.ps-md-5{padding-left:3rem !important}.text-md-start{text-align:left !important}.text-md-end{text-align:right !important}.text-md-center{text-align:center !important}}@media(min-width: 992px){.float-lg-start{float:left !important}.float-lg-end{float:right !important}.float-lg-none{float:none !important}.d-lg-inline{display:inline !important}.d-lg-inline-block{display:inline-block !important}.d-lg-block{display:block !important}.d-lg-grid{display:grid !important}.d-lg-table{display:table !important}.d-lg-table-row{display:table-row !important}.d-lg-table-cell{display:table-cell !important}.d-lg-flex{display:flex !important}.d-lg-inline-flex{display:inline-flex !important}.d-lg-none{display:none !important}.flex-lg-fill{flex:1 1 auto !important}.flex-lg-row{flex-direction:row !important}.flex-lg-column{flex-direction:column !important}.flex-lg-row-reverse{flex-direction:row-reverse !important}.flex-lg-column-reverse{flex-direction:column-reverse !important}.flex-lg-grow-0{flex-grow:0 !important}.flex-lg-grow-1{flex-grow:1 !important}.flex-lg-shrink-0{flex-shrink:0 !important}.flex-lg-shrink-1{flex-shrink:1 !important}.flex-lg-wrap{flex-wrap:wrap !important}.flex-lg-nowrap{flex-wrap:nowrap !important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-lg-0{gap:0 !important}.gap-lg-1{gap:.25rem !important}.gap-lg-2{gap:.5rem !important}.gap-lg-3{gap:1rem !important}.gap-lg-4{gap:1.5rem !important}.gap-lg-5{gap:3rem !important}.justify-content-lg-start{justify-content:flex-start !important}.justify-content-lg-end{justify-content:flex-end !important}.justify-content-lg-center{justify-content:center !important}.justify-content-lg-between{justify-content:space-between !important}.justify-content-lg-around{justify-content:space-around !important}.justify-content-lg-evenly{justify-content:space-evenly !important}.align-items-lg-start{align-items:flex-start !important}.align-items-lg-end{align-items:flex-end !important}.align-items-lg-center{align-items:center !important}.align-items-lg-baseline{align-items:baseline !important}.align-items-lg-stretch{align-items:stretch !important}.align-content-lg-start{align-content:flex-start !important}.align-content-lg-end{align-content:flex-end !important}.align-content-lg-center{align-content:center !important}.align-content-lg-between{align-content:space-between !important}.align-content-lg-around{align-content:space-around !important}.align-content-lg-stretch{align-content:stretch !important}.align-self-lg-auto{align-self:auto !important}.align-self-lg-start{align-self:flex-start !important}.align-self-lg-end{align-self:flex-end !important}.align-self-lg-center{align-self:center !important}.align-self-lg-baseline{align-self:baseline !important}.align-self-lg-stretch{align-self:stretch !important}.order-lg-first{order:-1 !important}.order-lg-0{order:0 !important}.order-lg-1{order:1 !important}.order-lg-2{order:2 !important}.order-lg-3{order:3 !important}.order-lg-4{order:4 !important}.order-lg-5{order:5 !important}.order-lg-last{order:6 !important}.m-lg-0{margin:0 !important}.m-lg-1{margin:.25rem !important}.m-lg-2{margin:.5rem !important}.m-lg-3{margin:1rem !important}.m-lg-4{margin:1.5rem !important}.m-lg-5{margin:3rem !important}.m-lg-auto{margin:auto !important}.mx-lg-0{margin-right:0 !important;margin-left:0 !important}.mx-lg-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-lg-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-lg-3{margin-right:1rem !important;margin-left:1rem !important}.mx-lg-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-lg-5{margin-right:3rem !important;margin-left:3rem !important}.mx-lg-auto{margin-right:auto !important;margin-left:auto !important}.my-lg-0{margin-top:0 !important;margin-bottom:0 !important}.my-lg-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-lg-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-lg-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-lg-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-lg-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-lg-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-lg-0{margin-top:0 !important}.mt-lg-1{margin-top:.25rem !important}.mt-lg-2{margin-top:.5rem !important}.mt-lg-3{margin-top:1rem !important}.mt-lg-4{margin-top:1.5rem !important}.mt-lg-5{margin-top:3rem !important}.mt-lg-auto{margin-top:auto !important}.me-lg-0{margin-right:0 !important}.me-lg-1{margin-right:.25rem !important}.me-lg-2{margin-right:.5rem !important}.me-lg-3{margin-right:1rem !important}.me-lg-4{margin-right:1.5rem !important}.me-lg-5{margin-right:3rem !important}.me-lg-auto{margin-right:auto !important}.mb-lg-0{margin-bottom:0 !important}.mb-lg-1{margin-bottom:.25rem !important}.mb-lg-2{margin-bottom:.5rem !important}.mb-lg-3{margin-bottom:1rem !important}.mb-lg-4{margin-bottom:1.5rem !important}.mb-lg-5{margin-bottom:3rem !important}.mb-lg-auto{margin-bottom:auto !important}.ms-lg-0{margin-left:0 !important}.ms-lg-1{margin-left:.25rem !important}.ms-lg-2{margin-left:.5rem !important}.ms-lg-3{margin-left:1rem !important}.ms-lg-4{margin-left:1.5rem !important}.ms-lg-5{margin-left:3rem !important}.ms-lg-auto{margin-left:auto !important}.p-lg-0{padding:0 !important}.p-lg-1{padding:.25rem !important}.p-lg-2{padding:.5rem !important}.p-lg-3{padding:1rem !important}.p-lg-4{padding:1.5rem !important}.p-lg-5{padding:3rem !important}.px-lg-0{padding-right:0 !important;padding-left:0 !important}.px-lg-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-lg-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-lg-3{padding-right:1rem !important;padding-left:1rem !important}.px-lg-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-lg-5{padding-right:3rem !important;padding-left:3rem !important}.py-lg-0{padding-top:0 !important;padding-bottom:0 !important}.py-lg-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-lg-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-lg-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-lg-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-lg-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-lg-0{padding-top:0 !important}.pt-lg-1{padding-top:.25rem !important}.pt-lg-2{padding-top:.5rem !important}.pt-lg-3{padding-top:1rem !important}.pt-lg-4{padding-top:1.5rem !important}.pt-lg-5{padding-top:3rem !important}.pe-lg-0{padding-right:0 !important}.pe-lg-1{padding-right:.25rem !important}.pe-lg-2{padding-right:.5rem !important}.pe-lg-3{padding-right:1rem !important}.pe-lg-4{padding-right:1.5rem !important}.pe-lg-5{padding-right:3rem !important}.pb-lg-0{padding-bottom:0 !important}.pb-lg-1{padding-bottom:.25rem !important}.pb-lg-2{padding-bottom:.5rem !important}.pb-lg-3{padding-bottom:1rem !important}.pb-lg-4{padding-bottom:1.5rem !important}.pb-lg-5{padding-bottom:3rem !important}.ps-lg-0{padding-left:0 !important}.ps-lg-1{padding-left:.25rem !important}.ps-lg-2{padding-left:.5rem !important}.ps-lg-3{padding-left:1rem !important}.ps-lg-4{padding-left:1.5rem !important}.ps-lg-5{padding-left:3rem !important}.text-lg-start{text-align:left !important}.text-lg-end{text-align:right !important}.text-lg-center{text-align:center !important}}@media(min-width: 1200px){.float-xl-start{float:left !important}.float-xl-end{float:right !important}.float-xl-none{float:none !important}.d-xl-inline{display:inline !important}.d-xl-inline-block{display:inline-block !important}.d-xl-block{display:block !important}.d-xl-grid{display:grid !important}.d-xl-table{display:table !important}.d-xl-table-row{display:table-row !important}.d-xl-table-cell{display:table-cell !important}.d-xl-flex{display:flex !important}.d-xl-inline-flex{display:inline-flex !important}.d-xl-none{display:none !important}.flex-xl-fill{flex:1 1 auto !important}.flex-xl-row{flex-direction:row !important}.flex-xl-column{flex-direction:column !important}.flex-xl-row-reverse{flex-direction:row-reverse !important}.flex-xl-column-reverse{flex-direction:column-reverse !important}.flex-xl-grow-0{flex-grow:0 !important}.flex-xl-grow-1{flex-grow:1 !important}.flex-xl-shrink-0{flex-shrink:0 !important}.flex-xl-shrink-1{flex-shrink:1 !important}.flex-xl-wrap{flex-wrap:wrap !important}.flex-xl-nowrap{flex-wrap:nowrap !important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-xl-0{gap:0 !important}.gap-xl-1{gap:.25rem !important}.gap-xl-2{gap:.5rem !important}.gap-xl-3{gap:1rem !important}.gap-xl-4{gap:1.5rem !important}.gap-xl-5{gap:3rem !important}.justify-content-xl-start{justify-content:flex-start !important}.justify-content-xl-end{justify-content:flex-end !important}.justify-content-xl-center{justify-content:center !important}.justify-content-xl-between{justify-content:space-between !important}.justify-content-xl-around{justify-content:space-around !important}.justify-content-xl-evenly{justify-content:space-evenly !important}.align-items-xl-start{align-items:flex-start !important}.align-items-xl-end{align-items:flex-end !important}.align-items-xl-center{align-items:center !important}.align-items-xl-baseline{align-items:baseline !important}.align-items-xl-stretch{align-items:stretch !important}.align-content-xl-start{align-content:flex-start !important}.align-content-xl-end{align-content:flex-end !important}.align-content-xl-center{align-content:center !important}.align-content-xl-between{align-content:space-between !important}.align-content-xl-around{align-content:space-around !important}.align-content-xl-stretch{align-content:stretch !important}.align-self-xl-auto{align-self:auto !important}.align-self-xl-start{align-self:flex-start !important}.align-self-xl-end{align-self:flex-end !important}.align-self-xl-center{align-self:center !important}.align-self-xl-baseline{align-self:baseline !important}.align-self-xl-stretch{align-self:stretch !important}.order-xl-first{order:-1 !important}.order-xl-0{order:0 !important}.order-xl-1{order:1 !important}.order-xl-2{order:2 !important}.order-xl-3{order:3 !important}.order-xl-4{order:4 !important}.order-xl-5{order:5 !important}.order-xl-last{order:6 !important}.m-xl-0{margin:0 !important}.m-xl-1{margin:.25rem !important}.m-xl-2{margin:.5rem !important}.m-xl-3{margin:1rem !important}.m-xl-4{margin:1.5rem !important}.m-xl-5{margin:3rem !important}.m-xl-auto{margin:auto !important}.mx-xl-0{margin-right:0 !important;margin-left:0 !important}.mx-xl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xl-auto{margin-right:auto !important;margin-left:auto !important}.my-xl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xl-0{margin-top:0 !important}.mt-xl-1{margin-top:.25rem !important}.mt-xl-2{margin-top:.5rem !important}.mt-xl-3{margin-top:1rem !important}.mt-xl-4{margin-top:1.5rem !important}.mt-xl-5{margin-top:3rem !important}.mt-xl-auto{margin-top:auto !important}.me-xl-0{margin-right:0 !important}.me-xl-1{margin-right:.25rem !important}.me-xl-2{margin-right:.5rem !important}.me-xl-3{margin-right:1rem !important}.me-xl-4{margin-right:1.5rem !important}.me-xl-5{margin-right:3rem !important}.me-xl-auto{margin-right:auto !important}.mb-xl-0{margin-bottom:0 !important}.mb-xl-1{margin-bottom:.25rem !important}.mb-xl-2{margin-bottom:.5rem !important}.mb-xl-3{margin-bottom:1rem !important}.mb-xl-4{margin-bottom:1.5rem !important}.mb-xl-5{margin-bottom:3rem !important}.mb-xl-auto{margin-bottom:auto !important}.ms-xl-0{margin-left:0 !important}.ms-xl-1{margin-left:.25rem !important}.ms-xl-2{margin-left:.5rem !important}.ms-xl-3{margin-left:1rem !important}.ms-xl-4{margin-left:1.5rem !important}.ms-xl-5{margin-left:3rem !important}.ms-xl-auto{margin-left:auto !important}.p-xl-0{padding:0 !important}.p-xl-1{padding:.25rem !important}.p-xl-2{padding:.5rem !important}.p-xl-3{padding:1rem !important}.p-xl-4{padding:1.5rem !important}.p-xl-5{padding:3rem !important}.px-xl-0{padding-right:0 !important;padding-left:0 !important}.px-xl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xl-0{padding-top:0 !important}.pt-xl-1{padding-top:.25rem !important}.pt-xl-2{padding-top:.5rem !important}.pt-xl-3{padding-top:1rem !important}.pt-xl-4{padding-top:1.5rem !important}.pt-xl-5{padding-top:3rem !important}.pe-xl-0{padding-right:0 !important}.pe-xl-1{padding-right:.25rem !important}.pe-xl-2{padding-right:.5rem !important}.pe-xl-3{padding-right:1rem !important}.pe-xl-4{padding-right:1.5rem !important}.pe-xl-5{padding-right:3rem !important}.pb-xl-0{padding-bottom:0 !important}.pb-xl-1{padding-bottom:.25rem !important}.pb-xl-2{padding-bottom:.5rem !important}.pb-xl-3{padding-bottom:1rem !important}.pb-xl-4{padding-bottom:1.5rem !important}.pb-xl-5{padding-bottom:3rem !important}.ps-xl-0{padding-left:0 !important}.ps-xl-1{padding-left:.25rem !important}.ps-xl-2{padding-left:.5rem !important}.ps-xl-3{padding-left:1rem !important}.ps-xl-4{padding-left:1.5rem !important}.ps-xl-5{padding-left:3rem !important}.text-xl-start{text-align:left !important}.text-xl-end{text-align:right !important}.text-xl-center{text-align:center !important}}@media(min-width: 1400px){.float-xxl-start{float:left !important}.float-xxl-end{float:right !important}.float-xxl-none{float:none !important}.d-xxl-inline{display:inline !important}.d-xxl-inline-block{display:inline-block !important}.d-xxl-block{display:block !important}.d-xxl-grid{display:grid !important}.d-xxl-table{display:table !important}.d-xxl-table-row{display:table-row !important}.d-xxl-table-cell{display:table-cell !important}.d-xxl-flex{display:flex !important}.d-xxl-inline-flex{display:inline-flex !important}.d-xxl-none{display:none !important}.flex-xxl-fill{flex:1 1 auto !important}.flex-xxl-row{flex-direction:row !important}.flex-xxl-column{flex-direction:column !important}.flex-xxl-row-reverse{flex-direction:row-reverse !important}.flex-xxl-column-reverse{flex-direction:column-reverse !important}.flex-xxl-grow-0{flex-grow:0 !important}.flex-xxl-grow-1{flex-grow:1 !important}.flex-xxl-shrink-0{flex-shrink:0 !important}.flex-xxl-shrink-1{flex-shrink:1 !important}.flex-xxl-wrap{flex-wrap:wrap !important}.flex-xxl-nowrap{flex-wrap:nowrap !important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-xxl-0{gap:0 !important}.gap-xxl-1{gap:.25rem !important}.gap-xxl-2{gap:.5rem !important}.gap-xxl-3{gap:1rem !important}.gap-xxl-4{gap:1.5rem !important}.gap-xxl-5{gap:3rem !important}.justify-content-xxl-start{justify-content:flex-start !important}.justify-content-xxl-end{justify-content:flex-end !important}.justify-content-xxl-center{justify-content:center !important}.justify-content-xxl-between{justify-content:space-between !important}.justify-content-xxl-around{justify-content:space-around !important}.justify-content-xxl-evenly{justify-content:space-evenly !important}.align-items-xxl-start{align-items:flex-start !important}.align-items-xxl-end{align-items:flex-end !important}.align-items-xxl-center{align-items:center !important}.align-items-xxl-baseline{align-items:baseline !important}.align-items-xxl-stretch{align-items:stretch !important}.align-content-xxl-start{align-content:flex-start !important}.align-content-xxl-end{align-content:flex-end !important}.align-content-xxl-center{align-content:center !important}.align-content-xxl-between{align-content:space-between !important}.align-content-xxl-around{align-content:space-around !important}.align-content-xxl-stretch{align-content:stretch !important}.align-self-xxl-auto{align-self:auto !important}.align-self-xxl-start{align-self:flex-start !important}.align-self-xxl-end{align-self:flex-end !important}.align-self-xxl-center{align-self:center !important}.align-self-xxl-baseline{align-self:baseline !important}.align-self-xxl-stretch{align-self:stretch !important}.order-xxl-first{order:-1 !important}.order-xxl-0{order:0 !important}.order-xxl-1{order:1 !important}.order-xxl-2{order:2 !important}.order-xxl-3{order:3 !important}.order-xxl-4{order:4 !important}.order-xxl-5{order:5 !important}.order-xxl-last{order:6 !important}.m-xxl-0{margin:0 !important}.m-xxl-1{margin:.25rem !important}.m-xxl-2{margin:.5rem !important}.m-xxl-3{margin:1rem !important}.m-xxl-4{margin:1.5rem !important}.m-xxl-5{margin:3rem !important}.m-xxl-auto{margin:auto !important}.mx-xxl-0{margin-right:0 !important;margin-left:0 !important}.mx-xxl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xxl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xxl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xxl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xxl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xxl-auto{margin-right:auto !important;margin-left:auto !important}.my-xxl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xxl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xxl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xxl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xxl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xxl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xxl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xxl-0{margin-top:0 !important}.mt-xxl-1{margin-top:.25rem !important}.mt-xxl-2{margin-top:.5rem !important}.mt-xxl-3{margin-top:1rem !important}.mt-xxl-4{margin-top:1.5rem !important}.mt-xxl-5{margin-top:3rem !important}.mt-xxl-auto{margin-top:auto !important}.me-xxl-0{margin-right:0 !important}.me-xxl-1{margin-right:.25rem !important}.me-xxl-2{margin-right:.5rem !important}.me-xxl-3{margin-right:1rem !important}.me-xxl-4{margin-right:1.5rem !important}.me-xxl-5{margin-right:3rem !important}.me-xxl-auto{margin-right:auto !important}.mb-xxl-0{margin-bottom:0 !important}.mb-xxl-1{margin-bottom:.25rem !important}.mb-xxl-2{margin-bottom:.5rem !important}.mb-xxl-3{margin-bottom:1rem !important}.mb-xxl-4{margin-bottom:1.5rem !important}.mb-xxl-5{margin-bottom:3rem !important}.mb-xxl-auto{margin-bottom:auto !important}.ms-xxl-0{margin-left:0 !important}.ms-xxl-1{margin-left:.25rem !important}.ms-xxl-2{margin-left:.5rem !important}.ms-xxl-3{margin-left:1rem !important}.ms-xxl-4{margin-left:1.5rem !important}.ms-xxl-5{margin-left:3rem !important}.ms-xxl-auto{margin-left:auto !important}.p-xxl-0{padding:0 !important}.p-xxl-1{padding:.25rem !important}.p-xxl-2{padding:.5rem !important}.p-xxl-3{padding:1rem !important}.p-xxl-4{padding:1.5rem !important}.p-xxl-5{padding:3rem !important}.px-xxl-0{padding-right:0 !important;padding-left:0 !important}.px-xxl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xxl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xxl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xxl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xxl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xxl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xxl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xxl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xxl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xxl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xxl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xxl-0{padding-top:0 !important}.pt-xxl-1{padding-top:.25rem !important}.pt-xxl-2{padding-top:.5rem !important}.pt-xxl-3{padding-top:1rem !important}.pt-xxl-4{padding-top:1.5rem !important}.pt-xxl-5{padding-top:3rem !important}.pe-xxl-0{padding-right:0 !important}.pe-xxl-1{padding-right:.25rem !important}.pe-xxl-2{padding-right:.5rem !important}.pe-xxl-3{padding-right:1rem !important}.pe-xxl-4{padding-right:1.5rem !important}.pe-xxl-5{padding-right:3rem !important}.pb-xxl-0{padding-bottom:0 !important}.pb-xxl-1{padding-bottom:.25rem !important}.pb-xxl-2{padding-bottom:.5rem !important}.pb-xxl-3{padding-bottom:1rem !important}.pb-xxl-4{padding-bottom:1.5rem !important}.pb-xxl-5{padding-bottom:3rem !important}.ps-xxl-0{padding-left:0 !important}.ps-xxl-1{padding-left:.25rem !important}.ps-xxl-2{padding-left:.5rem !important}.ps-xxl-3{padding-left:1rem !important}.ps-xxl-4{padding-left:1.5rem !important}.ps-xxl-5{padding-left:3rem !important}.text-xxl-start{text-align:left !important}.text-xxl-end{text-align:right !important}.text-xxl-center{text-align:center !important}}.bg-default{color:#fff}.bg-primary{color:#fff}.bg-secondary{color:#fff}.bg-success{color:#fff}.bg-info{color:#fff}.bg-warning{color:#fff}.bg-danger{color:#fff}.bg-light{color:#000}.bg-dark{color:#fff}@media(min-width: 1200px){.fs-1{font-size:2.2rem !important}.fs-2{font-size:1.75rem !important}.fs-3{font-size:1.5rem !important}}@media print{.d-print-inline{display:inline !important}.d-print-inline-block{display:inline-block !important}.d-print-block{display:block !important}.d-print-grid{display:grid !important}.d-print-table{display:table !important}.d-print-table-row{display:table-row !important}.d-print-table-cell{display:table-cell !important}.d-print-flex{display:flex !important}.d-print-inline-flex{display:inline-flex !important}.d-print-none{display:none !important}}.quarto-container{min-height:calc(100vh - 132px)}footer.footer .nav-footer,#quarto-header nav{padding-left:1em;padding-right:1em}nav[role=doc-toc]{padding-left:.5em}#quarto-content>*{padding-top:14px}@media(max-width: 991.98px){#quarto-content>*{padding-top:0}#quarto-content .subtitle{padding-top:14px}#quarto-content section:first-of-type h2:first-of-type,#quarto-content section:first-of-type .h2:first-of-type{margin-top:1rem}}.headroom-target,header.headroom{will-change:transform;transition:transform 200ms linear;transition:position 200ms linear}header.headroom--pinned{transform:translateY(0%)}header.headroom--unpinned{transform:translateY(-100%)}.navbar-container{width:100%}.navbar-brand{overflow:hidden;text-overflow:ellipsis}.navbar-brand-container{max-width:calc(100% - 85px);min-width:0;display:flex;align-items:center;margin-right:1em}.navbar-brand.navbar-brand-logo{margin-right:4px;display:inline-flex}.navbar-toggler{flex-basis:content;flex-shrink:0}.navbar-logo{max-height:24px;width:auto;padding-right:4px}nav .nav-item:not(.compact){padding-top:1px}nav .nav-link i,nav .dropdown-item i{padding-right:1px}.navbar-expand-lg .navbar-nav .nav-link{padding-left:.6rem;padding-right:.6rem}nav .nav-item.compact .nav-link{padding-left:.5rem;padding-right:.5rem;font-size:1.1rem}.navbar-nav .dropdown-menu{min-width:220px;font-size:.9rem}.navbar .navbar-nav .nav-link.dropdown-toggle::after{opacity:.75;vertical-align:.175em}.navbar ul.dropdown-menu{padding-top:0;padding-bottom:0}.navbar .dropdown-header{text-transform:uppercase;font-size:.8rem;padding:0 .5rem}.navbar .dropdown-item{padding:.4rem .5rem}.navbar .dropdown-item>i.bi{margin-left:.1rem;margin-right:.25em}.sidebar #quarto-search{margin-top:-1px}.sidebar #quarto-search svg.aa-SubmitIcon{width:16px;height:16px}.sidebar-navigation a{color:inherit}.sidebar-title{margin-top:.25rem;padding-bottom:.5rem;font-size:1.3rem;line-height:1.6rem;visibility:visible}.sidebar-title>a{font-size:inherit;text-decoration:none}.sidebar-title .sidebar-tools-main{margin-top:-6px}.sidebar-header-stacked .sidebar-title{margin-top:.6rem}.sidebar-logo{max-width:90%;padding-bottom:.5rem}.sidebar-logo-link{text-decoration:none}.sidebar-navigation li a{text-decoration:none}.sidebar-navigation .sidebar-tool{opacity:.7;font-size:.875rem}#quarto-sidebar>nav>.sidebar-tools-main{margin-left:14px}.sidebar-tools-main{margin-left:0px}.sidebar-tools-main:not(.tools-wide){display:inline-block;vertical-align:middle}.sidebar-tools-main.tools-wide{padding-top:.3em}.sidebar-navigation .sidebar-tool.dropdown-toggle::after{display:none}.sidebar.sidebar-navigation>*{padding-top:1em}.sidebar-item{margin-bottom:.2em}.sidebar-section{margin-top:.2em;padding-left:.5em;padding-bottom:.2em}.sidebar-item .sidebar-item-container{display:flex;justify-content:space-between}.sidebar-item .sidebar-item-toggle .bi{font-size:.7rem;text-align:center}.sidebar-navigation .sidebar-divider{margin-left:0;margin-right:0;margin-top:.5rem;margin-bottom:.5rem}@media(max-width: 767.98px){.quarto-secondary-nav{display:block}}@media(min-width: 992px){.quarto-secondary-nav{display:none}}.quarto-secondary-nav .quarto-btn-toggle{color:#595959;padding-right:0}.quarto-secondary-nav[aria-expanded=false] .quarto-btn-toggle .bi-chevron-right::before{transform:none}.quarto-secondary-nav[aria-expanded=true] .quarto-btn-toggle .bi-chevron-right::before{transform:rotate(90deg)}.quarto-secondary-nav .quarto-btn-toggle .bi-chevron-right::before{transition:transform 200ms ease}.quarto-secondary-nav{cursor:pointer}.quarto-secondary-nav-title{margin-top:.3em;color:#595959;padding-top:4px}div.sidebar-item-container{color:#595959}div.sidebar-item-container:hover,div.sidebar-item-container:focus{color:rgba(27,88,157,.8)}div.sidebar-item-container.disabled{color:rgba(89,89,89,.75)}div.sidebar-item-container .active,div.sidebar-item-container .show>.nav-link,div.sidebar-item-container .sidebar-link>code{color:#1b589d}div.sidebar.sidebar-navigation.rollup.quarto-sidebar-toggle-contents,nav.sidebar.sidebar-navigation:not(.rollup){background-color:#fff}@media(max-width: 991.98px){.sidebar-navigation .sidebar-item a,.nav-page .nav-page-text,.sidebar-navigation{font-size:1rem}.sidebar-navigation ul.sidebar-section.depth1 .sidebar-section-item{font-size:1.1rem}.sidebar-logo{display:none}.sidebar.sidebar-navigation{position:static;border-bottom:1px solid #dee2e6}.sidebar.sidebar-navigation.collapsing{position:fixed;z-index:1000}.sidebar.sidebar-navigation.show{position:fixed;z-index:1000}.sidebar.sidebar-navigation{transition:height .15s linear;width:100%}nav.quarto-secondary-nav{background-color:#fff;border-bottom:1px solid #dee2e6}.sidebar .sidebar-footer{visibility:visible;padding-top:1rem;position:inherit}.sidebar-tools-collapse{display:block}}@media(min-width: 992px){#quarto-sidebar{display:flex;flex-direction:column}.nav-page .nav-page-text,.sidebar-navigation .sidebar-section .sidebar-item{font-size:.875rem}.sidebar-navigation .sidebar-item{font-size:.925rem}.sidebar.sidebar-navigation{display:block;position:sticky}.sidebar-search{width:100%}.sidebar .sidebar-footer{visibility:visible}}.sidebar .sidebar-footer{padding:.5rem 1rem;align-self:flex-end;color:#6c757d;width:100%}#quarto-sidebar{width:100%;padding-right:1em;color:#595959}.quarto-sidebar-footer{font-size:.875em}.sidebar-section .bi-chevron-right{vertical-align:middle}.sidebar-section a .bi-chevron-right::before{transform:rotate(90deg)}.sidebar-section a.collapsed .bi-chevron-right::before{transform:none}.sidebar-section .bi-chevron-right::before{font-size:.9em;transition:transform 200ms ease}.notransition{-webkit-transition:none !important;-moz-transition:none !important;-o-transition:none !important;transition:none !important}.btn:focus:not(:focus-visible){box-shadow:none}.page-navigation{display:flex;justify-content:space-between}.nav-page{padding-bottom:.75em}.nav-page .bi{font-size:1.8rem;vertical-align:middle}.nav-page .nav-page-text{padding-left:.25em;padding-right:.25em}.nav-page a{color:#6c757d;text-decoration:none;display:flex;align-items:center}.nav-page a:hover{color:#1f66b6}.toc-actions{display:flex}.toc-actions p{margin-block-start:0;margin-block-end:0}.toc-actions a{text-decoration:none;color:inherit;font-weight:400}.toc-actions a:hover{color:#1f66b6}.toc-actions .action-links{margin-left:4px}.sidebar nav[role=doc-toc] .toc-actions .bi{margin-left:-4px;font-size:.7rem;color:#6c757d}.sidebar nav[role=doc-toc] .toc-actions .bi:before{padding-top:3px}#quarto-margin-sidebar .toc-actions .bi:before{margin-top:.3rem;font-size:.7rem;color:#6c757d;vertical-align:top}.sidebar nav[role=doc-toc] .toc-actions>div:first-of-type{margin-top:-3px}#quarto-margin-sidebar .toc-actions p,.sidebar nav[role=doc-toc] .toc-actions p{font-size:.875rem}.nav-footer{display:flex;justify-content:center;align-items:center;text-align:center;padding-top:.5rem;padding-bottom:.5rem;background-color:#fff}body.nav-fixed{padding-top:66px}.nav-footer-contents{color:#6c757d;margin-top:.25rem}.nav-footer{min-height:3.5em;color:#757575}.nav-footer a{color:#757575}.nav-footer .nav-footer-left{font-size:.825em}.nav-footer .nav-footer-center{font-size:.825em}.nav-footer .nav-footer-right{font-size:.825em}.nav-footer-left .footer-items,.nav-footer-center .footer-items,.nav-footer-right .footer-items{display:flex;padding-top:.3em;padding-bottom:.3em;margin-bottom:0em}.nav-footer-left .footer-items .nav-link,.nav-footer-center .footer-items .nav-link,.nav-footer-right .footer-items .nav-link{padding-left:.6em;padding-right:.6em}.nav-footer-left{margin-right:auto}.nav-footer-center{min-height:3em;position:absolute;text-align:center}.nav-footer-center .footer-items{justify-content:center}@media(max-width: 767.98px){.nav-footer-center{margin-top:3em}}.nav-footer-right{margin-left:auto}.navbar .quarto-reader-toggle{padding-left:.4em;padding-right:0}.navbar .quarto-reader-toggle.reader .quarto-reader-toggle-btn{background-color:#fdfeff;border-radius:3px}.quarto-reader-toggle.reader.sidebar-tool .quarto-reader-toggle-btn{background-color:#595959;border-radius:3px}.quarto-reader-toggle.sidebar-tool{padding-left:.3em}.quarto-reader-toggle .quarto-reader-toggle-btn{display:inline-flex;padding-left:.1em;padding-right:.3em;text-align:center}.navbar .quarto-reader-toggle:not(.reader) .bi::before{background-image:url('data:image/svg+xml,')}.navbar .quarto-reader-toggle.reader .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-reader-toggle:not(.reader) .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-reader-toggle.reader .bi::before{background-image:url('data:image/svg+xml,')}.aa-DetachedOverlay ul.aa-List,#quarto-search-results ul.aa-List{list-style:none;padding-left:0}.aa-DetachedOverlay .aa-Panel,#quarto-search-results .aa-Panel{background-color:#fff;position:absolute;z-index:2000}#quarto-search-results .aa-Panel{max-width:400px}#quarto-search input{font-size:.925rem}@media(min-width: 992px){.navbar #quarto-search{margin-left:1rem}}#quarto-sidebar .sidebar-search .aa-Autocomplete{width:100%}.navbar .aa-Autocomplete .aa-Form{width:180px}.navbar #quarto-search.type-overlay .aa-Autocomplete{width:40px}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form{background-color:inherit;border:none}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form:focus-within{box-shadow:none;outline:none}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-InputWrapper{display:none}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-InputWrapper:focus-within{display:inherit}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-Label svg,.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-LoadingIndicator svg{width:26px;height:26px;color:#fdfeff;opacity:1}.navbar #quarto-search.type-overlay .aa-Autocomplete svg.aa-SubmitIcon{width:26px;height:26px;color:#fdfeff;opacity:1}.aa-Autocomplete .aa-Form,.aa-DetachedFormContainer .aa-Form{align-items:center;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem;color:#373a3c;display:flex;line-height:1em;margin:0;position:relative;width:100%}.aa-Autocomplete .aa-Form:focus-within,.aa-DetachedFormContainer .aa-Form:focus-within{box-shadow:rgba(39,128,227,.6) 0 0 0 1px;outline:currentColor none medium}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix{align-items:center;display:flex;flex-shrink:0;order:1}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-Label,.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-Label,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator{cursor:initial;flex-shrink:0;padding:0;text-align:left}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-Label svg,.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator svg,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-Label svg,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator svg{color:#373a3c;opacity:.5}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-SubmitButton,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-SubmitButton{appearance:none;background:none;border:0;margin:0}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator{align-items:center;display:flex;justify-content:center}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator[hidden],.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator[hidden]{display:none}.aa-Autocomplete .aa-Form .aa-InputWrapper,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper{order:3;position:relative;width:100%}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input{appearance:none;background:none;border:0;color:#373a3c;font:inherit;height:calc(1.5em + (0.1rem + 2px));padding:0;width:100%}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::placeholder,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::placeholder{color:#373a3c;opacity:.8}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input:focus,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input:focus{border-color:none;box-shadow:none;outline:none}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-decoration,.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-cancel-button,.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-button,.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-decoration,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-decoration,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-cancel-button,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-button,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-decoration{display:none}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix{align-items:center;display:flex;order:4}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton{align-items:center;background:none;border:0;color:#373a3c;opacity:.8;cursor:pointer;display:flex;margin:0;width:calc(1.5em + (0.1rem + 2px))}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:hover,.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:focus,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:hover,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:focus{color:#373a3c;opacity:.8}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton[hidden],.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton[hidden]{display:none}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton svg,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton svg{width:calc(1.5em + 0.75rem + 2px)}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton{border:none;align-items:center;background:none;color:#373a3c;opacity:.4;font-size:.7rem;cursor:pointer;display:none;margin:0;width:calc(1em + (0.1rem + 2px))}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:hover,.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:focus,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:hover,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:focus{color:#373a3c;opacity:.8}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton[hidden],.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton[hidden]{display:none}#quarto-search-results .aa-Panel{border:solid #ced4da 1px}#quarto-search-results .aa-SourceNoResults{width:398px}.aa-DetachedOverlay .aa-Panel,#quarto-search-results .aa-Panel{max-height:65vh;overflow-y:auto;font-size:.925rem}.aa-DetachedOverlay .aa-SourceNoResults,#quarto-search-results .aa-SourceNoResults{height:60px;display:flex;justify-content:center;align-items:center}.aa-DetachedOverlay .search-error,#quarto-search-results .search-error{padding-top:10px;padding-left:20px;padding-right:20px;cursor:default}.aa-DetachedOverlay .search-error .search-error-title,#quarto-search-results .search-error .search-error-title{font-size:1.1rem;margin-bottom:.5rem}.aa-DetachedOverlay .search-error .search-error-title .search-error-icon,#quarto-search-results .search-error .search-error-title .search-error-icon{margin-right:8px}.aa-DetachedOverlay .search-error .search-error-text,#quarto-search-results .search-error .search-error-text{font-weight:300}.aa-DetachedOverlay .search-result-text,#quarto-search-results .search-result-text{font-weight:300;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;line-height:1.2rem;max-height:2.4rem}.aa-DetachedOverlay .aa-SourceHeader .search-result-header,#quarto-search-results .aa-SourceHeader .search-result-header{font-size:.875rem;background-color:#f2f2f2;padding-left:14px;padding-bottom:4px;padding-top:4px}.aa-DetachedOverlay .aa-SourceHeader .search-result-header-no-results,#quarto-search-results .aa-SourceHeader .search-result-header-no-results{display:none}.aa-DetachedOverlay .aa-SourceFooter .algolia-search-logo,#quarto-search-results .aa-SourceFooter .algolia-search-logo{width:110px;opacity:.85;margin:8px;float:right}.aa-DetachedOverlay .search-result-section,#quarto-search-results .search-result-section{font-size:.925em}.aa-DetachedOverlay a.search-result-link,#quarto-search-results a.search-result-link{color:inherit;text-decoration:none}.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item,#quarto-search-results li.aa-Item[aria-selected=true] .search-item{background-color:#2780e3}.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item.search-result-more,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-section,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-text,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-title-container,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-text-container,#quarto-search-results li.aa-Item[aria-selected=true] .search-item.search-result-more,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-section,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-text,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-title-container,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-text-container{color:#fff;background-color:#2780e3}.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item mark.search-match,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-match.mark,#quarto-search-results li.aa-Item[aria-selected=true] .search-item mark.search-match,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-match.mark{color:#fff;background-color:#4b95e8}.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item,#quarto-search-results li.aa-Item[aria-selected=false] .search-item{background-color:#fff}.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item.search-result-more,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-section,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-text,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-title-container,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-text-container,#quarto-search-results li.aa-Item[aria-selected=false] .search-item.search-result-more,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-section,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-text,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-title-container,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-text-container{color:#373a3c}.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item mark.search-match,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-match.mark,#quarto-search-results li.aa-Item[aria-selected=false] .search-item mark.search-match,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-match.mark{color:inherit;background-color:#e5effc}.aa-DetachedOverlay .aa-Item .search-result-doc:not(.document-selectable) .search-result-title-container,#quarto-search-results .aa-Item .search-result-doc:not(.document-selectable) .search-result-title-container{background-color:#fff;color:#373a3c}.aa-DetachedOverlay .aa-Item .search-result-doc:not(.document-selectable) .search-result-text-container,#quarto-search-results .aa-Item .search-result-doc:not(.document-selectable) .search-result-text-container{padding-top:0px}.aa-DetachedOverlay li.aa-Item .search-result-doc.document-selectable .search-result-text-container,#quarto-search-results li.aa-Item .search-result-doc.document-selectable .search-result-text-container{margin-top:-4px}.aa-DetachedOverlay .aa-Item,#quarto-search-results .aa-Item{cursor:pointer}.aa-DetachedOverlay .aa-Item .search-item,#quarto-search-results .aa-Item .search-item{border-left:none;border-right:none;border-top:none;background-color:#fff;border-color:#ced4da;color:#373a3c}.aa-DetachedOverlay .aa-Item .search-item p,#quarto-search-results .aa-Item .search-item p{margin-top:0;margin-bottom:0}.aa-DetachedOverlay .aa-Item .search-item i.bi,#quarto-search-results .aa-Item .search-item i.bi{padding-left:8px;padding-right:8px;font-size:1.3em}.aa-DetachedOverlay .aa-Item .search-item .search-result-title,#quarto-search-results .aa-Item .search-item .search-result-title{margin-top:.3em;margin-bottom:.1rem}.aa-DetachedOverlay .aa-Item .search-result-title-container,#quarto-search-results .aa-Item .search-result-title-container{font-size:1em;display:flex;padding:6px 4px 6px 4px}.aa-DetachedOverlay .aa-Item .search-result-text-container,#quarto-search-results .aa-Item .search-result-text-container{padding-bottom:8px;padding-right:8px;margin-left:44px}.aa-DetachedOverlay .aa-Item .search-result-doc-section,.aa-DetachedOverlay .aa-Item .search-result-more,#quarto-search-results .aa-Item .search-result-doc-section,#quarto-search-results .aa-Item .search-result-more{padding-top:8px;padding-bottom:8px;padding-left:44px}.aa-DetachedOverlay .aa-Item .search-result-more,#quarto-search-results .aa-Item .search-result-more{font-size:.8em;font-weight:400}.aa-DetachedOverlay .aa-Item .search-result-doc,#quarto-search-results .aa-Item .search-result-doc{border-top:1px solid #ced4da}.aa-DetachedSearchButton{background:none;border:none}.aa-DetachedSearchButton .aa-DetachedSearchButtonPlaceholder{display:none}.navbar .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon{color:#fdfeff}.sidebar-tools-collapse #quarto-search,.sidebar-tools-main #quarto-search{display:inline}.sidebar-tools-collapse #quarto-search .aa-Autocomplete,.sidebar-tools-main #quarto-search .aa-Autocomplete{display:inline}.sidebar-tools-collapse #quarto-search .aa-DetachedSearchButton,.sidebar-tools-main #quarto-search .aa-DetachedSearchButton{padding-left:4px;padding-right:4px}.sidebar-tools-collapse #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon,.sidebar-tools-main #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon{color:#595959}.sidebar-tools-collapse #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon .aa-SubmitIcon,.sidebar-tools-main #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon .aa-SubmitIcon{margin-top:-3px}.aa-DetachedContainer{background:rgba(255,255,255,.65);width:90%;bottom:0;box-shadow:rgba(206,212,218,.6) 0 0 0 1px;outline:currentColor none medium;display:flex;flex-direction:column;left:0;margin:0;overflow:hidden;padding:0;position:fixed;right:0;top:0;z-index:1101}.aa-DetachedContainer::after{height:32px}.aa-DetachedContainer .aa-SourceHeader{margin:var(--aa-spacing-half) 0 var(--aa-spacing-half) 2px}.aa-DetachedContainer .aa-Panel{background-color:#fff;border-radius:0;box-shadow:none;flex-grow:1;margin:0;padding:0;position:relative}.aa-DetachedContainer .aa-PanelLayout{bottom:0;box-shadow:none;left:0;margin:0;max-height:none;overflow-y:auto;position:absolute;right:0;top:0;width:100%}.aa-DetachedFormContainer{background-color:#fff;border-bottom:1px solid #ced4da;display:flex;flex-direction:row;justify-content:space-between;margin:0;padding:.5em}.aa-DetachedCancelButton{background:none;font-size:.8em;border:0;border-radius:3px;color:#373a3c;cursor:pointer;margin:0 0 0 .5em;padding:0 .5em}.aa-DetachedCancelButton:hover,.aa-DetachedCancelButton:focus{box-shadow:rgba(39,128,227,.6) 0 0 0 1px;outline:currentColor none medium}.aa-DetachedContainer--modal{border-radius:6px;bottom:inherit;height:auto;margin:0 auto;max-width:850px;position:absolute;top:100px}.aa-DetachedContainer--modal .aa-PanelLayout{max-height:var(--aa-detached-modal-max-height);padding-bottom:var(--aa-spacing-half);position:static}.aa-Detached{height:100vh;overflow:hidden}.aa-DetachedOverlay{background-color:rgba(55,58,60,.4);position:fixed;left:0;right:0;top:0;margin:0;padding:0;height:100vh;z-index:1100}.quarto-listing{padding-bottom:1em}.listing-pagination{padding-top:.5em}ul.pagination{float:right;padding-left:8px;padding-top:.5em}ul.pagination li{padding-right:.75em}ul.pagination li.disabled a,ul.pagination li.active a{color:#373a3c;text-decoration:none}ul.pagination li:last-of-type{padding-right:0}.listing-actions-group{display:flex}.quarto-listing-filter{margin-bottom:1em;width:200px;margin-left:auto}.quarto-listing-sort{margin-bottom:1em;margin-right:auto;width:auto}.quarto-listing-sort .input-group-text{font-size:.8em}.input-group-text{border-right:none}.quarto-listing-sort select.form-select{font-size:.8em}.listing-no-matching{text-align:center;padding-top:2em;padding-bottom:3em;font-size:1em}#quarto-margin-sidebar .quarto-listing-category{padding-top:0;font-size:1rem}#quarto-margin-sidebar .quarto-listing-category-title{cursor:pointer;font-weight:600;font-size:1rem}.quarto-listing-category .category{cursor:pointer}.quarto-listing-category .category.active{font-weight:600}.quarto-listing-category.category-cloud{display:flex;flex-wrap:wrap;align-items:baseline}.quarto-listing-category.category-cloud .category{padding-right:5px}.quarto-listing-category.category-cloud .category-cloud-1{font-size:.75em}.quarto-listing-category.category-cloud .category-cloud-2{font-size:.95em}.quarto-listing-category.category-cloud .category-cloud-3{font-size:1.15em}.quarto-listing-category.category-cloud .category-cloud-4{font-size:1.35em}.quarto-listing-category.category-cloud .category-cloud-5{font-size:1.55em}.quarto-listing-category.category-cloud .category-cloud-6{font-size:1.75em}.quarto-listing-category.category-cloud .category-cloud-7{font-size:1.95em}.quarto-listing-category.category-cloud .category-cloud-8{font-size:2.15em}.quarto-listing-category.category-cloud .category-cloud-9{font-size:2.35em}.quarto-listing-category.category-cloud .category-cloud-10{font-size:2.55em}.quarto-listing-cols-1{grid-template-columns:repeat(1, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-1{grid-template-columns:repeat(1, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-1{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-2{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-2{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-2{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-3{grid-template-columns:repeat(3, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-3{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-3{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-4{grid-template-columns:repeat(4, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-4{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-4{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-5{grid-template-columns:repeat(5, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-5{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-5{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-6{grid-template-columns:repeat(6, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-6{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-6{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-7{grid-template-columns:repeat(7, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-7{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-7{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-8{grid-template-columns:repeat(8, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-8{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-8{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-9{grid-template-columns:repeat(9, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-9{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-9{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-10{grid-template-columns:repeat(10, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-10{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-10{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-11{grid-template-columns:repeat(11, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-11{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-11{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-12{grid-template-columns:repeat(12, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-12{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-12{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-grid{gap:1.5em}.quarto-grid-item.borderless{border:none}.quarto-grid-item.borderless .listing-categories .listing-category:last-of-type,.quarto-grid-item.borderless .listing-categories .listing-category:first-of-type{padding-left:0}.quarto-grid-item.borderless .listing-categories .listing-category{border:0}.quarto-grid-link{text-decoration:none;color:inherit}.quarto-grid-link:hover{text-decoration:none;color:inherit}.quarto-grid-item h5.title,.quarto-grid-item .title.h5{margin-top:0;margin-bottom:0}.quarto-grid-item .card-footer{display:flex;justify-content:space-between;font-size:.8em}.quarto-grid-item .card-footer p{margin-bottom:0}.quarto-grid-item p.card-img-top{margin-bottom:0}.quarto-grid-item img.thumbnail-image{object-fit:cover}.quarto-grid-item .card-other-values{margin-top:.5em;font-size:.8em}.quarto-grid-item .card-other-values tr{margin-bottom:.5em}.quarto-grid-item .card-other-values tr>td:first-of-type{font-weight:600;padding-right:1em;padding-left:1em;vertical-align:top}.quarto-grid-item div.post-contents{display:flex;flex-direction:column;text-decoration:none;height:100%}.quarto-grid-item div.card-img-bg{background-color:#adb5bd;flex-shrink:0}.quarto-grid-item .card-attribution{padding-top:1em;display:flex;gap:1em;text-transform:uppercase;color:#6c757d;font-weight:500;flex-grow:10;align-items:flex-end}.quarto-grid-item .description{padding-bottom:1em}.quarto-grid-item .card-attribution .date{align-self:flex-end}.quarto-grid-item .card-attribution.justify{justify-content:space-between}.quarto-grid-item .card-attribution.start{justify-content:flex-start}.quarto-grid-item .card-attribution.end{justify-content:flex-end}.quarto-grid-item .card-title{margin-bottom:.1em}.quarto-grid-item .card-subtitle{padding-top:.25em}.quarto-grid-item .card-text{font-size:.9em}.quarto-grid-item .listing-reading-time{padding-bottom:.25em}.quarto-grid-item .card-text-small{font-size:.8em}.quarto-grid-item .card-subtitle.subtitle{font-size:.9em;font-weight:600;padding-bottom:.5em}.quarto-grid-item .listing-categories{display:flex;flex-wrap:wrap;padding-bottom:5px}.quarto-grid-item .listing-categories .listing-category{color:#6c757d;border:solid 1px #dee2e6;border-radius:.25rem;text-transform:uppercase;font-size:.65em;padding-left:.5em;padding-right:.5em;padding-top:.15em;padding-bottom:.15em;cursor:pointer;margin-right:4px;margin-bottom:4px}.quarto-grid-item.card-right{text-align:right}.quarto-grid-item.card-right .listing-categories{justify-content:flex-end}.quarto-grid-item.card-left{text-align:left}.quarto-grid-item.card-center{text-align:center}.quarto-grid-item.card-center .listing-description{text-align:justify}.quarto-grid-item.card-center .listing-categories{justify-content:center}table.quarto-listing-table td.image{padding:0px}table.quarto-listing-table td.image img{width:100%;max-width:50px;object-fit:contain}table.quarto-listing-table a{text-decoration:none}table.quarto-listing-table th a{color:inherit}table.quarto-listing-table th a.asc:after{margin-bottom:-2px;margin-left:5px;display:inline-block;height:1rem;width:1rem;background-repeat:no-repeat;background-size:1rem 1rem;background-image:url('data:image/svg+xml,');content:""}table.quarto-listing-table th a.desc:after{margin-bottom:-2px;margin-left:5px;display:inline-block;height:1rem;width:1rem;background-repeat:no-repeat;background-size:1rem 1rem;background-image:url('data:image/svg+xml,');content:""}table.quarto-listing-table.table-hover td{cursor:pointer}.quarto-post.image-left{flex-direction:row}.quarto-post.image-right{flex-direction:row-reverse}@media(max-width: 767.98px){.quarto-post.image-right,.quarto-post.image-left{gap:0em;flex-direction:column}.quarto-post .metadata{padding-bottom:1em;order:2}.quarto-post .body{order:1}.quarto-post .thumbnail{order:3}}.list.quarto-listing-default div:last-of-type{border-bottom:none}@media(min-width: 992px){.quarto-listing-container-default{margin-right:2em}}div.quarto-post{display:flex;gap:2em;margin-bottom:1.5em;border-bottom:1px solid #dee2e6}@media(max-width: 767.98px){div.quarto-post{padding-bottom:1em}}div.quarto-post .metadata{flex-basis:20%;flex-grow:0;margin-top:.2em;flex-shrink:10}div.quarto-post .thumbnail{flex-basis:30%;flex-grow:0;flex-shrink:0}div.quarto-post .thumbnail img{margin-top:.4em;width:100%;object-fit:cover}div.quarto-post .body{flex-basis:45%;flex-grow:1;flex-shrink:0}div.quarto-post .body h3.listing-title,div.quarto-post .body .listing-title.h3{margin-top:0px;margin-bottom:0px;border-bottom:none}div.quarto-post .body .listing-subtitle{font-size:.875em;margin-bottom:.5em;margin-top:.2em}div.quarto-post .body .description{font-size:.9em}div.quarto-post a{color:#373a3c;display:flex;flex-direction:column;text-decoration:none}div.quarto-post a div.description{flex-shrink:0}div.quarto-post .metadata{display:flex;flex-direction:column;font-size:.8em;font-family:var(--bs-font-sans-serif);flex-basis:33%}div.quarto-post .listing-categories{display:flex;flex-wrap:wrap;padding-bottom:5px}div.quarto-post .listing-categories .listing-category{color:#6c757d;border:solid 1px #dee2e6;border-radius:.25rem;text-transform:uppercase;font-size:.65em;padding-left:.5em;padding-right:.5em;padding-top:.15em;padding-bottom:.15em;cursor:pointer;margin-right:4px;margin-bottom:4px}div.quarto-post .listing-description{margin-bottom:.5em}div.quarto-about-jolla{display:flex !important;flex-direction:column;align-items:center;margin-top:10%;padding-bottom:1em}div.quarto-about-jolla .about-image{object-fit:cover;margin-left:auto;margin-right:auto;margin-bottom:1.5em}div.quarto-about-jolla img.round{border-radius:50%}div.quarto-about-jolla img.rounded{border-radius:10px}div.quarto-about-jolla .quarto-title h1.title,div.quarto-about-jolla .quarto-title .title.h1{text-align:center}div.quarto-about-jolla .quarto-title .description{text-align:center}div.quarto-about-jolla h2,div.quarto-about-jolla .h2{border-bottom:none}div.quarto-about-jolla .about-sep{width:60%}div.quarto-about-jolla main{text-align:center}div.quarto-about-jolla .about-links{display:flex}@media(min-width: 992px){div.quarto-about-jolla .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-jolla .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-jolla .about-link{color:#686d71;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-jolla .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-jolla .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-jolla .about-link:hover{color:#2780e3}div.quarto-about-jolla .about-link i.bi{margin-right:.15em}div.quarto-about-solana{display:flex !important;flex-direction:column;padding-top:3em !important;padding-bottom:1em}div.quarto-about-solana .about-entity{display:flex !important;align-items:start;justify-content:space-between}@media(min-width: 992px){div.quarto-about-solana .about-entity{flex-direction:row}}@media(max-width: 991.98px){div.quarto-about-solana .about-entity{flex-direction:column-reverse;align-items:center;text-align:center}}div.quarto-about-solana .about-entity .entity-contents{display:flex;flex-direction:column}@media(max-width: 767.98px){div.quarto-about-solana .about-entity .entity-contents{width:100%}}div.quarto-about-solana .about-entity .about-image{object-fit:cover}@media(max-width: 991.98px){div.quarto-about-solana .about-entity .about-image{margin-bottom:1.5em}}div.quarto-about-solana .about-entity img.round{border-radius:50%}div.quarto-about-solana .about-entity img.rounded{border-radius:10px}div.quarto-about-solana .about-entity .about-links{display:flex;justify-content:left;padding-bottom:1.2em}@media(min-width: 992px){div.quarto-about-solana .about-entity .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-solana .about-entity .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-solana .about-entity .about-link{color:#686d71;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-solana .about-entity .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-solana .about-entity .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-solana .about-entity .about-link:hover{color:#2780e3}div.quarto-about-solana .about-entity .about-link i.bi{margin-right:.15em}div.quarto-about-solana .about-contents{padding-right:1.5em;flex-basis:0;flex-grow:1}div.quarto-about-solana .about-contents main.content{margin-top:0}div.quarto-about-solana .about-contents h2,div.quarto-about-solana .about-contents .h2{border-bottom:none}div.quarto-about-trestles{display:flex !important;flex-direction:row;padding-top:3em !important;padding-bottom:1em}@media(max-width: 991.98px){div.quarto-about-trestles{flex-direction:column;padding-top:0em !important}}div.quarto-about-trestles .about-entity{display:flex !important;flex-direction:column;align-items:center;text-align:center;padding-right:1em}@media(min-width: 992px){div.quarto-about-trestles .about-entity{flex:0 0 42%}}div.quarto-about-trestles .about-entity .about-image{object-fit:cover;margin-bottom:1.5em}div.quarto-about-trestles .about-entity img.round{border-radius:50%}div.quarto-about-trestles .about-entity img.rounded{border-radius:10px}div.quarto-about-trestles .about-entity .about-links{display:flex;justify-content:center}@media(min-width: 992px){div.quarto-about-trestles .about-entity .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-trestles .about-entity .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-trestles .about-entity .about-link{color:#686d71;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-trestles .about-entity .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-trestles .about-entity .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-trestles .about-entity .about-link:hover{color:#2780e3}div.quarto-about-trestles .about-entity .about-link i.bi{margin-right:.15em}div.quarto-about-trestles .about-contents{flex-basis:0;flex-grow:1}div.quarto-about-trestles .about-contents h2,div.quarto-about-trestles .about-contents .h2{border-bottom:none}@media(min-width: 992px){div.quarto-about-trestles .about-contents{border-left:solid 1px #dee2e6;padding-left:1.5em}}div.quarto-about-trestles .about-contents main.content{margin-top:0}div.quarto-about-marquee{padding-bottom:1em}div.quarto-about-marquee .about-contents{display:flex;flex-direction:column}div.quarto-about-marquee .about-image{max-height:550px;margin-bottom:1.5em;object-fit:cover}div.quarto-about-marquee img.round{border-radius:50%}div.quarto-about-marquee img.rounded{border-radius:10px}div.quarto-about-marquee h2,div.quarto-about-marquee .h2{border-bottom:none}div.quarto-about-marquee .about-links{display:flex;justify-content:center;padding-top:1.5em}@media(min-width: 992px){div.quarto-about-marquee .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-marquee .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-marquee .about-link{color:#686d71;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-marquee .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-marquee .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-marquee .about-link:hover{color:#2780e3}div.quarto-about-marquee .about-link i.bi{margin-right:.15em}@media(min-width: 992px){div.quarto-about-marquee .about-link{border:none}}div.quarto-about-broadside{display:flex;flex-direction:column;padding-bottom:1em}div.quarto-about-broadside .about-main{display:flex !important;padding-top:0 !important}@media(min-width: 992px){div.quarto-about-broadside .about-main{flex-direction:row;align-items:flex-start}}@media(max-width: 991.98px){div.quarto-about-broadside .about-main{flex-direction:column}}@media(max-width: 991.98px){div.quarto-about-broadside .about-main .about-entity{flex-shrink:0;width:100%;height:450px;margin-bottom:1.5em;background-size:cover;background-repeat:no-repeat}}@media(min-width: 992px){div.quarto-about-broadside .about-main .about-entity{flex:0 10 50%;margin-right:1.5em;width:100%;height:100%;background-size:100%;background-repeat:no-repeat}}div.quarto-about-broadside .about-main .about-contents{padding-top:14px;flex:0 0 50%}div.quarto-about-broadside h2,div.quarto-about-broadside .h2{border-bottom:none}div.quarto-about-broadside .about-sep{margin-top:1.5em;width:60%;align-self:center}div.quarto-about-broadside .about-links{display:flex;justify-content:center;column-gap:20px;padding-top:1.5em}@media(min-width: 992px){div.quarto-about-broadside .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-broadside .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-broadside .about-link{color:#686d71;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-broadside .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-broadside .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-broadside .about-link:hover{color:#2780e3}div.quarto-about-broadside .about-link i.bi{margin-right:.15em}@media(min-width: 992px){div.quarto-about-broadside .about-link{border:none}}.tippy-box[data-theme~=quarto]{background-color:#fff;color:#373a3c;border-radius:.25rem;border:solid 1px #dee2e6;font-size:.875rem}.tippy-box[data-theme~=quarto] .tippy-arrow{color:#dee2e6}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:-1px}.tippy-box[data-placement^=bottom]>.tippy-content{padding:.75em 1em;z-index:1}.top-right{position:absolute;top:1em;right:1em}.hidden{display:none !important}.quarto-layout-panel{margin-bottom:1em}.quarto-layout-panel>figure{width:100%}.quarto-layout-panel>figure>figcaption,.quarto-layout-panel>.panel-caption{margin-top:10pt}.quarto-layout-panel>.table-caption{margin-top:0px}.table-caption p{margin-bottom:.5em}.quarto-layout-row{display:flex;flex-direction:row;align-items:flex-start}.quarto-layout-valign-top{align-items:flex-start}.quarto-layout-valign-bottom{align-items:flex-end}.quarto-layout-valign-center{align-items:center}.quarto-layout-cell{position:relative;margin-right:20px}.quarto-layout-cell:last-child{margin-right:0}.quarto-layout-cell figure,.quarto-layout-cell>p{margin:.2em}.quarto-layout-cell img{max-width:100%}.quarto-layout-cell .html-widget{width:100% !important}.quarto-layout-cell div figure p{margin:0}.quarto-layout-cell figure{display:inline-block;margin-inline-start:0;margin-inline-end:0}.quarto-layout-cell table{display:inline-table}.quarto-layout-cell-subref figcaption,figure .quarto-layout-row figure figcaption{text-align:center;font-style:italic}.quarto-figure{position:relative;margin-bottom:1em}.quarto-figure>figure{width:100%;margin-bottom:0}.quarto-figure-left>figure>p{text-align:left}.quarto-figure-center>figure>p{text-align:center}.quarto-figure-right>figure>p{text-align:right}figure>p:empty{display:none}figure>p:first-child{margin-top:0;margin-bottom:0}figure>figcaption{margin-top:.5em}div[id^=tbl-]{position:relative}.quarto-figure>.anchorjs-link,div[id^=tbl-]>.anchorjs-link{position:absolute;top:0;right:0}.quarto-figure:hover>.anchorjs-link,div[id^=tbl-]:hover>.anchorjs-link,h2:hover>.anchorjs-link,.h2:hover>.anchorjs-link,h3:hover>.anchorjs-link,.h3:hover>.anchorjs-link,h4:hover>.anchorjs-link,.h4:hover>.anchorjs-link,h5:hover>.anchorjs-link,.h5:hover>.anchorjs-link,h6:hover>.anchorjs-link,.h6:hover>.anchorjs-link,.reveal-anchorjs-link>.anchorjs-link{opacity:1}#title-block-header{margin-block-end:1rem;position:relative;margin-top:-1px}#title-block-header .abstract{margin-block-start:1rem}#title-block-header .abstract .abstract-title{font-weight:600}#title-block-header a{text-decoration:none}#title-block-header .author,#title-block-header .date,#title-block-header .doi{margin-block-end:.2rem}#title-block-header .quarto-title-block>div{display:flex}#title-block-header .quarto-title-block>div>h1,#title-block-header .quarto-title-block>div>.h1{flex-grow:1}#title-block-header .quarto-title-block>div>button{flex-shrink:0;height:2.25rem;margin-top:0}@media(min-width: 992px){#title-block-header .quarto-title-block>div>button{margin-top:5px}}tr.header>th>p:last-of-type{margin-bottom:0px}table,.table{caption-side:top;margin-bottom:1.5rem}caption,.table-caption{padding-top:.5rem;padding-bottom:.5rem;text-align:center}.utterances{max-width:none;margin-left:-8px}iframe{margin-bottom:1em}details{margin-bottom:1em}details[show]{margin-bottom:0}details>summary{color:#6c757d}details>summary>p:only-child{display:inline}pre.sourceCode,code.sourceCode{position:relative}code{white-space:pre}@media print{code{white-space:pre-wrap}}pre>code{display:block}pre>code.sourceCode{white-space:pre}pre>code.sourceCode>span>a:first-child::before{text-decoration:none}pre.code-overflow-wrap>code.sourceCode{white-space:pre-wrap}pre.code-overflow-scroll>code.sourceCode{white-space:pre}code a:any-link{color:inherit;text-decoration:none}code a:hover{color:inherit;text-decoration:underline}ul.task-list{padding-left:1em}[data-tippy-root]{display:inline-block}.tippy-content .footnote-back{display:none}.quarto-embedded-source-code{display:none}.quarto-unresolved-ref{font-weight:600}.quarto-cover-image{max-width:35%;float:right;margin-left:30px}.cell-output-display .widget-subarea{margin-bottom:1em}.cell-output-display:not(.no-overflow-x){overflow-x:auto}.panel-input{margin-bottom:1em}.panel-input>div,.panel-input>div>div{display:inline-block;vertical-align:top;padding-right:12px}.panel-input>p:last-child{margin-bottom:0}.layout-sidebar{margin-bottom:1em}.layout-sidebar .tab-content{border:none}.tab-content>.page-columns.active{display:grid}div.sourceCode>iframe{width:100%;height:300px;margin-bottom:-0.5em}div.ansi-escaped-output{font-family:monospace;display:block}/*! -* -* ansi colors from IPython notebook's -* -*/.ansi-black-fg{color:#3e424d}.ansi-black-bg{background-color:#3e424d}.ansi-black-intense-fg{color:#282c36}.ansi-black-intense-bg{background-color:#282c36}.ansi-red-fg{color:#e75c58}.ansi-red-bg{background-color:#e75c58}.ansi-red-intense-fg{color:#b22b31}.ansi-red-intense-bg{background-color:#b22b31}.ansi-green-fg{color:#00a250}.ansi-green-bg{background-color:#00a250}.ansi-green-intense-fg{color:#007427}.ansi-green-intense-bg{background-color:#007427}.ansi-yellow-fg{color:#ddb62b}.ansi-yellow-bg{background-color:#ddb62b}.ansi-yellow-intense-fg{color:#b27d12}.ansi-yellow-intense-bg{background-color:#b27d12}.ansi-blue-fg{color:#208ffb}.ansi-blue-bg{background-color:#208ffb}.ansi-blue-intense-fg{color:#0065ca}.ansi-blue-intense-bg{background-color:#0065ca}.ansi-magenta-fg{color:#d160c4}.ansi-magenta-bg{background-color:#d160c4}.ansi-magenta-intense-fg{color:#a03196}.ansi-magenta-intense-bg{background-color:#a03196}.ansi-cyan-fg{color:#60c6c8}.ansi-cyan-bg{background-color:#60c6c8}.ansi-cyan-intense-fg{color:#258f8f}.ansi-cyan-intense-bg{background-color:#258f8f}.ansi-white-fg{color:#c5c1b4}.ansi-white-bg{background-color:#c5c1b4}.ansi-white-intense-fg{color:#a1a6b2}.ansi-white-intense-bg{background-color:#a1a6b2}.ansi-default-inverse-fg{color:#fff}.ansi-default-inverse-bg{background-color:#000}.ansi-bold{font-weight:bold}.ansi-underline{text-decoration:underline}:root{--quarto-body-bg: #fff;--quarto-body-color: #373a3c;--quarto-text-muted: #6c757d;--quarto-border-color: #dee2e6;--quarto-border-width: 1px;--quarto-border-radius: 0.25rem}table.gt_table{color:var(--quarto-body-color);font-size:1em;width:100%;background-color:transparent;border-top-width:inherit;border-bottom-width:inherit;border-color:var(--quarto-border-color)}table.gt_table th.gt_col_heading{color:var(--quarto-body-color);font-weight:bold;background-color:transparent}table.gt_table thead.gt_col_headings{border-bottom:1px solid currentColor;border-top-width:inherit;border-top-color:var(--quarto-border-color)}table.gt_table thead.gt_col_headings:not(:first-child){border-top-width:1px;border-top-color:var(--quarto-border-color)}table.gt_table td.gt_row{border-bottom-width:1px;border-bottom-color:var(--quarto-border-color);border-top-width:0px}table.gt_table tbody.gt_table_body{border-top-width:1px;border-bottom-width:1px;border-bottom-color:var(--quarto-border-color);border-top-color:currentColor}div.columns{display:initial;gap:initial}div.column{display:inline-block;overflow-x:initial;vertical-align:top;width:50%}@media print{:root{font-size:11pt}#quarto-sidebar,#TOC,.nav-page{display:none}.page-columns .content{grid-column-start:page-start}.fixed-top{position:relative}.panel-caption,.figure-caption,figcaption{color:#666}}.code-copy-button{position:absolute;top:0;right:0;border:0;margin-top:5px;margin-right:5px;background-color:transparent}.code-copy-button:focus{outline:none}pre.sourceCode:hover>.code-copy-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:1rem 1rem}pre.sourceCode:hover>.code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,')}pre.sourceCode:hover>.code-copy-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}pre.sourceCode:hover>.code-copy-button-checked:hover>.bi::before{background-image:url('data:image/svg+xml,')}main ol ol,main ul ul,main ol ul,main ul ol{margin-bottom:1em}body{margin:0}main.page-columns>header>h1.title,main.page-columns>header>.title.h1{margin-bottom:0}@media(min-width: 992px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] 35px [page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1200px - 3em)) [body-content-end] 3em [body-end] 50px [body-end-outset] minmax(0px, 250px) [page-end-inset] 50px [page-end] 1fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 175px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 175px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] minmax(25px, 50px) [body-end-outset] minmax(50px, 150px) [page-end-inset] minmax(25px, 50px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc( 1000px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 100px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc( 1000px - 3em )) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 50px [page-start-inset] minmax(50px, 150px) [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc( 1000px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 100px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 50px [page-start-inset] minmax(50px, 150px) [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(50px, 150px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] minmax(25px, 50px) [body-end-outset] minmax(50px, 150px) [page-end-inset] minmax(25px, 50px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}}@media(max-width: 991.98px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(1200px - 3em)) [body-content-end body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 145px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 145px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(75px, 150px) [page-end-inset] 25px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc( 1000px - 3em )) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 4fr [screen-end-inset] 1.5em [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(75px, 150px) [page-end-inset] 25px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}}@media(max-width: 767.98px){body .page-columns,body.fullcontent:not(.floating):not(.docked) .page-columns,body.slimcontent:not(.floating):not(.docked) .page-columns,body.docked .page-columns,body.docked.slimcontent .page-columns,body.docked.fullcontent .page-columns,body.floating .page-columns,body.floating.slimcontent .page-columns,body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}nav[role=doc-toc]{display:none}}body,.page-row-navigation{grid-template-rows:[page-top] max-content [contents-top] max-content [contents-bottom] max-content [page-bottom]}.page-rows-contents{grid-template-rows:[content-top] minmax(max-content, 1fr) [content-bottom] minmax(60px, max-content) [page-bottom]}.page-full{grid-column:screen-start/screen-end !important}.page-columns>*{grid-column:body-content-start/body-content-end}.page-columns.column-page>*{grid-column:page-start/page-end}.page-columns.column-page-left>*{grid-column:page-start/body-content-end}.page-columns.column-page-right>*{grid-column:body-content-start/page-end}.page-rows{grid-auto-rows:auto}.header{grid-column:screen-start/screen-end;grid-row:page-top/contents-top}#quarto-content{padding:0;grid-column:screen-start/screen-end;grid-row:contents-top/contents-bottom}body.floating .sidebar.sidebar-navigation{grid-column:page-start/body-start;grid-row:content-top/page-bottom}body.docked .sidebar.sidebar-navigation{grid-column:screen-start/body-start;grid-row:content-top/page-bottom}.sidebar.toc-left{grid-column:page-start/body-start;grid-row:content-top/page-bottom}.sidebar.margin-sidebar{grid-column:body-end/page-end;grid-row:content-top/page-bottom}.page-columns .content{grid-column:body-content-start/body-content-end;grid-row:content-top/content-bottom;align-content:flex-start}.page-columns .page-navigation{grid-column:body-content-start/body-content-end;grid-row:content-bottom/page-bottom}.page-columns .footer{grid-column:screen-start/screen-end;grid-row:contents-bottom/page-bottom}.page-columns .column-body{grid-column:body-content-start/body-content-end}.page-columns .column-body-fullbleed{grid-column:body-start/body-end}.page-columns .column-body-outset{grid-column:body-start-outset/body-end-outset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-body-outset table{background:#fff}.page-columns .column-body-outset-left{grid-column:body-start-outset/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-body-outset-left table{background:#fff}.page-columns .column-body-outset-right{grid-column:body-content-start/body-end-outset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-body-outset-right table{background:#fff}.page-columns .column-page{grid-column:page-start/page-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page table{background:#fff}.page-columns .column-page-inset{grid-column:page-start-inset/page-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-inset table{background:#fff}.page-columns .column-page-inset-left{grid-column:page-start-inset/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-inset-left table{background:#fff}.page-columns .column-page-inset-right{grid-column:body-content-start/page-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-inset-right figcaption table{background:#fff}.page-columns .column-page-left{grid-column:page-start/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-left table{background:#fff}.page-columns .column-page-right{grid-column:body-content-start/page-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-right figcaption table{background:#fff}#quarto-content.page-columns #quarto-margin-sidebar,#quarto-content.page-columns #quarto-sidebar{z-index:1}@media(max-width: 991.98px){#quarto-content.page-columns #quarto-margin-sidebar.collapse,#quarto-content.page-columns #quarto-sidebar.collapse{z-index:1055}}#quarto-content.page-columns main.column-page,#quarto-content.page-columns main.column-page-right,#quarto-content.page-columns main.column-page-left{z-index:0}.page-columns .column-screen-inset{grid-column:screen-start-inset/screen-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset table{background:#fff}.page-columns .column-screen-inset-left{grid-column:screen-start-inset/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset-left table{background:#fff}.page-columns .column-screen-inset-right{grid-column:body-content-start/screen-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:screen-start/screen-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:screen-start/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/screen-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-right table{background:#fff}.page-columns .column-screen-inset-shaded{grid-column:screen-start/screen-end;padding:1em;background:#f8f9fa;z-index:998;transform:translate3d(0, 0, 0);margin-bottom:1em}.zindex-content{z-index:998;transform:translate3d(0, 0, 0)}.zindex-modal{z-index:1055;transform:translate3d(0, 0, 0)}.zindex-over-content{z-index:999;transform:translate3d(0, 0, 0)}img.img-fluid.column-screen,img.img-fluid.column-screen-inset-shaded,img.img-fluid.column-screen-inset,img.img-fluid.column-screen-inset-left,img.img-fluid.column-screen-inset-right,img.img-fluid.column-screen-left,img.img-fluid.column-screen-right{width:100%}@media(min-width: 992px){.margin-caption,div.aside,aside,.column-margin{grid-column:body-end/page-end !important;z-index:998}.column-sidebar{grid-column:page-start/body-start !important;z-index:998}.column-leftmargin{grid-column:screen-start-inset/body-start !important;z-index:998}.no-row-height{height:1em;overflow:visible}}@media(max-width: 991.98px){.margin-caption,div.aside,aside,.column-margin{grid-column:body-end/page-end !important;z-index:998}.no-row-height{height:1em;overflow:visible}.page-columns.page-full{overflow:visible}.page-columns.toc-left .margin-caption,.page-columns.toc-left div.aside,.page-columns.toc-left aside,.page-columns.toc-left .column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;transform:translate3d(0, 0, 0)}.page-columns.toc-left .no-row-height{height:initial;overflow:initial}}@media(max-width: 767.98px){.margin-caption,div.aside,aside,.column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;transform:translate3d(0, 0, 0)}.no-row-height{height:initial;overflow:initial}#quarto-margin-sidebar{display:none}.hidden-sm{display:none}}.panel-grid{display:grid;grid-template-rows:repeat(1, 1fr);grid-template-columns:repeat(24, 1fr);gap:1em}.panel-grid .g-col-1{grid-column:auto/span 1}.panel-grid .g-col-2{grid-column:auto/span 2}.panel-grid .g-col-3{grid-column:auto/span 3}.panel-grid .g-col-4{grid-column:auto/span 4}.panel-grid .g-col-5{grid-column:auto/span 5}.panel-grid .g-col-6{grid-column:auto/span 6}.panel-grid .g-col-7{grid-column:auto/span 7}.panel-grid .g-col-8{grid-column:auto/span 8}.panel-grid .g-col-9{grid-column:auto/span 9}.panel-grid .g-col-10{grid-column:auto/span 10}.panel-grid .g-col-11{grid-column:auto/span 11}.panel-grid .g-col-12{grid-column:auto/span 12}.panel-grid .g-col-13{grid-column:auto/span 13}.panel-grid .g-col-14{grid-column:auto/span 14}.panel-grid .g-col-15{grid-column:auto/span 15}.panel-grid .g-col-16{grid-column:auto/span 16}.panel-grid .g-col-17{grid-column:auto/span 17}.panel-grid .g-col-18{grid-column:auto/span 18}.panel-grid .g-col-19{grid-column:auto/span 19}.panel-grid .g-col-20{grid-column:auto/span 20}.panel-grid .g-col-21{grid-column:auto/span 21}.panel-grid .g-col-22{grid-column:auto/span 22}.panel-grid .g-col-23{grid-column:auto/span 23}.panel-grid .g-col-24{grid-column:auto/span 24}.panel-grid .g-start-1{grid-column-start:1}.panel-grid .g-start-2{grid-column-start:2}.panel-grid .g-start-3{grid-column-start:3}.panel-grid .g-start-4{grid-column-start:4}.panel-grid .g-start-5{grid-column-start:5}.panel-grid .g-start-6{grid-column-start:6}.panel-grid .g-start-7{grid-column-start:7}.panel-grid .g-start-8{grid-column-start:8}.panel-grid .g-start-9{grid-column-start:9}.panel-grid .g-start-10{grid-column-start:10}.panel-grid .g-start-11{grid-column-start:11}.panel-grid .g-start-12{grid-column-start:12}.panel-grid .g-start-13{grid-column-start:13}.panel-grid .g-start-14{grid-column-start:14}.panel-grid .g-start-15{grid-column-start:15}.panel-grid .g-start-16{grid-column-start:16}.panel-grid .g-start-17{grid-column-start:17}.panel-grid .g-start-18{grid-column-start:18}.panel-grid .g-start-19{grid-column-start:19}.panel-grid .g-start-20{grid-column-start:20}.panel-grid .g-start-21{grid-column-start:21}.panel-grid .g-start-22{grid-column-start:22}.panel-grid .g-start-23{grid-column-start:23}@media(min-width: 576px){.panel-grid .g-col-sm-1{grid-column:auto/span 1}.panel-grid .g-col-sm-2{grid-column:auto/span 2}.panel-grid .g-col-sm-3{grid-column:auto/span 3}.panel-grid .g-col-sm-4{grid-column:auto/span 4}.panel-grid .g-col-sm-5{grid-column:auto/span 5}.panel-grid .g-col-sm-6{grid-column:auto/span 6}.panel-grid .g-col-sm-7{grid-column:auto/span 7}.panel-grid .g-col-sm-8{grid-column:auto/span 8}.panel-grid .g-col-sm-9{grid-column:auto/span 9}.panel-grid .g-col-sm-10{grid-column:auto/span 10}.panel-grid .g-col-sm-11{grid-column:auto/span 11}.panel-grid .g-col-sm-12{grid-column:auto/span 12}.panel-grid .g-col-sm-13{grid-column:auto/span 13}.panel-grid .g-col-sm-14{grid-column:auto/span 14}.panel-grid .g-col-sm-15{grid-column:auto/span 15}.panel-grid .g-col-sm-16{grid-column:auto/span 16}.panel-grid .g-col-sm-17{grid-column:auto/span 17}.panel-grid .g-col-sm-18{grid-column:auto/span 18}.panel-grid .g-col-sm-19{grid-column:auto/span 19}.panel-grid .g-col-sm-20{grid-column:auto/span 20}.panel-grid .g-col-sm-21{grid-column:auto/span 21}.panel-grid .g-col-sm-22{grid-column:auto/span 22}.panel-grid .g-col-sm-23{grid-column:auto/span 23}.panel-grid .g-col-sm-24{grid-column:auto/span 24}.panel-grid .g-start-sm-1{grid-column-start:1}.panel-grid .g-start-sm-2{grid-column-start:2}.panel-grid .g-start-sm-3{grid-column-start:3}.panel-grid .g-start-sm-4{grid-column-start:4}.panel-grid .g-start-sm-5{grid-column-start:5}.panel-grid .g-start-sm-6{grid-column-start:6}.panel-grid .g-start-sm-7{grid-column-start:7}.panel-grid .g-start-sm-8{grid-column-start:8}.panel-grid .g-start-sm-9{grid-column-start:9}.panel-grid .g-start-sm-10{grid-column-start:10}.panel-grid .g-start-sm-11{grid-column-start:11}.panel-grid .g-start-sm-12{grid-column-start:12}.panel-grid .g-start-sm-13{grid-column-start:13}.panel-grid .g-start-sm-14{grid-column-start:14}.panel-grid .g-start-sm-15{grid-column-start:15}.panel-grid .g-start-sm-16{grid-column-start:16}.panel-grid .g-start-sm-17{grid-column-start:17}.panel-grid .g-start-sm-18{grid-column-start:18}.panel-grid .g-start-sm-19{grid-column-start:19}.panel-grid .g-start-sm-20{grid-column-start:20}.panel-grid .g-start-sm-21{grid-column-start:21}.panel-grid .g-start-sm-22{grid-column-start:22}.panel-grid .g-start-sm-23{grid-column-start:23}}@media(min-width: 768px){.panel-grid .g-col-md-1{grid-column:auto/span 1}.panel-grid .g-col-md-2{grid-column:auto/span 2}.panel-grid .g-col-md-3{grid-column:auto/span 3}.panel-grid .g-col-md-4{grid-column:auto/span 4}.panel-grid .g-col-md-5{grid-column:auto/span 5}.panel-grid .g-col-md-6{grid-column:auto/span 6}.panel-grid .g-col-md-7{grid-column:auto/span 7}.panel-grid .g-col-md-8{grid-column:auto/span 8}.panel-grid .g-col-md-9{grid-column:auto/span 9}.panel-grid .g-col-md-10{grid-column:auto/span 10}.panel-grid .g-col-md-11{grid-column:auto/span 11}.panel-grid .g-col-md-12{grid-column:auto/span 12}.panel-grid .g-col-md-13{grid-column:auto/span 13}.panel-grid .g-col-md-14{grid-column:auto/span 14}.panel-grid .g-col-md-15{grid-column:auto/span 15}.panel-grid .g-col-md-16{grid-column:auto/span 16}.panel-grid .g-col-md-17{grid-column:auto/span 17}.panel-grid .g-col-md-18{grid-column:auto/span 18}.panel-grid .g-col-md-19{grid-column:auto/span 19}.panel-grid .g-col-md-20{grid-column:auto/span 20}.panel-grid .g-col-md-21{grid-column:auto/span 21}.panel-grid .g-col-md-22{grid-column:auto/span 22}.panel-grid .g-col-md-23{grid-column:auto/span 23}.panel-grid .g-col-md-24{grid-column:auto/span 24}.panel-grid .g-start-md-1{grid-column-start:1}.panel-grid .g-start-md-2{grid-column-start:2}.panel-grid .g-start-md-3{grid-column-start:3}.panel-grid .g-start-md-4{grid-column-start:4}.panel-grid .g-start-md-5{grid-column-start:5}.panel-grid .g-start-md-6{grid-column-start:6}.panel-grid .g-start-md-7{grid-column-start:7}.panel-grid .g-start-md-8{grid-column-start:8}.panel-grid .g-start-md-9{grid-column-start:9}.panel-grid .g-start-md-10{grid-column-start:10}.panel-grid .g-start-md-11{grid-column-start:11}.panel-grid .g-start-md-12{grid-column-start:12}.panel-grid .g-start-md-13{grid-column-start:13}.panel-grid .g-start-md-14{grid-column-start:14}.panel-grid .g-start-md-15{grid-column-start:15}.panel-grid .g-start-md-16{grid-column-start:16}.panel-grid .g-start-md-17{grid-column-start:17}.panel-grid .g-start-md-18{grid-column-start:18}.panel-grid .g-start-md-19{grid-column-start:19}.panel-grid .g-start-md-20{grid-column-start:20}.panel-grid .g-start-md-21{grid-column-start:21}.panel-grid .g-start-md-22{grid-column-start:22}.panel-grid .g-start-md-23{grid-column-start:23}}@media(min-width: 992px){.panel-grid .g-col-lg-1{grid-column:auto/span 1}.panel-grid .g-col-lg-2{grid-column:auto/span 2}.panel-grid .g-col-lg-3{grid-column:auto/span 3}.panel-grid .g-col-lg-4{grid-column:auto/span 4}.panel-grid .g-col-lg-5{grid-column:auto/span 5}.panel-grid .g-col-lg-6{grid-column:auto/span 6}.panel-grid .g-col-lg-7{grid-column:auto/span 7}.panel-grid .g-col-lg-8{grid-column:auto/span 8}.panel-grid .g-col-lg-9{grid-column:auto/span 9}.panel-grid .g-col-lg-10{grid-column:auto/span 10}.panel-grid .g-col-lg-11{grid-column:auto/span 11}.panel-grid .g-col-lg-12{grid-column:auto/span 12}.panel-grid .g-col-lg-13{grid-column:auto/span 13}.panel-grid .g-col-lg-14{grid-column:auto/span 14}.panel-grid .g-col-lg-15{grid-column:auto/span 15}.panel-grid .g-col-lg-16{grid-column:auto/span 16}.panel-grid .g-col-lg-17{grid-column:auto/span 17}.panel-grid .g-col-lg-18{grid-column:auto/span 18}.panel-grid .g-col-lg-19{grid-column:auto/span 19}.panel-grid .g-col-lg-20{grid-column:auto/span 20}.panel-grid .g-col-lg-21{grid-column:auto/span 21}.panel-grid .g-col-lg-22{grid-column:auto/span 22}.panel-grid .g-col-lg-23{grid-column:auto/span 23}.panel-grid .g-col-lg-24{grid-column:auto/span 24}.panel-grid .g-start-lg-1{grid-column-start:1}.panel-grid .g-start-lg-2{grid-column-start:2}.panel-grid .g-start-lg-3{grid-column-start:3}.panel-grid .g-start-lg-4{grid-column-start:4}.panel-grid .g-start-lg-5{grid-column-start:5}.panel-grid .g-start-lg-6{grid-column-start:6}.panel-grid .g-start-lg-7{grid-column-start:7}.panel-grid .g-start-lg-8{grid-column-start:8}.panel-grid .g-start-lg-9{grid-column-start:9}.panel-grid .g-start-lg-10{grid-column-start:10}.panel-grid .g-start-lg-11{grid-column-start:11}.panel-grid .g-start-lg-12{grid-column-start:12}.panel-grid .g-start-lg-13{grid-column-start:13}.panel-grid .g-start-lg-14{grid-column-start:14}.panel-grid .g-start-lg-15{grid-column-start:15}.panel-grid .g-start-lg-16{grid-column-start:16}.panel-grid .g-start-lg-17{grid-column-start:17}.panel-grid .g-start-lg-18{grid-column-start:18}.panel-grid .g-start-lg-19{grid-column-start:19}.panel-grid .g-start-lg-20{grid-column-start:20}.panel-grid .g-start-lg-21{grid-column-start:21}.panel-grid .g-start-lg-22{grid-column-start:22}.panel-grid .g-start-lg-23{grid-column-start:23}}@media(min-width: 1200px){.panel-grid .g-col-xl-1{grid-column:auto/span 1}.panel-grid .g-col-xl-2{grid-column:auto/span 2}.panel-grid .g-col-xl-3{grid-column:auto/span 3}.panel-grid .g-col-xl-4{grid-column:auto/span 4}.panel-grid .g-col-xl-5{grid-column:auto/span 5}.panel-grid .g-col-xl-6{grid-column:auto/span 6}.panel-grid .g-col-xl-7{grid-column:auto/span 7}.panel-grid .g-col-xl-8{grid-column:auto/span 8}.panel-grid .g-col-xl-9{grid-column:auto/span 9}.panel-grid .g-col-xl-10{grid-column:auto/span 10}.panel-grid .g-col-xl-11{grid-column:auto/span 11}.panel-grid .g-col-xl-12{grid-column:auto/span 12}.panel-grid .g-col-xl-13{grid-column:auto/span 13}.panel-grid .g-col-xl-14{grid-column:auto/span 14}.panel-grid .g-col-xl-15{grid-column:auto/span 15}.panel-grid .g-col-xl-16{grid-column:auto/span 16}.panel-grid .g-col-xl-17{grid-column:auto/span 17}.panel-grid .g-col-xl-18{grid-column:auto/span 18}.panel-grid .g-col-xl-19{grid-column:auto/span 19}.panel-grid .g-col-xl-20{grid-column:auto/span 20}.panel-grid .g-col-xl-21{grid-column:auto/span 21}.panel-grid .g-col-xl-22{grid-column:auto/span 22}.panel-grid .g-col-xl-23{grid-column:auto/span 23}.panel-grid .g-col-xl-24{grid-column:auto/span 24}.panel-grid .g-start-xl-1{grid-column-start:1}.panel-grid .g-start-xl-2{grid-column-start:2}.panel-grid .g-start-xl-3{grid-column-start:3}.panel-grid .g-start-xl-4{grid-column-start:4}.panel-grid .g-start-xl-5{grid-column-start:5}.panel-grid .g-start-xl-6{grid-column-start:6}.panel-grid .g-start-xl-7{grid-column-start:7}.panel-grid .g-start-xl-8{grid-column-start:8}.panel-grid .g-start-xl-9{grid-column-start:9}.panel-grid .g-start-xl-10{grid-column-start:10}.panel-grid .g-start-xl-11{grid-column-start:11}.panel-grid .g-start-xl-12{grid-column-start:12}.panel-grid .g-start-xl-13{grid-column-start:13}.panel-grid .g-start-xl-14{grid-column-start:14}.panel-grid .g-start-xl-15{grid-column-start:15}.panel-grid .g-start-xl-16{grid-column-start:16}.panel-grid .g-start-xl-17{grid-column-start:17}.panel-grid .g-start-xl-18{grid-column-start:18}.panel-grid .g-start-xl-19{grid-column-start:19}.panel-grid .g-start-xl-20{grid-column-start:20}.panel-grid .g-start-xl-21{grid-column-start:21}.panel-grid .g-start-xl-22{grid-column-start:22}.panel-grid .g-start-xl-23{grid-column-start:23}}@media(min-width: 1400px){.panel-grid .g-col-xxl-1{grid-column:auto/span 1}.panel-grid .g-col-xxl-2{grid-column:auto/span 2}.panel-grid .g-col-xxl-3{grid-column:auto/span 3}.panel-grid .g-col-xxl-4{grid-column:auto/span 4}.panel-grid .g-col-xxl-5{grid-column:auto/span 5}.panel-grid .g-col-xxl-6{grid-column:auto/span 6}.panel-grid .g-col-xxl-7{grid-column:auto/span 7}.panel-grid .g-col-xxl-8{grid-column:auto/span 8}.panel-grid .g-col-xxl-9{grid-column:auto/span 9}.panel-grid .g-col-xxl-10{grid-column:auto/span 10}.panel-grid .g-col-xxl-11{grid-column:auto/span 11}.panel-grid .g-col-xxl-12{grid-column:auto/span 12}.panel-grid .g-col-xxl-13{grid-column:auto/span 13}.panel-grid .g-col-xxl-14{grid-column:auto/span 14}.panel-grid .g-col-xxl-15{grid-column:auto/span 15}.panel-grid .g-col-xxl-16{grid-column:auto/span 16}.panel-grid .g-col-xxl-17{grid-column:auto/span 17}.panel-grid .g-col-xxl-18{grid-column:auto/span 18}.panel-grid .g-col-xxl-19{grid-column:auto/span 19}.panel-grid .g-col-xxl-20{grid-column:auto/span 20}.panel-grid .g-col-xxl-21{grid-column:auto/span 21}.panel-grid .g-col-xxl-22{grid-column:auto/span 22}.panel-grid .g-col-xxl-23{grid-column:auto/span 23}.panel-grid .g-col-xxl-24{grid-column:auto/span 24}.panel-grid .g-start-xxl-1{grid-column-start:1}.panel-grid .g-start-xxl-2{grid-column-start:2}.panel-grid .g-start-xxl-3{grid-column-start:3}.panel-grid .g-start-xxl-4{grid-column-start:4}.panel-grid .g-start-xxl-5{grid-column-start:5}.panel-grid .g-start-xxl-6{grid-column-start:6}.panel-grid .g-start-xxl-7{grid-column-start:7}.panel-grid .g-start-xxl-8{grid-column-start:8}.panel-grid .g-start-xxl-9{grid-column-start:9}.panel-grid .g-start-xxl-10{grid-column-start:10}.panel-grid .g-start-xxl-11{grid-column-start:11}.panel-grid .g-start-xxl-12{grid-column-start:12}.panel-grid .g-start-xxl-13{grid-column-start:13}.panel-grid .g-start-xxl-14{grid-column-start:14}.panel-grid .g-start-xxl-15{grid-column-start:15}.panel-grid .g-start-xxl-16{grid-column-start:16}.panel-grid .g-start-xxl-17{grid-column-start:17}.panel-grid .g-start-xxl-18{grid-column-start:18}.panel-grid .g-start-xxl-19{grid-column-start:19}.panel-grid .g-start-xxl-20{grid-column-start:20}.panel-grid .g-start-xxl-21{grid-column-start:21}.panel-grid .g-start-xxl-22{grid-column-start:22}.panel-grid .g-start-xxl-23{grid-column-start:23}}main{margin-top:1em;margin-bottom:1em}h1,.h1,h2,.h2{margin-top:2rem;margin-bottom:1rem}h1.title,.title.h1{margin-top:0}h2,.h2{border-bottom:1px solid #dee2e6;padding-bottom:.5rem}h3,.h3,h4,.h4{margin-top:1.5rem}.header-section-number{color:#747a7f}.nav-link.active .header-section-number{color:inherit}mark,.mark{padding:0em}.panel-caption,caption,.figure-caption{font-size:1rem}.panel-caption,.figure-caption,figcaption{color:#747a7f}.table-caption,caption{color:#373a3c}.quarto-layout-cell[data-ref-parent] caption{color:#747a7f}.column-margin figcaption,.margin-caption,div.aside,aside,.column-margin{color:#747a7f;font-size:.825rem}.panel-caption.margin-caption{text-align:inherit}.column-margin.column-container p{margin-bottom:0}.column-margin.column-container>*:not(.collapse){padding-top:.5em;padding-bottom:.5em;display:block}.column-margin.column-container>*.collapse:not(.show){display:none}@media(min-width: 768px){.column-margin.column-container .callout-margin-content:first-child{margin-top:4.5em}.column-margin.column-container .callout-margin-content-simple:first-child{margin-top:3.5em}}.margin-caption>*{padding-top:.5em;padding-bottom:.5em}@media(max-width: 767.98px){.quarto-layout-row{flex-direction:column}}.tab-content{margin-top:0px;border-left:#dee2e6 1px solid;border-right:#dee2e6 1px solid;border-bottom:#dee2e6 1px solid;margin-left:0;padding:1em;margin-bottom:1em}@media(max-width: 767.98px){.layout-sidebar{margin-left:0;margin-right:0}}.panel-sidebar,.panel-sidebar .form-control,.panel-input,.panel-input .form-control,.selectize-dropdown{font-size:.9rem}.panel-sidebar .form-control,.panel-input .form-control{padding-top:.1rem}.tab-pane div.sourceCode{margin-top:0px}.tab-pane>p{padding-top:1em}.tab-content>.tab-pane:not(.active){display:none !important}div.sourceCode{background-color:rgba(233,236,239,.65);border:1px solid rgba(233,236,239,.65);border-radius:.25rem}pre.sourceCode{background-color:transparent}pre.sourceCode{border:none;font-size:.875em;overflow:visible !important;padding:.4em}.callout pre.sourceCode{padding-left:0}div.sourceCode{overflow-y:hidden}.callout div.sourceCode{margin-left:initial}.blockquote{font-size:inherit;padding-left:1rem;padding-right:1.5rem;color:#747a7f}.blockquote h1:first-child,.blockquote .h1:first-child,.blockquote h2:first-child,.blockquote .h2:first-child,.blockquote h3:first-child,.blockquote .h3:first-child,.blockquote h4:first-child,.blockquote .h4:first-child,.blockquote h5:first-child,.blockquote .h5:first-child{margin-top:0}pre{background-color:initial;padding:initial;border:initial}p code:not(.sourceCode),li code:not(.sourceCode){background-color:#f7f7f7;padding:.2em}nav p code:not(.sourceCode),nav li code:not(.sourceCode){background-color:transparent;padding:0}#quarto-embedded-source-code-modal>.modal-dialog{max-width:1000px;padding-left:1.75rem;padding-right:1.75rem}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-body{padding:0}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-body div.sourceCode{margin:0;padding:.2rem .2rem;border-radius:0px;border:none}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-header{padding:.7rem}.code-tools-button{font-size:1rem;padding:.15rem .15rem;margin-left:5px;color:#6c757d;background-color:transparent;transition:initial;cursor:pointer}.code-tools-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:1rem 1rem}.code-tools-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}#quarto-embedded-source-code-modal .code-copy-button>.bi::before{background-image:url('data:image/svg+xml,')}#quarto-embedded-source-code-modal .code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,')}.sidebar{will-change:top;transition:top 200ms linear;position:sticky;overflow-y:auto;padding-top:1.2em;max-height:100vh}.sidebar.toc-left,.sidebar.margin-sidebar{top:0px;padding-top:1em}.sidebar.toc-left>*,.sidebar.margin-sidebar>*{padding-top:.5em}.sidebar.quarto-banner-title-block-sidebar>*{padding-top:1.65em}.sidebar nav[role=doc-toc]>h2,.sidebar nav[role=doc-toc]>.h2{font-size:.875rem;font-weight:400;margin-bottom:.5rem;margin-top:.3rem;font-family:inherit;border-bottom:0;padding-bottom:0;padding-top:0px}.sidebar nav[role=doc-toc]>ul a{border-left:1px solid #e9ecef;padding-left:.6rem}.sidebar nav[role=doc-toc]>ul a:empty{display:none}.sidebar nav[role=doc-toc] ul{padding-left:0;list-style:none;font-size:.875rem;font-weight:300}.sidebar nav[role=doc-toc]>ul li a{line-height:1.1rem;padding-bottom:.2rem;padding-top:.2rem;color:inherit}.sidebar nav[role=doc-toc] ul>li>ul>li>a{padding-left:1.2em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>a{padding-left:2.4em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>a{padding-left:3.6em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>ul>li>a{padding-left:4.8em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>ul>li>ul>li>a{padding-left:6em}.sidebar nav[role=doc-toc] ul>li>ul>li>a.active{border-left:1px solid #2780e3;color:#2780e3 !important}.sidebar nav[role=doc-toc] ul>li>a.active{border-left:1px solid #2780e3;color:#2780e3 !important}kbd,.kbd{color:#373a3c;background-color:#f8f9fa;border:1px solid;border-radius:5px;border-color:#dee2e6}div.hanging-indent{margin-left:1em;text-indent:-1em}.citation a,.footnote-ref{text-decoration:none}.footnotes ol{padding-left:1em}.tippy-content>*{margin-bottom:.7em}.tippy-content>*:last-child{margin-bottom:0}.table a{word-break:break-word}.table>:not(:first-child){border-top-width:1px;border-top-color:#dee2e6}.table>thead{border-bottom:1px solid currentColor}.table>tbody{border-top:1px solid #dee2e6}.callout{margin-top:1.25rem;margin-bottom:1.25rem;border-radius:.25rem}.callout.callout-style-simple{padding:.4em .7em;border-left:5px solid;border-right:1px solid #dee2e6;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.callout.callout-style-default{border-left:5px solid;border-right:1px solid #dee2e6;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.callout .callout-body-container{flex-grow:1}.callout.callout-style-simple .callout-body{font-size:.9rem;font-weight:400}.callout.callout-style-default .callout-body{font-size:.9rem;font-weight:400}.callout.callout-captioned .callout-body{margin-top:.2em}.callout:not(.no-icon).callout-captioned.callout-style-simple .callout-body{padding-left:1.6em}.callout.callout-captioned>.callout-header{padding-top:.2em;margin-bottom:-0.2em}.callout.callout-style-simple>div.callout-header{border-bottom:none;font-size:.9rem;font-weight:600;opacity:75%}.callout.callout-style-default>div.callout-header{border-bottom:none;font-weight:600;opacity:85%;font-size:.9rem;padding-left:.5em;padding-right:.5em}.callout.callout-style-default div.callout-body{padding-left:.5em;padding-right:.5em}.callout.callout-style-default div.callout-body>:first-child{margin-top:.5em}.callout>div.callout-header[data-bs-toggle=collapse]{cursor:pointer}.callout.callout-style-default .callout-header[aria-expanded=false],.callout.callout-style-default .callout-header[aria-expanded=true]{padding-top:0px;margin-bottom:0px;align-items:center}.callout.callout-captioned .callout-body>:last-child:not(.sourceCode),.callout.callout-captioned .callout-body>div>:last-child:not(.sourceCode){margin-bottom:.5rem}.callout:not(.callout-captioned) .callout-body>:first-child,.callout:not(.callout-captioned) .callout-body>div>:first-child{margin-top:.25rem}.callout:not(.callout-captioned) .callout-body>:last-child,.callout:not(.callout-captioned) .callout-body>div>:last-child{margin-bottom:.2rem}.callout.callout-style-simple .callout-icon::before,.callout.callout-style-simple .callout-toggle::before{height:1rem;width:1rem;display:inline-block;content:"";background-repeat:no-repeat;background-size:1rem 1rem}.callout.callout-style-default .callout-icon::before,.callout.callout-style-default .callout-toggle::before{height:.9rem;width:.9rem;display:inline-block;content:"";background-repeat:no-repeat;background-size:.9rem .9rem}.callout.callout-style-default .callout-toggle::before{margin-top:5px}.callout .callout-btn-toggle .callout-toggle::before{transition:transform .2s linear}.callout .callout-header[aria-expanded=false] .callout-toggle::before{transform:rotate(-90deg)}.callout .callout-header[aria-expanded=true] .callout-toggle::before{transform:none}.callout.callout-style-simple:not(.no-icon) div.callout-icon-container{padding-top:.2em;padding-right:.55em}.callout.callout-style-default:not(.no-icon) div.callout-icon-container{padding-top:.1em;padding-right:.35em}.callout.callout-style-default:not(.no-icon) div.callout-caption-container{margin-top:-1px}.callout.callout-style-default.callout-caution:not(.no-icon) div.callout-icon-container{padding-top:.3em;padding-right:.35em}.callout>.callout-body>.callout-icon-container>.no-icon,.callout>.callout-header>.callout-icon-container>.no-icon{display:none}div.callout.callout{border-left-color:#6c757d}div.callout.callout-style-default>.callout-header{background-color:#6c757d}div.callout-note.callout{border-left-color:#2780e3}div.callout-note.callout-style-default>.callout-header{background-color:#e9f2fc}div.callout-note:not(.callout-captioned) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-note.callout-captioned .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-note .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-tip.callout{border-left-color:#3fb618}div.callout-tip.callout-style-default>.callout-header{background-color:#ecf8e8}div.callout-tip:not(.callout-captioned) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-tip.callout-captioned .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-tip .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-warning.callout{border-left-color:#ff7518}div.callout-warning.callout-style-default>.callout-header{background-color:#fff1e8}div.callout-warning:not(.callout-captioned) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-warning.callout-captioned .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-warning .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-caution.callout{border-left-color:#f0ad4e}div.callout-caution.callout-style-default>.callout-header{background-color:#fef7ed}div.callout-caution:not(.callout-captioned) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-caution.callout-captioned .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-caution .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-important.callout{border-left-color:#ff0039}div.callout-important.callout-style-default>.callout-header{background-color:#ffe6eb}div.callout-important:not(.callout-captioned) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-important.callout-captioned .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-important .callout-toggle::before{background-image:url('data:image/svg+xml,')}.quarto-toggle-container{display:flex;align-items:center}@media(min-width: 992px){.navbar .quarto-color-scheme-toggle{padding-left:.5rem;padding-right:.5rem}}@media(max-width: 767.98px){.navbar .quarto-color-scheme-toggle{padding-left:0;padding-right:0;padding-bottom:.5em}}.quarto-reader-toggle .bi::before,.quarto-color-scheme-toggle .bi::before{display:inline-block;height:1rem;width:1rem;content:"";background-repeat:no-repeat;background-size:1rem 1rem}.navbar-collapse .quarto-color-scheme-toggle{padding-left:.6rem;padding-right:0;margin-top:-12px}.sidebar-navigation{padding-left:20px}.sidebar-navigation .quarto-color-scheme-toggle .bi::before{padding-top:.2rem;margin-bottom:-0.2rem}.sidebar-tools-main .quarto-color-scheme-toggle .bi::before{padding-top:.2rem;margin-bottom:-0.2rem}.navbar .quarto-color-scheme-toggle .bi::before{padding-top:7px;margin-bottom:-7px;padding-left:2px;margin-right:2px}.navbar .quarto-color-scheme-toggle:not(.alternate) .bi::before{background-image:url('data:image/svg+xml,')}.navbar .quarto-color-scheme-toggle.alternate .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-color-scheme-toggle:not(.alternate) .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-color-scheme-toggle.alternate .bi::before{background-image:url('data:image/svg+xml,')}.quarto-sidebar-toggle{border-color:#dee2e6;border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem;border-style:solid;border-width:1px;overflow:hidden;border-top-width:0px;padding-top:0px !important}.quarto-sidebar-toggle-title{cursor:pointer;padding-bottom:2px;margin-left:.25em;text-align:center;font-weight:400;font-size:.775em}#quarto-content .quarto-sidebar-toggle{background:#fafafa}#quarto-content .quarto-sidebar-toggle-title{color:#373a3c}.quarto-sidebar-toggle-icon{color:#dee2e6;margin-right:.5em;float:right;transition:transform .2s ease}.quarto-sidebar-toggle-icon::before{padding-top:5px}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-icon{transform:rotate(-180deg)}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-title{border-bottom:solid #dee2e6 1px}.quarto-sidebar-toggle-contents{background-color:#fff;padding-right:10px;padding-left:10px;margin-top:0px !important;transition:max-height .5s ease}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-contents{padding-top:1em;padding-bottom:10px}.quarto-sidebar-toggle:not(.expanded) .quarto-sidebar-toggle-contents{padding-top:0px !important;padding-bottom:0px}nav[role=doc-toc]{z-index:1020}#quarto-sidebar>*,nav[role=doc-toc]>*{transition:opacity .1s ease,border .1s ease}#quarto-sidebar.slow>*,nav[role=doc-toc].slow>*{transition:opacity .4s ease,border .4s ease}.quarto-color-scheme-toggle:not(.alternate).top-right .bi::before{background-image:url('data:image/svg+xml,')}.quarto-color-scheme-toggle.alternate.top-right .bi::before{background-image:url('data:image/svg+xml,')}#quarto-appendix.default{border-top:1px solid #dee2e6}#quarto-appendix.default{background-color:#fff;padding-top:1.5em;margin-top:2em;z-index:998}#quarto-appendix.default .quarto-appendix-heading{margin-top:0;line-height:1.4em;font-weight:600;opacity:.9;border-bottom:none;margin-bottom:0}#quarto-appendix.default .footnotes ol,#quarto-appendix.default .footnotes ol li>p:last-of-type,#quarto-appendix.default .quarto-appendix-contents>p:last-of-type{margin-bottom:0}#quarto-appendix.default .quarto-appendix-secondary-label{margin-bottom:.4em}#quarto-appendix.default .quarto-appendix-bibtex{font-size:.7em;padding:1em;border:solid 1px #dee2e6;margin-bottom:1em}#quarto-appendix.default .quarto-appendix-bibtex code.sourceCode{white-space:pre-wrap}#quarto-appendix.default .quarto-appendix-citeas{font-size:.9em;padding:1em;border:solid 1px #dee2e6;margin-bottom:1em}#quarto-appendix.default .quarto-appendix-heading{font-size:1em !important}#quarto-appendix.default *[role=doc-endnotes]>ol,#quarto-appendix.default .quarto-appendix-contents>*:not(h2):not(.h2){font-size:.9em}#quarto-appendix.default section{padding-bottom:1.5em}#quarto-appendix.default section *[role=doc-endnotes],#quarto-appendix.default section>*:not(a){opacity:.9;word-wrap:break-word}.btn.btn-quarto,div.cell-output-display .btn-quarto{color:#cbcccc;background-color:#373a3c;border-color:#373a3c}.btn.btn-quarto:hover,div.cell-output-display .btn-quarto:hover{color:#cbcccc;background-color:#555859;border-color:#4b4e50}.btn-check:focus+.btn.btn-quarto,.btn.btn-quarto:focus,.btn-check:focus+div.cell-output-display .btn-quarto,div.cell-output-display .btn-quarto:focus{color:#cbcccc;background-color:#555859;border-color:#4b4e50;box-shadow:0 0 0 .25rem rgba(77,80,82,.5)}.btn-check:checked+.btn.btn-quarto,.btn-check:active+.btn.btn-quarto,.btn.btn-quarto:active,.btn.btn-quarto.active,.show>.btn.btn-quarto.dropdown-toggle,.btn-check:checked+div.cell-output-display .btn-quarto,.btn-check:active+div.cell-output-display .btn-quarto,div.cell-output-display .btn-quarto:active,div.cell-output-display .btn-quarto.active,.show>div.cell-output-display .btn-quarto.dropdown-toggle{color:#fff;background-color:#5f6163;border-color:#4b4e50}.btn-check:checked+.btn.btn-quarto:focus,.btn-check:active+.btn.btn-quarto:focus,.btn.btn-quarto:active:focus,.btn.btn-quarto.active:focus,.show>.btn.btn-quarto.dropdown-toggle:focus,.btn-check:checked+div.cell-output-display .btn-quarto:focus,.btn-check:active+div.cell-output-display .btn-quarto:focus,div.cell-output-display .btn-quarto:active:focus,div.cell-output-display .btn-quarto.active:focus,.show>div.cell-output-display .btn-quarto.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(77,80,82,.5)}.btn.btn-quarto:disabled,.btn.btn-quarto.disabled,div.cell-output-display .btn-quarto:disabled,div.cell-output-display .btn-quarto.disabled{color:#fff;background-color:#373a3c;border-color:#373a3c}nav.quarto-secondary-nav.color-navbar{background-color:#2780e3;color:#fdfeff}nav.quarto-secondary-nav.color-navbar h1,nav.quarto-secondary-nav.color-navbar .h1,nav.quarto-secondary-nav.color-navbar .quarto-btn-toggle{color:#fdfeff}@media(max-width: 991.98px){body.nav-sidebar .quarto-title-banner,body.nav-sidebar .quarto-title-banner{display:none}}p.subtitle{margin-top:.25em;margin-bottom:.5em}code a:any-link{color:inherit;text-decoration-color:#6c757d}/*! light */div.observablehq table thead tr th{background-color:var(--bs-body-bg)}input,button,select,optgroup,textarea{background-color:var(--bs-body-bg)}@media print{.page-columns .column-screen-inset{grid-column:page-start-inset/page-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset table{background:#fff}.page-columns .column-screen-inset-left{grid-column:page-start-inset/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset-left table{background:#fff}.page-columns .column-screen-inset-right{grid-column:body-content-start/page-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:page-start/page-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:page-start/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/page-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-right table{background:#fff}.page-columns .column-screen-inset-shaded{grid-column:page-start-inset/page-end-inset;padding:1em;background:#f8f9fa;z-index:998;transform:translate3d(0, 0, 0);margin-bottom:1em}}a.external:after{display:inline-block;height:.75rem;width:.75rem;margin-bottom:.15em;margin-left:.25em;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:.75rem .75rem}a.external:after:hover{cursor:pointer}.quarto-ext-icon{display:inline-block;font-size:.75em;padding-left:.3em}.code-with-filename .code-with-filename-file{margin-bottom:0;padding-bottom:2px;padding-top:2px;padding-left:.7em;border:var(--quarto-border-width) solid var(--quarto-border-color);border-radius:var(--quarto-border-radius);border-bottom:0;border-bottom-left-radius:0%;border-bottom-right-radius:0%}.code-with-filename div.sourceCode,.reveal .code-with-filename div.sourceCode{margin-top:0;border-top-left-radius:0%;border-top-right-radius:0%}.code-with-filename .code-with-filename-file pre{margin-bottom:0}.code-with-filename .code-with-filename-file,.code-with-filename .code-with-filename-file pre{background-color:rgba(219,219,219,.8)}.quarto-dark .code-with-filename .code-with-filename-file,.quarto-dark .code-with-filename .code-with-filename-file pre{background-color:#555}.code-with-filename .code-with-filename-file strong{font-weight:400}.quarto-title-banner{margin-bottom:1em;color:#fdfeff;background:#2780e3}.quarto-title-banner .code-tools-button{color:#97cbff}.quarto-title-banner .code-tools-button:hover{color:#fdfeff}.quarto-title-banner .code-tools-button>.bi::before{background-image:url('data:image/svg+xml,')}.quarto-title-banner .code-tools-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}.quarto-title-banner .quarto-title .title{font-weight:600}.quarto-title-banner .quarto-categories{margin-top:.75em}@media(min-width: 992px){.quarto-title-banner{padding-top:2.5em;padding-bottom:2.5em}}@media(max-width: 991.98px){.quarto-title-banner{padding-top:1em;padding-bottom:1em}}main.quarto-banner-title-block section:first-of-type h2:first-of-type,main.quarto-banner-title-block section:first-of-type .h2:first-of-type,main.quarto-banner-title-block section:first-of-type h3:first-of-type,main.quarto-banner-title-block section:first-of-type .h3:first-of-type,main.quarto-banner-title-block section:first-of-type h4:first-of-type,main.quarto-banner-title-block section:first-of-type .h4:first-of-type{margin-top:0}.quarto-title .quarto-categories{display:flex;column-gap:.4em;padding-bottom:.5em;margin-top:.75em}.quarto-title .quarto-categories .quarto-category{padding:.25em .75em;font-size:.65em;text-transform:uppercase;border:solid 1px;border-radius:.25rem;opacity:.6}.quarto-title .quarto-categories .quarto-category a{color:inherit}#title-block-header.quarto-title-block.default .quarto-title-meta{display:grid;grid-template-columns:repeat(2, 1fr)}#title-block-header.quarto-title-block.default .quarto-title .title{margin-bottom:0}#title-block-header.quarto-title-block.default .quarto-title-author-orcid img{margin-top:-5px}#title-block-header.quarto-title-block.default .quarto-description p:last-of-type{margin-bottom:0}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p,#title-block-header.quarto-title-block.default .quarto-title-authors p,#title-block-header.quarto-title-block.default .quarto-title-affiliations p{margin-bottom:.1em}#title-block-header.quarto-title-block.default .quarto-title-meta-heading{text-transform:uppercase;margin-top:1em;font-size:.8em;opacity:.8;font-weight:400}#title-block-header.quarto-title-block.default .quarto-title-meta-contents{font-size:.9em}#title-block-header.quarto-title-block.default .quarto-title-meta-contents a{color:#373a3c}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p.affiliation:last-of-type{margin-bottom:.7em}#title-block-header.quarto-title-block.default p.affiliation{margin-bottom:.1em}#title-block-header.quarto-title-block.default .description,#title-block-header.quarto-title-block.default .abstract{margin-top:0}#title-block-header.quarto-title-block.default .description>p,#title-block-header.quarto-title-block.default .abstract>p{font-size:.9em}#title-block-header.quarto-title-block.default .description>p:last-of-type,#title-block-header.quarto-title-block.default .abstract>p:last-of-type{margin-bottom:0}#title-block-header.quarto-title-block.default .description .abstract-title,#title-block-header.quarto-title-block.default .abstract .abstract-title{margin-top:1em;text-transform:uppercase;font-size:.8em;opacity:.8;font-weight:400}#title-block-header.quarto-title-block.default .quarto-title-meta-author{display:grid;grid-template-columns:1fr 1fr}body{-webkit-font-smoothing:antialiased}.badge.bg-light{color:#373a3c}.progress .progress-bar{font-size:8px;line-height:8px}/*# sourceMappingURL=d6b77e37a12f878a50f9f8a85e535bdc.css.map */ diff --git a/docs/site_libs/bootstrap/bootstrap.min.js b/docs/site_libs/bootstrap/bootstrap.min.js deleted file mode 100644 index cc0a2556..00000000 --- a/docs/site_libs/bootstrap/bootstrap.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v5.1.3 (https://getbootstrap.com/) - * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t="transitionend",e=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e},i=t=>{const i=e(t);return i&&document.querySelector(i)?i:null},n=t=>{const i=e(t);return i?document.querySelector(i):null},s=e=>{e.dispatchEvent(new Event(t))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(t):null,a=(t,e,i)=>{Object.keys(i).forEach((n=>{const s=i[n],r=e[n],a=r&&o(r)?"element":null==(l=r)?`${l}`:{}.toString.call(l).match(/\s([a-z]+)/i)[1].toLowerCase();var l;if(!new RegExp(s).test(a))throw new TypeError(`${t.toUpperCase()}: Option "${n}" provided type "${a}" but expected type "${s}".`)}))},l=t=>!(!o(t)||0===t.getClientRects().length)&&"visible"===getComputedStyle(t).getPropertyValue("visibility"),c=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),h=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?h(t.parentNode):null},d=()=>{},u=t=>{t.offsetHeight},f=()=>{const{jQuery:t}=window;return t&&!document.body.hasAttribute("data-bs-no-jquery")?t:null},p=[],m=()=>"rtl"===document.documentElement.dir,g=t=>{var e;e=()=>{const e=f();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(p.length||document.addEventListener("DOMContentLoaded",(()=>{p.forEach((t=>t()))})),p.push(e)):e()},_=t=>{"function"==typeof t&&t()},b=(e,i,n=!0)=>{if(!n)return void _(e);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(i)+5;let r=!1;const a=({target:n})=>{n===i&&(r=!0,i.removeEventListener(t,a),_(e))};i.addEventListener(t,a),setTimeout((()=>{r||s(i)}),o)},v=(t,e,i,n)=>{let s=t.indexOf(e);if(-1===s)return t[!i&&n?t.length-1:0];const o=t.length;return s+=i?1:-1,n&&(s=(s+o)%o),t[Math.max(0,Math.min(s,o-1))]},y=/[^.]*(?=\..*)\.|.*/,w=/\..*/,E=/::\d+$/,A={};let T=1;const O={mouseenter:"mouseover",mouseleave:"mouseout"},C=/^(mouseenter|mouseleave)/i,k=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function L(t,e){return e&&`${e}::${T++}`||t.uidEvent||T++}function x(t){const e=L(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function D(t,e,i=null){const n=Object.keys(t);for(let s=0,o=n.length;sfunction(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};n?n=t(n):i=t(i)}const[o,r,a]=S(e,i,n),l=x(t),c=l[a]||(l[a]={}),h=D(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=L(r,e.replace(y,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(let a=o.length;a--;)if(o[a]===r)return s.delegateTarget=r,n.oneOff&&j.off(t,s.type,e,i),i.apply(r,[s]);return null}}(t,i,n):function(t,e){return function i(n){return n.delegateTarget=t,i.oneOff&&j.off(t,n.type,e),e.apply(t,[n])}}(t,i);u.delegationSelector=o?i:null,u.originalHandler=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function I(t,e,i,n,s){const o=D(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function P(t){return t=t.replace(w,""),O[t]||t}const j={on(t,e,i,n){N(t,e,i,n,!1)},one(t,e,i,n){N(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=S(e,i,n),a=r!==e,l=x(t),c=e.startsWith(".");if(void 0!==o){if(!l||!l[r])return;return void I(t,l,r,o,s?i:null)}c&&Object.keys(l).forEach((i=>{!function(t,e,i,n){const s=e[i]||{};Object.keys(s).forEach((o=>{if(o.includes(n)){const n=s[o];I(t,e,i,n.originalHandler,n.delegationSelector)}}))}(t,l,i,e.slice(1))}));const h=l[r]||{};Object.keys(h).forEach((i=>{const n=i.replace(E,"");if(!a||e.includes(n)){const e=h[i];I(t,l,r,e.originalHandler,e.delegationSelector)}}))},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=f(),s=P(e),o=e!==s,r=k.has(s);let a,l=!0,c=!0,h=!1,d=null;return o&&n&&(a=n.Event(e,i),n(t).trigger(a),l=!a.isPropagationStopped(),c=!a.isImmediatePropagationStopped(),h=a.isDefaultPrevented()),r?(d=document.createEvent("HTMLEvents"),d.initEvent(s,l,!0)):d=new CustomEvent(e,{bubbles:l,cancelable:!0}),void 0!==i&&Object.keys(i).forEach((t=>{Object.defineProperty(d,t,{get:()=>i[t]})})),h&&d.preventDefault(),c&&t.dispatchEvent(d),d.defaultPrevented&&void 0!==a&&a.preventDefault(),d}},M=new Map,H={set(t,e,i){M.has(t)||M.set(t,new Map);const n=M.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>M.has(t)&&M.get(t).get(e)||null,remove(t,e){if(!M.has(t))return;const i=M.get(t);i.delete(e),0===i.size&&M.delete(t)}};class B{constructor(t){(t=r(t))&&(this._element=t,H.set(this._element,this.constructor.DATA_KEY,this))}dispose(){H.remove(this._element,this.constructor.DATA_KEY),j.off(this._element,this.constructor.EVENT_KEY),Object.getOwnPropertyNames(this).forEach((t=>{this[t]=null}))}_queueCallback(t,e,i=!0){b(t,e,i)}static getInstance(t){return H.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.1.3"}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}}const R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,s=t.NAME;j.on(document,i,`[data-bs-dismiss="${s}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),c(this))return;const o=n(this)||this.closest(`.${s}`);t.getOrCreateInstance(o)[e]()}))};class W extends B{static get NAME(){return"alert"}close(){if(j.trigger(this._element,"close.bs.alert").defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),j.trigger(this._element,"closed.bs.alert"),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=W.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(W,"close"),g(W);const $='[data-bs-toggle="button"]';class z extends B{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=z.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}function q(t){return"true"===t||"false"!==t&&(t===Number(t).toString()?Number(t):""===t||"null"===t?null:t)}function F(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}j.on(document,"click.bs.button.data-api",$,(t=>{t.preventDefault();const e=t.target.closest($);z.getOrCreateInstance(e).toggle()})),g(z);const U={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${F(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${F(e)}`)},getDataAttributes(t){if(!t)return{};const e={};return Object.keys(t.dataset).filter((t=>t.startsWith("bs"))).forEach((i=>{let n=i.replace(/^bs/,"");n=n.charAt(0).toLowerCase()+n.slice(1,n.length),e[n]=q(t.dataset[i])})),e},getDataAttribute:(t,e)=>q(t.getAttribute(`data-bs-${F(e)}`)),offset(t){const e=t.getBoundingClientRect();return{top:e.top+window.pageYOffset,left:e.left+window.pageXOffset}},position:t=>({top:t.offsetTop,left:t.offsetLeft})},V={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode;for(;n&&n.nodeType===Node.ELEMENT_NODE&&3!==n.nodeType;)n.matches(e)&&i.push(n),n=n.parentNode;return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(", ");return this.find(e,t).filter((t=>!c(t)&&l(t)))}},K="carousel",X={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0,touch:!0},Y={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean",touch:"boolean"},Q="next",G="prev",Z="left",J="right",tt={ArrowLeft:J,ArrowRight:Z},et="slid.bs.carousel",it="active",nt=".active.carousel-item";class st extends B{constructor(t,e){super(t),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this.touchStartX=0,this.touchDeltaX=0,this._config=this._getConfig(e),this._indicatorsElement=V.findOne(".carousel-indicators",this._element),this._touchSupported="ontouchstart"in document.documentElement||navigator.maxTouchPoints>0,this._pointerEvent=Boolean(window.PointerEvent),this._addEventListeners()}static get Default(){return X}static get NAME(){return K}next(){this._slide(Q)}nextWhenVisible(){!document.hidden&&l(this._element)&&this.next()}prev(){this._slide(G)}pause(t){t||(this._isPaused=!0),V.findOne(".carousel-item-next, .carousel-item-prev",this._element)&&(s(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null}cycle(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config&&this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))}to(t){this._activeElement=V.findOne(nt,this._element);const e=this._getItemIndex(this._activeElement);if(t>this._items.length-1||t<0)return;if(this._isSliding)return void j.one(this._element,et,(()=>this.to(t)));if(e===t)return this.pause(),void this.cycle();const i=t>e?Q:G;this._slide(i,this._items[t])}_getConfig(t){return t={...X,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(K,t,Y),t}_handleSwipe(){const t=Math.abs(this.touchDeltaX);if(t<=40)return;const e=t/this.touchDeltaX;this.touchDeltaX=0,e&&this._slide(e>0?J:Z)}_addEventListeners(){this._config.keyboard&&j.on(this._element,"keydown.bs.carousel",(t=>this._keydown(t))),"hover"===this._config.pause&&(j.on(this._element,"mouseenter.bs.carousel",(t=>this.pause(t))),j.on(this._element,"mouseleave.bs.carousel",(t=>this.cycle(t)))),this._config.touch&&this._touchSupported&&this._addTouchEventListeners()}_addTouchEventListeners(){const t=t=>this._pointerEvent&&("pen"===t.pointerType||"touch"===t.pointerType),e=e=>{t(e)?this.touchStartX=e.clientX:this._pointerEvent||(this.touchStartX=e.touches[0].clientX)},i=t=>{this.touchDeltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this.touchStartX},n=e=>{t(e)&&(this.touchDeltaX=e.clientX-this.touchStartX),this._handleSwipe(),"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((t=>this.cycle(t)),500+this._config.interval))};V.find(".carousel-item img",this._element).forEach((t=>{j.on(t,"dragstart.bs.carousel",(t=>t.preventDefault()))})),this._pointerEvent?(j.on(this._element,"pointerdown.bs.carousel",(t=>e(t))),j.on(this._element,"pointerup.bs.carousel",(t=>n(t))),this._element.classList.add("pointer-event")):(j.on(this._element,"touchstart.bs.carousel",(t=>e(t))),j.on(this._element,"touchmove.bs.carousel",(t=>i(t))),j.on(this._element,"touchend.bs.carousel",(t=>n(t))))}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=tt[t.key];e&&(t.preventDefault(),this._slide(e))}_getItemIndex(t){return this._items=t&&t.parentNode?V.find(".carousel-item",t.parentNode):[],this._items.indexOf(t)}_getItemByOrder(t,e){const i=t===Q;return v(this._items,e,i,this._config.wrap)}_triggerSlideEvent(t,e){const i=this._getItemIndex(t),n=this._getItemIndex(V.findOne(nt,this._element));return j.trigger(this._element,"slide.bs.carousel",{relatedTarget:t,direction:e,from:n,to:i})}_setActiveIndicatorElement(t){if(this._indicatorsElement){const e=V.findOne(".active",this._indicatorsElement);e.classList.remove(it),e.removeAttribute("aria-current");const i=V.find("[data-bs-target]",this._indicatorsElement);for(let e=0;e{j.trigger(this._element,et,{relatedTarget:o,direction:d,from:s,to:r})};if(this._element.classList.contains("slide")){o.classList.add(h),u(o),n.classList.add(c),o.classList.add(c);const t=()=>{o.classList.remove(c,h),o.classList.add(it),n.classList.remove(it,h,c),this._isSliding=!1,setTimeout(f,0)};this._queueCallback(t,n,!0)}else n.classList.remove(it),o.classList.add(it),this._isSliding=!1,f();a&&this.cycle()}_directionToOrder(t){return[J,Z].includes(t)?m()?t===Z?G:Q:t===Z?Q:G:t}_orderToDirection(t){return[Q,G].includes(t)?m()?t===G?Z:J:t===G?J:Z:t}static carouselInterface(t,e){const i=st.getOrCreateInstance(t,e);let{_config:n}=i;"object"==typeof e&&(n={...n,...e});const s="string"==typeof e?e:n.slide;if("number"==typeof e)i.to(e);else if("string"==typeof s){if(void 0===i[s])throw new TypeError(`No method named "${s}"`);i[s]()}else n.interval&&n.ride&&(i.pause(),i.cycle())}static jQueryInterface(t){return this.each((function(){st.carouselInterface(this,t)}))}static dataApiClickHandler(t){const e=n(this);if(!e||!e.classList.contains("carousel"))return;const i={...U.getDataAttributes(e),...U.getDataAttributes(this)},s=this.getAttribute("data-bs-slide-to");s&&(i.interval=!1),st.carouselInterface(e,i),s&&st.getInstance(e).to(s),t.preventDefault()}}j.on(document,"click.bs.carousel.data-api","[data-bs-slide], [data-bs-slide-to]",st.dataApiClickHandler),j.on(window,"load.bs.carousel.data-api",(()=>{const t=V.find('[data-bs-ride="carousel"]');for(let e=0,i=t.length;et===this._element));null!==s&&o.length&&(this._selector=s,this._triggerArray.push(e))}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return rt}static get NAME(){return ot}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t,e=[];if(this._config.parent){const t=V.find(ut,this._config.parent);e=V.find(".collapse.show, .collapse.collapsing",this._config.parent).filter((e=>!t.includes(e)))}const i=V.findOne(this._selector);if(e.length){const n=e.find((t=>i!==t));if(t=n?pt.getInstance(n):null,t&&t._isTransitioning)return}if(j.trigger(this._element,"show.bs.collapse").defaultPrevented)return;e.forEach((e=>{i!==e&&pt.getOrCreateInstance(e,{toggle:!1}).hide(),t||H.set(e,"bs.collapse",null)}));const n=this._getDimension();this._element.classList.remove(ct),this._element.classList.add(ht),this._element.style[n]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const s=`scroll${n[0].toUpperCase()+n.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct,lt),this._element.style[n]="",j.trigger(this._element,"shown.bs.collapse")}),this._element,!0),this._element.style[n]=`${this._element[s]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(j.trigger(this._element,"hide.bs.collapse").defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,u(this._element),this._element.classList.add(ht),this._element.classList.remove(ct,lt);const e=this._triggerArray.length;for(let t=0;t{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct),j.trigger(this._element,"hidden.bs.collapse")}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(lt)}_getConfig(t){return(t={...rt,...U.getDataAttributes(this._element),...t}).toggle=Boolean(t.toggle),t.parent=r(t.parent),a(ot,t,at),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=V.find(ut,this._config.parent);V.find(ft,this._config.parent).filter((e=>!t.includes(e))).forEach((t=>{const e=n(t);e&&this._addAriaAndCollapsedClass([t],this._isShown(e))}))}_addAriaAndCollapsedClass(t,e){t.length&&t.forEach((t=>{e?t.classList.remove(dt):t.classList.add(dt),t.setAttribute("aria-expanded",e)}))}static jQueryInterface(t){return this.each((function(){const e={};"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1);const i=pt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}j.on(document,"click.bs.collapse.data-api",ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();const e=i(this);V.find(e).forEach((t=>{pt.getOrCreateInstance(t,{toggle:!1}).toggle()}))})),g(pt);var mt="top",gt="bottom",_t="right",bt="left",vt="auto",yt=[mt,gt,_t,bt],wt="start",Et="end",At="clippingParents",Tt="viewport",Ot="popper",Ct="reference",kt=yt.reduce((function(t,e){return t.concat([e+"-"+wt,e+"-"+Et])}),[]),Lt=[].concat(yt,[vt]).reduce((function(t,e){return t.concat([e,e+"-"+wt,e+"-"+Et])}),[]),xt="beforeRead",Dt="read",St="afterRead",Nt="beforeMain",It="main",Pt="afterMain",jt="beforeWrite",Mt="write",Ht="afterWrite",Bt=[xt,Dt,St,Nt,It,Pt,jt,Mt,Ht];function Rt(t){return t?(t.nodeName||"").toLowerCase():null}function Wt(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function $t(t){return t instanceof Wt(t).Element||t instanceof Element}function zt(t){return t instanceof Wt(t).HTMLElement||t instanceof HTMLElement}function qt(t){return"undefined"!=typeof ShadowRoot&&(t instanceof Wt(t).ShadowRoot||t instanceof ShadowRoot)}const Ft={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];zt(s)&&Rt(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});zt(n)&&Rt(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function Ut(t){return t.split("-")[0]}function Vt(t,e){var i=t.getBoundingClientRect();return{width:i.width/1,height:i.height/1,top:i.top/1,right:i.right/1,bottom:i.bottom/1,left:i.left/1,x:i.left/1,y:i.top/1}}function Kt(t){var e=Vt(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Xt(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&qt(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function Yt(t){return Wt(t).getComputedStyle(t)}function Qt(t){return["table","td","th"].indexOf(Rt(t))>=0}function Gt(t){return(($t(t)?t.ownerDocument:t.document)||window.document).documentElement}function Zt(t){return"html"===Rt(t)?t:t.assignedSlot||t.parentNode||(qt(t)?t.host:null)||Gt(t)}function Jt(t){return zt(t)&&"fixed"!==Yt(t).position?t.offsetParent:null}function te(t){for(var e=Wt(t),i=Jt(t);i&&Qt(i)&&"static"===Yt(i).position;)i=Jt(i);return i&&("html"===Rt(i)||"body"===Rt(i)&&"static"===Yt(i).position)?e:i||function(t){var e=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&zt(t)&&"fixed"===Yt(t).position)return null;for(var i=Zt(t);zt(i)&&["html","body"].indexOf(Rt(i))<0;){var n=Yt(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function ee(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}var ie=Math.max,ne=Math.min,se=Math.round;function oe(t,e,i){return ie(t,ne(e,i))}function re(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function ae(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const le={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=Ut(i.placement),l=ee(a),c=[bt,_t].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return re("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:ae(t,yt))}(s.padding,i),d=Kt(o),u="y"===l?mt:bt,f="y"===l?gt:_t,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=te(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,E=oe(v,w,y),A=l;i.modifiersData[n]=((e={})[A]=E,e.centerOffset=E-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Xt(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function ce(t){return t.split("-")[1]}var he={top:"auto",right:"auto",bottom:"auto",left:"auto"};function de(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=!0===h?function(t){var e=t.x,i=t.y,n=window.devicePixelRatio||1;return{x:se(se(e*n)/n)||0,y:se(se(i*n)/n)||0}}(r):"function"==typeof h?h(r):r,u=d.x,f=void 0===u?0:u,p=d.y,m=void 0===p?0:p,g=r.hasOwnProperty("x"),_=r.hasOwnProperty("y"),b=bt,v=mt,y=window;if(c){var w=te(i),E="clientHeight",A="clientWidth";w===Wt(i)&&"static"!==Yt(w=Gt(i)).position&&"absolute"===a&&(E="scrollHeight",A="scrollWidth"),w=w,s!==mt&&(s!==bt&&s!==_t||o!==Et)||(v=gt,m-=w[E]-n.height,m*=l?1:-1),s!==bt&&(s!==mt&&s!==gt||o!==Et)||(b=_t,f-=w[A]-n.width,f*=l?1:-1)}var T,O=Object.assign({position:a},c&&he);return l?Object.assign({},O,((T={})[v]=_?"0":"",T[b]=g?"0":"",T.transform=(y.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",T)):Object.assign({},O,((e={})[v]=_?m+"px":"",e[b]=g?f+"px":"",e.transform="",e))}const ue={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:Ut(e.placement),variation:ce(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,de(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,de(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var fe={passive:!0};const pe={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=Wt(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,fe)})),a&&l.addEventListener("resize",i.update,fe),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,fe)})),a&&l.removeEventListener("resize",i.update,fe)}},data:{}};var me={left:"right",right:"left",bottom:"top",top:"bottom"};function ge(t){return t.replace(/left|right|bottom|top/g,(function(t){return me[t]}))}var _e={start:"end",end:"start"};function be(t){return t.replace(/start|end/g,(function(t){return _e[t]}))}function ve(t){var e=Wt(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function ye(t){return Vt(Gt(t)).left+ve(t).scrollLeft}function we(t){var e=Yt(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ee(t){return["html","body","#document"].indexOf(Rt(t))>=0?t.ownerDocument.body:zt(t)&&we(t)?t:Ee(Zt(t))}function Ae(t,e){var i;void 0===e&&(e=[]);var n=Ee(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=Wt(n),r=s?[o].concat(o.visualViewport||[],we(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Ae(Zt(r)))}function Te(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function Oe(t,e){return e===Tt?Te(function(t){var e=Wt(t),i=Gt(t),n=e.visualViewport,s=i.clientWidth,o=i.clientHeight,r=0,a=0;return n&&(s=n.width,o=n.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(r=n.offsetLeft,a=n.offsetTop)),{width:s,height:o,x:r+ye(t),y:a}}(t)):zt(e)?function(t){var e=Vt(t);return e.top=e.top+t.clientTop,e.left=e.left+t.clientLeft,e.bottom=e.top+t.clientHeight,e.right=e.left+t.clientWidth,e.width=t.clientWidth,e.height=t.clientHeight,e.x=e.left,e.y=e.top,e}(e):Te(function(t){var e,i=Gt(t),n=ve(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ie(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ie(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+ye(t),l=-n.scrollTop;return"rtl"===Yt(s||i).direction&&(a+=ie(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Gt(t)))}function Ce(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?Ut(s):null,r=s?ce(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case mt:e={x:a,y:i.y-n.height};break;case gt:e={x:a,y:i.y+i.height};break;case _t:e={x:i.x+i.width,y:l};break;case bt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?ee(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case wt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Et:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ke(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.boundary,r=void 0===o?At:o,a=i.rootBoundary,l=void 0===a?Tt:a,c=i.elementContext,h=void 0===c?Ot:c,d=i.altBoundary,u=void 0!==d&&d,f=i.padding,p=void 0===f?0:f,m=re("number"!=typeof p?p:ae(p,yt)),g=h===Ot?Ct:Ot,_=t.rects.popper,b=t.elements[u?g:h],v=function(t,e,i){var n="clippingParents"===e?function(t){var e=Ae(Zt(t)),i=["absolute","fixed"].indexOf(Yt(t).position)>=0&&zt(t)?te(t):t;return $t(i)?e.filter((function(t){return $t(t)&&Xt(t,i)&&"body"!==Rt(t)})):[]}(t):[].concat(e),s=[].concat(n,[i]),o=s[0],r=s.reduce((function(e,i){var n=Oe(t,i);return e.top=ie(n.top,e.top),e.right=ne(n.right,e.right),e.bottom=ne(n.bottom,e.bottom),e.left=ie(n.left,e.left),e}),Oe(t,o));return r.width=r.right-r.left,r.height=r.bottom-r.top,r.x=r.left,r.y=r.top,r}($t(b)?b:b.contextElement||Gt(t.elements.popper),r,l),y=Vt(t.elements.reference),w=Ce({reference:y,element:_,strategy:"absolute",placement:s}),E=Te(Object.assign({},_,w)),A=h===Ot?E:y,T={top:v.top-A.top+m.top,bottom:A.bottom-v.bottom+m.bottom,left:v.left-A.left+m.left,right:A.right-v.right+m.right},O=t.modifiersData.offset;if(h===Ot&&O){var C=O[s];Object.keys(T).forEach((function(t){var e=[_t,gt].indexOf(t)>=0?1:-1,i=[mt,gt].indexOf(t)>=0?"y":"x";T[t]+=C[i]*e}))}return T}function Le(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?Lt:l,h=ce(n),d=h?a?kt:kt.filter((function(t){return ce(t)===h})):yt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ke(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[Ut(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const xe={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=Ut(g),b=l||(_!==g&&p?function(t){if(Ut(t)===vt)return[];var e=ge(t);return[be(t),e,be(e)]}(g):[ge(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(Ut(i)===vt?Le(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,E=new Map,A=!0,T=v[0],O=0;O=0,D=x?"width":"height",S=ke(e,{placement:C,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),N=x?L?_t:bt:L?gt:mt;y[D]>w[D]&&(N=ge(N));var I=ge(N),P=[];if(o&&P.push(S[k]<=0),a&&P.push(S[N]<=0,S[I]<=0),P.every((function(t){return t}))){T=C,A=!1;break}E.set(C,P)}if(A)for(var j=function(t){var e=v.find((function(e){var i=E.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},M=p?3:1;M>0&&"break"!==j(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function De(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function Se(t){return[mt,_t,gt,bt].some((function(e){return t[e]>=0}))}const Ne={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ke(e,{elementContext:"reference"}),a=ke(e,{altBoundary:!0}),l=De(r,n),c=De(a,s,o),h=Se(l),d=Se(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},Ie={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=Lt.reduce((function(t,i){return t[i]=function(t,e,i){var n=Ut(t),s=[bt,mt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[bt,_t].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},Pe={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=Ce({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},je={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ke(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=Ut(e.placement),b=ce(e.placement),v=!b,y=ee(_),w="x"===y?"y":"x",E=e.modifiersData.popperOffsets,A=e.rects.reference,T=e.rects.popper,O="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,C={x:0,y:0};if(E){if(o||a){var k="y"===y?mt:bt,L="y"===y?gt:_t,x="y"===y?"height":"width",D=E[y],S=E[y]+g[k],N=E[y]-g[L],I=f?-T[x]/2:0,P=b===wt?A[x]:T[x],j=b===wt?-T[x]:-A[x],M=e.elements.arrow,H=f&&M?Kt(M):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},R=B[k],W=B[L],$=oe(0,A[x],H[x]),z=v?A[x]/2-I-$-R-O:P-$-R-O,q=v?-A[x]/2+I+$+W+O:j+$+W+O,F=e.elements.arrow&&te(e.elements.arrow),U=F?"y"===y?F.clientTop||0:F.clientLeft||0:0,V=e.modifiersData.offset?e.modifiersData.offset[e.placement][y]:0,K=E[y]+z-V-U,X=E[y]+q-V;if(o){var Y=oe(f?ne(S,K):S,D,f?ie(N,X):N);E[y]=Y,C[y]=Y-D}if(a){var Q="x"===y?mt:bt,G="x"===y?gt:_t,Z=E[w],J=Z+g[Q],tt=Z-g[G],et=oe(f?ne(J,K):J,Z,f?ie(tt,X):tt);E[w]=et,C[w]=et-Z}}e.modifiersData[n]=C}},requiresIfExists:["offset"]};function Me(t,e,i){void 0===i&&(i=!1);var n=zt(e);zt(e)&&function(t){var e=t.getBoundingClientRect();e.width,t.offsetWidth,e.height,t.offsetHeight}(e);var s,o,r=Gt(e),a=Vt(t),l={scrollLeft:0,scrollTop:0},c={x:0,y:0};return(n||!n&&!i)&&(("body"!==Rt(e)||we(r))&&(l=(s=e)!==Wt(s)&&zt(s)?{scrollLeft:(o=s).scrollLeft,scrollTop:o.scrollTop}:ve(s)),zt(e)?((c=Vt(e)).x+=e.clientLeft,c.y+=e.clientTop):r&&(c.x=ye(r))),{x:a.left+l.scrollLeft-c.x,y:a.top+l.scrollTop-c.y,width:a.width,height:a.height}}function He(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var Be={placement:"bottom",modifiers:[],strategy:"absolute"};function Re(){for(var t=arguments.length,e=new Array(t),i=0;ij.on(t,"mouseover",d))),this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(Je),this._element.classList.add(Je),j.trigger(this._element,"shown.bs.dropdown",t)}hide(){if(c(this._element)||!this._isShown(this._menu))return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){j.trigger(this._element,"hide.bs.dropdown",t).defaultPrevented||("ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._popper&&this._popper.destroy(),this._menu.classList.remove(Je),this._element.classList.remove(Je),this._element.setAttribute("aria-expanded","false"),U.removeDataAttribute(this._menu,"popper"),j.trigger(this._element,"hidden.bs.dropdown",t))}_getConfig(t){if(t={...this.constructor.Default,...U.getDataAttributes(this._element),...t},a(Ue,t,this.constructor.DefaultType),"object"==typeof t.reference&&!o(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Ue.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(t){if(void 0===Fe)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let e=this._element;"parent"===this._config.reference?e=t:o(this._config.reference)?e=r(this._config.reference):"object"==typeof this._config.reference&&(e=this._config.reference);const i=this._getPopperConfig(),n=i.modifiers.find((t=>"applyStyles"===t.name&&!1===t.enabled));this._popper=qe(e,this._menu,i),n&&U.setDataAttribute(this._menu,"popper","static")}_isShown(t=this._element){return t.classList.contains(Je)}_getMenuElement(){return V.next(this._element,ei)[0]}_getPlacement(){const t=this._element.parentNode;if(t.classList.contains("dropend"))return ri;if(t.classList.contains("dropstart"))return ai;const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?ni:ii:e?oi:si}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return"static"===this._config.display&&(t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,..."function"==typeof this._config.popperConfig?this._config.popperConfig(t):this._config.popperConfig}}_selectMenuItem({key:t,target:e}){const i=V.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(l);i.length&&v(i,e,t===Ye,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(t&&(2===t.button||"keyup"===t.type&&"Tab"!==t.key))return;const e=V.find(ti);for(let i=0,n=e.length;ie+t)),this._setElementAttributes(di,"paddingRight",(e=>e+t)),this._setElementAttributes(ui,"marginRight",(e=>e-t))}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t)[e];t.style[e]=`${i(Number.parseFloat(s))}px`}))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,"paddingRight"),this._resetElementAttributes(di,"paddingRight"),this._resetElementAttributes(ui,"marginRight")}_saveInitialAttribute(t,e){const i=t.style[e];i&&U.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=U.getDataAttribute(t,e);void 0===i?t.style.removeProperty(e):(U.removeDataAttribute(t,e),t.style[e]=i)}))}_applyManipulationCallback(t,e){o(t)?e(t):V.find(t,this._element).forEach(e)}isOverflowing(){return this.getWidth()>0}}const pi={className:"modal-backdrop",isVisible:!0,isAnimated:!1,rootElement:"body",clickCallback:null},mi={className:"string",isVisible:"boolean",isAnimated:"boolean",rootElement:"(element|string)",clickCallback:"(function|null)"},gi="show",_i="mousedown.bs.backdrop";class bi{constructor(t){this._config=this._getConfig(t),this._isAppended=!1,this._element=null}show(t){this._config.isVisible?(this._append(),this._config.isAnimated&&u(this._getElement()),this._getElement().classList.add(gi),this._emulateAnimation((()=>{_(t)}))):_(t)}hide(t){this._config.isVisible?(this._getElement().classList.remove(gi),this._emulateAnimation((()=>{this.dispose(),_(t)}))):_(t)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_getConfig(t){return(t={...pi,..."object"==typeof t?t:{}}).rootElement=r(t.rootElement),a("backdrop",t,mi),t}_append(){this._isAppended||(this._config.rootElement.append(this._getElement()),j.on(this._getElement(),_i,(()=>{_(this._config.clickCallback)})),this._isAppended=!0)}dispose(){this._isAppended&&(j.off(this._element,_i),this._element.remove(),this._isAppended=!1)}_emulateAnimation(t){b(t,this._getElement(),this._config.isAnimated)}}const vi={trapElement:null,autofocus:!0},yi={trapElement:"element",autofocus:"boolean"},wi=".bs.focustrap",Ei="backward";class Ai{constructor(t){this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}activate(){const{trapElement:t,autofocus:e}=this._config;this._isActive||(e&&t.focus(),j.off(document,wi),j.on(document,"focusin.bs.focustrap",(t=>this._handleFocusin(t))),j.on(document,"keydown.tab.bs.focustrap",(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,j.off(document,wi))}_handleFocusin(t){const{target:e}=t,{trapElement:i}=this._config;if(e===document||e===i||i.contains(e))return;const n=V.focusableChildren(i);0===n.length?i.focus():this._lastTabNavDirection===Ei?n[n.length-1].focus():n[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?Ei:"forward")}_getConfig(t){return t={...vi,..."object"==typeof t?t:{}},a("focustrap",t,yi),t}}const Ti="modal",Oi="Escape",Ci={backdrop:!0,keyboard:!0,focus:!0},ki={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean"},Li="hidden.bs.modal",xi="show.bs.modal",Di="resize.bs.modal",Si="click.dismiss.bs.modal",Ni="keydown.dismiss.bs.modal",Ii="mousedown.dismiss.bs.modal",Pi="modal-open",ji="show",Mi="modal-static";class Hi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._dialog=V.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._scrollBar=new fi}static get Default(){return Ci}static get NAME(){return Ti}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||j.trigger(this._element,xi,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isAnimated()&&(this._isTransitioning=!0),this._scrollBar.hide(),document.body.classList.add(Pi),this._adjustDialog(),this._setEscapeEvent(),this._setResizeEvent(),j.on(this._dialog,Ii,(()=>{j.one(this._element,"mouseup.dismiss.bs.modal",(t=>{t.target===this._element&&(this._ignoreBackdropClick=!0)}))})),this._showBackdrop((()=>this._showElement(t))))}hide(){if(!this._isShown||this._isTransitioning)return;if(j.trigger(this._element,"hide.bs.modal").defaultPrevented)return;this._isShown=!1;const t=this._isAnimated();t&&(this._isTransitioning=!0),this._setEscapeEvent(),this._setResizeEvent(),this._focustrap.deactivate(),this._element.classList.remove(ji),j.off(this._element,Si),j.off(this._dialog,Ii),this._queueCallback((()=>this._hideModal()),this._element,t)}dispose(){[window,this._dialog].forEach((t=>j.off(t,".bs.modal"))),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new bi({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_getConfig(t){return t={...Ci,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Ti,t,ki),t}_showElement(t){const e=this._isAnimated(),i=V.findOne(".modal-body",this._dialog);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0,i&&(i.scrollTop=0),e&&u(this._element),this._element.classList.add(ji),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,j.trigger(this._element,"shown.bs.modal",{relatedTarget:t})}),this._dialog,e)}_setEscapeEvent(){this._isShown?j.on(this._element,Ni,(t=>{this._config.keyboard&&t.key===Oi?(t.preventDefault(),this.hide()):this._config.keyboard||t.key!==Oi||this._triggerBackdropTransition()})):j.off(this._element,Ni)}_setResizeEvent(){this._isShown?j.on(window,Di,(()=>this._adjustDialog())):j.off(window,Di)}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(Pi),this._resetAdjustments(),this._scrollBar.reset(),j.trigger(this._element,Li)}))}_showBackdrop(t){j.on(this._element,Si,(t=>{this._ignoreBackdropClick?this._ignoreBackdropClick=!1:t.target===t.currentTarget&&(!0===this._config.backdrop?this.hide():"static"===this._config.backdrop&&this._triggerBackdropTransition())})),this._backdrop.show(t)}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(j.trigger(this._element,"hidePrevented.bs.modal").defaultPrevented)return;const{classList:t,scrollHeight:e,style:i}=this._element,n=e>document.documentElement.clientHeight;!n&&"hidden"===i.overflowY||t.contains(Mi)||(n||(i.overflowY="hidden"),t.add(Mi),this._queueCallback((()=>{t.remove(Mi),n||this._queueCallback((()=>{i.overflowY=""}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;(!i&&t&&!m()||i&&!t&&m())&&(this._element.style.paddingLeft=`${e}px`),(i&&!t&&!m()||!i&&t&&m())&&(this._element.style.paddingRight=`${e}px`)}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=Hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}j.on(document,"click.bs.modal.data-api",'[data-bs-toggle="modal"]',(function(t){const e=n(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),j.one(e,xi,(t=>{t.defaultPrevented||j.one(e,Li,(()=>{l(this)&&this.focus()}))}));const i=V.findOne(".modal.show");i&&Hi.getInstance(i).hide(),Hi.getOrCreateInstance(e).toggle(this)})),R(Hi),g(Hi);const Bi="offcanvas",Ri={backdrop:!0,keyboard:!0,scroll:!1},Wi={backdrop:"boolean",keyboard:"boolean",scroll:"boolean"},$i="show",zi=".offcanvas.show",qi="hidden.bs.offcanvas";class Fi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get NAME(){return Bi}static get Default(){return Ri}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||j.trigger(this._element,"show.bs.offcanvas",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._element.style.visibility="visible",this._backdrop.show(),this._config.scroll||(new fi).hide(),this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add($i),this._queueCallback((()=>{this._config.scroll||this._focustrap.activate(),j.trigger(this._element,"shown.bs.offcanvas",{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(j.trigger(this._element,"hide.bs.offcanvas").defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.remove($i),this._backdrop.hide(),this._queueCallback((()=>{this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._element.style.visibility="hidden",this._config.scroll||(new fi).reset(),j.trigger(this._element,qi)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_getConfig(t){return t={...Ri,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Bi,t,Wi),t}_initializeBackDrop(){return new bi({className:"offcanvas-backdrop",isVisible:this._config.backdrop,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:()=>this.hide()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_addEventListeners(){j.on(this._element,"keydown.dismiss.bs.offcanvas",(t=>{this._config.keyboard&&"Escape"===t.key&&this.hide()}))}static jQueryInterface(t){return this.each((function(){const e=Fi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}j.on(document,"click.bs.offcanvas.data-api",'[data-bs-toggle="offcanvas"]',(function(t){const e=n(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this))return;j.one(e,qi,(()=>{l(this)&&this.focus()}));const i=V.findOne(zi);i&&i!==e&&Fi.getInstance(i).hide(),Fi.getOrCreateInstance(e).toggle(this)})),j.on(window,"load.bs.offcanvas.data-api",(()=>V.find(zi).forEach((t=>Fi.getOrCreateInstance(t).show())))),R(Fi),g(Fi);const Ui=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Vi=/^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i,Ki=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i,Xi=(t,e)=>{const i=t.nodeName.toLowerCase();if(e.includes(i))return!Ui.has(i)||Boolean(Vi.test(t.nodeValue)||Ki.test(t.nodeValue));const n=e.filter((t=>t instanceof RegExp));for(let t=0,e=n.length;t{Xi(t,r)||i.removeAttribute(t.nodeName)}))}return n.body.innerHTML}const Qi="tooltip",Gi=new Set(["sanitize","allowList","sanitizeFn"]),Zi={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(array|string|function)",container:"(string|element|boolean)",fallbackPlacements:"array",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",allowList:"object",popperConfig:"(null|object|function)"},Ji={AUTO:"auto",TOP:"top",RIGHT:m()?"left":"right",BOTTOM:"bottom",LEFT:m()?"right":"left"},tn={animation:!0,template:'',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:[0,0],container:!1,fallbackPlacements:["top","right","bottom","left"],boundary:"clippingParents",customClass:"",sanitize:!0,sanitizeFn:null,allowList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},en={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},nn="fade",sn="show",on="show",rn="out",an=".tooltip-inner",ln=".modal",cn="hide.bs.modal",hn="hover",dn="focus";class un extends B{constructor(t,e){if(void 0===Fe)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this._config=this._getConfig(e),this.tip=null,this._setListeners()}static get Default(){return tn}static get NAME(){return Qi}static get Event(){return en}static get DefaultType(){return Zi}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(t){if(this._isEnabled)if(t){const e=this._initializeOnDelegatedTarget(t);e._activeTrigger.click=!e._activeTrigger.click,e._isWithActiveTrigger()?e._enter(null,e):e._leave(null,e)}else{if(this.getTipElement().classList.contains(sn))return void this._leave(null,this);this._enter(null,this)}}dispose(){clearTimeout(this._timeout),j.off(this._element.closest(ln),cn,this._hideModalHandler),this.tip&&this.tip.remove(),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this.isWithContent()||!this._isEnabled)return;const t=j.trigger(this._element,this.constructor.Event.SHOW),e=h(this._element),i=null===e?this._element.ownerDocument.documentElement.contains(this._element):e.contains(this._element);if(t.defaultPrevented||!i)return;"tooltip"===this.constructor.NAME&&this.tip&&this.getTitle()!==this.tip.querySelector(an).innerHTML&&(this._disposePopper(),this.tip.remove(),this.tip=null);const n=this.getTipElement(),s=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME);n.setAttribute("id",s),this._element.setAttribute("aria-describedby",s),this._config.animation&&n.classList.add(nn);const o="function"==typeof this._config.placement?this._config.placement.call(this,n,this._element):this._config.placement,r=this._getAttachment(o);this._addAttachmentClass(r);const{container:a}=this._config;H.set(n,this.constructor.DATA_KEY,this),this._element.ownerDocument.documentElement.contains(this.tip)||(a.append(n),j.trigger(this._element,this.constructor.Event.INSERTED)),this._popper?this._popper.update():this._popper=qe(this._element,n,this._getPopperConfig(r)),n.classList.add(sn);const l=this._resolvePossibleFunction(this._config.customClass);l&&n.classList.add(...l.split(" ")),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>{j.on(t,"mouseover",d)}));const c=this.tip.classList.contains(nn);this._queueCallback((()=>{const t=this._hoverState;this._hoverState=null,j.trigger(this._element,this.constructor.Event.SHOWN),t===rn&&this._leave(null,this)}),this.tip,c)}hide(){if(!this._popper)return;const t=this.getTipElement();if(j.trigger(this._element,this.constructor.Event.HIDE).defaultPrevented)return;t.classList.remove(sn),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1;const e=this.tip.classList.contains(nn);this._queueCallback((()=>{this._isWithActiveTrigger()||(this._hoverState!==on&&t.remove(),this._cleanTipClass(),this._element.removeAttribute("aria-describedby"),j.trigger(this._element,this.constructor.Event.HIDDEN),this._disposePopper())}),this.tip,e),this._hoverState=""}update(){null!==this._popper&&this._popper.update()}isWithContent(){return Boolean(this.getTitle())}getTipElement(){if(this.tip)return this.tip;const t=document.createElement("div");t.innerHTML=this._config.template;const e=t.children[0];return this.setContent(e),e.classList.remove(nn,sn),this.tip=e,this.tip}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),an)}_sanitizeAndSetContent(t,e,i){const n=V.findOne(i,t);e||!n?this.setElementContent(n,e):n.remove()}setElementContent(t,e){if(null!==t)return o(e)?(e=r(e),void(this._config.html?e.parentNode!==t&&(t.innerHTML="",t.append(e)):t.textContent=e.textContent)):void(this._config.html?(this._config.sanitize&&(e=Yi(e,this._config.allowList,this._config.sanitizeFn)),t.innerHTML=e):t.textContent=e)}getTitle(){const t=this._element.getAttribute("data-bs-original-title")||this._config.title;return this._resolvePossibleFunction(t)}updateAttachment(t){return"right"===t?"end":"left"===t?"start":t}_initializeOnDelegatedTarget(t,e){return e||this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return"function"==typeof t?t.call(this._element):t}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"onChange",enabled:!0,phase:"afterWrite",fn:t=>this._handlePopperPlacementChange(t)}],onFirstUpdate:t=>{t.options.placement!==t.placement&&this._handlePopperPlacementChange(t)}};return{...e,..."function"==typeof this._config.popperConfig?this._config.popperConfig(e):this._config.popperConfig}}_addAttachmentClass(t){this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(t)}`)}_getAttachment(t){return Ji[t.toUpperCase()]}_setListeners(){this._config.trigger.split(" ").forEach((t=>{if("click"===t)j.on(this._element,this.constructor.Event.CLICK,this._config.selector,(t=>this.toggle(t)));else if("manual"!==t){const e=t===hn?this.constructor.Event.MOUSEENTER:this.constructor.Event.FOCUSIN,i=t===hn?this.constructor.Event.MOUSELEAVE:this.constructor.Event.FOCUSOUT;j.on(this._element,e,this._config.selector,(t=>this._enter(t))),j.on(this._element,i,this._config.selector,(t=>this._leave(t)))}})),this._hideModalHandler=()=>{this._element&&this.hide()},j.on(this._element.closest(ln),cn,this._hideModalHandler),this._config.selector?this._config={...this._config,trigger:"manual",selector:""}:this._fixTitle()}_fixTitle(){const t=this._element.getAttribute("title"),e=typeof this._element.getAttribute("data-bs-original-title");(t||"string"!==e)&&(this._element.setAttribute("data-bs-original-title",t||""),!t||this._element.getAttribute("aria-label")||this._element.textContent||this._element.setAttribute("aria-label",t),this._element.setAttribute("title",""))}_enter(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusin"===t.type?dn:hn]=!0),e.getTipElement().classList.contains(sn)||e._hoverState===on?e._hoverState=on:(clearTimeout(e._timeout),e._hoverState=on,e._config.delay&&e._config.delay.show?e._timeout=setTimeout((()=>{e._hoverState===on&&e.show()}),e._config.delay.show):e.show())}_leave(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusout"===t.type?dn:hn]=e._element.contains(t.relatedTarget)),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=rn,e._config.delay&&e._config.delay.hide?e._timeout=setTimeout((()=>{e._hoverState===rn&&e.hide()}),e._config.delay.hide):e.hide())}_isWithActiveTrigger(){for(const t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1}_getConfig(t){const e=U.getDataAttributes(this._element);return Object.keys(e).forEach((t=>{Gi.has(t)&&delete e[t]})),(t={...this.constructor.Default,...e,..."object"==typeof t&&t?t:{}}).container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),a(Qi,t,this.constructor.DefaultType),t.sanitize&&(t.template=Yi(t.template,t.allowList,t.sanitizeFn)),t}_getDelegateConfig(){const t={};for(const e in this._config)this.constructor.Default[e]!==this._config[e]&&(t[e]=this._config[e]);return t}_cleanTipClass(){const t=this.getTipElement(),e=new RegExp(`(^|\\s)${this._getBasicClassPrefix()}\\S+`,"g"),i=t.getAttribute("class").match(e);null!==i&&i.length>0&&i.map((t=>t.trim())).forEach((e=>t.classList.remove(e)))}_getBasicClassPrefix(){return"bs-tooltip"}_handlePopperPlacementChange(t){const{state:e}=t;e&&(this.tip=e.elements.popper,this._cleanTipClass(),this._addAttachmentClass(this._getAttachment(e.placement)))}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null)}static jQueryInterface(t){return this.each((function(){const e=un.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(un);const fn={...un.Default,placement:"right",offset:[0,8],trigger:"click",content:"",template:''},pn={...un.DefaultType,content:"(string|element|function)"},mn={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"};class gn extends un{static get Default(){return fn}static get NAME(){return"popover"}static get Event(){return mn}static get DefaultType(){return pn}isWithContent(){return this.getTitle()||this._getContent()}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),".popover-header"),this._sanitizeAndSetContent(t,this._getContent(),".popover-body")}_getContent(){return this._resolvePossibleFunction(this._config.content)}_getBasicClassPrefix(){return"bs-popover"}static jQueryInterface(t){return this.each((function(){const e=gn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(gn);const _n="scrollspy",bn={offset:10,method:"auto",target:""},vn={offset:"number",method:"string",target:"(string|element)"},yn="active",wn=".nav-link, .list-group-item, .dropdown-item",En="position";class An extends B{constructor(t,e){super(t),this._scrollElement="BODY"===this._element.tagName?window:this._element,this._config=this._getConfig(e),this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,j.on(this._scrollElement,"scroll.bs.scrollspy",(()=>this._process())),this.refresh(),this._process()}static get Default(){return bn}static get NAME(){return _n}refresh(){const t=this._scrollElement===this._scrollElement.window?"offset":En,e="auto"===this._config.method?t:this._config.method,n=e===En?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),V.find(wn,this._config.target).map((t=>{const s=i(t),o=s?V.findOne(s):null;if(o){const t=o.getBoundingClientRect();if(t.width||t.height)return[U[e](o).top+n,s]}return null})).filter((t=>t)).sort(((t,e)=>t[0]-e[0])).forEach((t=>{this._offsets.push(t[0]),this._targets.push(t[1])}))}dispose(){j.off(this._scrollElement,".bs.scrollspy"),super.dispose()}_getConfig(t){return(t={...bn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}}).target=r(t.target)||document.documentElement,a(_n,t,vn),t}_getScrollTop(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop}_getScrollHeight(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)}_getOffsetHeight(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height}_process(){const t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),i=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=i){const t=this._targets[this._targets.length-1];this._activeTarget!==t&&this._activate(t)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(let e=this._offsets.length;e--;)this._activeTarget!==this._targets[e]&&t>=this._offsets[e]&&(void 0===this._offsets[e+1]||t`${e}[data-bs-target="${t}"],${e}[href="${t}"]`)),i=V.findOne(e.join(","),this._config.target);i.classList.add(yn),i.classList.contains("dropdown-item")?V.findOne(".dropdown-toggle",i.closest(".dropdown")).classList.add(yn):V.parents(i,".nav, .list-group").forEach((t=>{V.prev(t,".nav-link, .list-group-item").forEach((t=>t.classList.add(yn))),V.prev(t,".nav-item").forEach((t=>{V.children(t,".nav-link").forEach((t=>t.classList.add(yn)))}))})),j.trigger(this._scrollElement,"activate.bs.scrollspy",{relatedTarget:t})}_clear(){V.find(wn,this._config.target).filter((t=>t.classList.contains(yn))).forEach((t=>t.classList.remove(yn)))}static jQueryInterface(t){return this.each((function(){const e=An.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(window,"load.bs.scrollspy.data-api",(()=>{V.find('[data-bs-spy="scroll"]').forEach((t=>new An(t)))})),g(An);const Tn="active",On="fade",Cn="show",kn=".active",Ln=":scope > li > .active";class xn extends B{static get NAME(){return"tab"}show(){if(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&this._element.classList.contains(Tn))return;let t;const e=n(this._element),i=this._element.closest(".nav, .list-group");if(i){const e="UL"===i.nodeName||"OL"===i.nodeName?Ln:kn;t=V.find(e,i),t=t[t.length-1]}const s=t?j.trigger(t,"hide.bs.tab",{relatedTarget:this._element}):null;if(j.trigger(this._element,"show.bs.tab",{relatedTarget:t}).defaultPrevented||null!==s&&s.defaultPrevented)return;this._activate(this._element,i);const o=()=>{j.trigger(t,"hidden.bs.tab",{relatedTarget:this._element}),j.trigger(this._element,"shown.bs.tab",{relatedTarget:t})};e?this._activate(e,e.parentNode,o):o()}_activate(t,e,i){const n=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?V.children(e,kn):V.find(Ln,e))[0],s=i&&n&&n.classList.contains(On),o=()=>this._transitionComplete(t,n,i);n&&s?(n.classList.remove(Cn),this._queueCallback(o,t,!0)):o()}_transitionComplete(t,e,i){if(e){e.classList.remove(Tn);const t=V.findOne(":scope > .dropdown-menu .active",e.parentNode);t&&t.classList.remove(Tn),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}t.classList.add(Tn),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),u(t),t.classList.contains(On)&&t.classList.add(Cn);let n=t.parentNode;if(n&&"LI"===n.nodeName&&(n=n.parentNode),n&&n.classList.contains("dropdown-menu")){const e=t.closest(".dropdown");e&&V.find(".dropdown-toggle",e).forEach((t=>t.classList.add(Tn))),t.setAttribute("aria-expanded",!0)}i&&i()}static jQueryInterface(t){return this.each((function(){const e=xn.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(document,"click.bs.tab.data-api",'[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this)||xn.getOrCreateInstance(this).show()})),g(xn);const Dn="toast",Sn="hide",Nn="show",In="showing",Pn={animation:"boolean",autohide:"boolean",delay:"number"},jn={animation:!0,autohide:!0,delay:5e3};class Mn extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get DefaultType(){return Pn}static get Default(){return jn}static get NAME(){return Dn}show(){j.trigger(this._element,"show.bs.toast").defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(Sn),u(this._element),this._element.classList.add(Nn),this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.remove(In),j.trigger(this._element,"shown.bs.toast"),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this._element.classList.contains(Nn)&&(j.trigger(this._element,"hide.bs.toast").defaultPrevented||(this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.add(Sn),this._element.classList.remove(In),this._element.classList.remove(Nn),j.trigger(this._element,"hidden.bs.toast")}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this._element.classList.contains(Nn)&&this._element.classList.remove(Nn),super.dispose()}_getConfig(t){return t={...jn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}},a(Dn,t,this.constructor.DefaultType),t}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){j.on(this._element,"mouseover.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"mouseout.bs.toast",(t=>this._onInteraction(t,!1))),j.on(this._element,"focusin.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"focusout.bs.toast",(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=Mn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(Mn),g(Mn),{Alert:W,Button:z,Carousel:st,Collapse:pt,Dropdown:hi,Modal:Hi,Offcanvas:Fi,Popover:gn,ScrollSpy:An,Tab:xn,Toast:Mn,Tooltip:un}})); -//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/docs/site_libs/clipboard/clipboard.min.js b/docs/site_libs/clipboard/clipboard.min.js deleted file mode 100644 index 41c6a0f7..00000000 --- a/docs/site_libs/clipboard/clipboard.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * clipboard.js v2.0.10 - * https://clipboardjs.com/ - * - * Licensed MIT © Zeno Rocha - */ -!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1.anchorjs-link,.anchorjs-link:focus{opacity:1}",u.sheet.cssRules.length),u.sheet.insertRule("[data-anchorjs-icon]::after{content:attr(data-anchorjs-icon)}",u.sheet.cssRules.length),u.sheet.insertRule('@font-face{font-family:anchorjs-icons;src:url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype")}',u.sheet.cssRules.length)),u=document.querySelectorAll("[id]"),t=[].map.call(u,function(A){return A.id}),i=0;i\]./()*\\\n\t\b\v\u00A0]/g,"-").replace(/-{2,}/g,"-").substring(0,this.options.truncate).replace(/^-+|-+$/gm,"").toLowerCase()},this.hasAnchorJSLink=function(A){var e=A.firstChild&&-1<(" "+A.firstChild.className+" ").indexOf(" anchorjs-link "),A=A.lastChild&&-1<(" "+A.lastChild.className+" ").indexOf(" anchorjs-link ");return e||A||!1}}}); -// @license-end \ No newline at end of file diff --git a/docs/site_libs/quarto-html/popper.min.js b/docs/site_libs/quarto-html/popper.min.js deleted file mode 100644 index 2269d669..00000000 --- a/docs/site_libs/quarto-html/popper.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/** - * @popperjs/core v2.11.4 - MIT License - */ - -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Popper={})}(this,(function(e){"use strict";function t(e){if(null==e)return window;if("[object Window]"!==e.toString()){var t=e.ownerDocument;return t&&t.defaultView||window}return e}function n(e){return e instanceof t(e).Element||e instanceof Element}function r(e){return e instanceof t(e).HTMLElement||e instanceof HTMLElement}function o(e){return"undefined"!=typeof ShadowRoot&&(e instanceof t(e).ShadowRoot||e instanceof ShadowRoot)}var i=Math.max,a=Math.min,s=Math.round;function f(e,t){void 0===t&&(t=!1);var n=e.getBoundingClientRect(),o=1,i=1;if(r(e)&&t){var a=e.offsetHeight,f=e.offsetWidth;f>0&&(o=s(n.width)/f||1),a>0&&(i=s(n.height)/a||1)}return{width:n.width/o,height:n.height/i,top:n.top/i,right:n.right/o,bottom:n.bottom/i,left:n.left/o,x:n.left/o,y:n.top/i}}function c(e){var n=t(e);return{scrollLeft:n.pageXOffset,scrollTop:n.pageYOffset}}function p(e){return e?(e.nodeName||"").toLowerCase():null}function u(e){return((n(e)?e.ownerDocument:e.document)||window.document).documentElement}function l(e){return f(u(e)).left+c(e).scrollLeft}function d(e){return t(e).getComputedStyle(e)}function h(e){var t=d(e),n=t.overflow,r=t.overflowX,o=t.overflowY;return/auto|scroll|overlay|hidden/.test(n+o+r)}function m(e,n,o){void 0===o&&(o=!1);var i,a,d=r(n),m=r(n)&&function(e){var t=e.getBoundingClientRect(),n=s(t.width)/e.offsetWidth||1,r=s(t.height)/e.offsetHeight||1;return 1!==n||1!==r}(n),v=u(n),g=f(e,m),y={scrollLeft:0,scrollTop:0},b={x:0,y:0};return(d||!d&&!o)&&(("body"!==p(n)||h(v))&&(y=(i=n)!==t(i)&&r(i)?{scrollLeft:(a=i).scrollLeft,scrollTop:a.scrollTop}:c(i)),r(n)?((b=f(n,!0)).x+=n.clientLeft,b.y+=n.clientTop):v&&(b.x=l(v))),{x:g.left+y.scrollLeft-b.x,y:g.top+y.scrollTop-b.y,width:g.width,height:g.height}}function v(e){var t=f(e),n=e.offsetWidth,r=e.offsetHeight;return Math.abs(t.width-n)<=1&&(n=t.width),Math.abs(t.height-r)<=1&&(r=t.height),{x:e.offsetLeft,y:e.offsetTop,width:n,height:r}}function g(e){return"html"===p(e)?e:e.assignedSlot||e.parentNode||(o(e)?e.host:null)||u(e)}function y(e){return["html","body","#document"].indexOf(p(e))>=0?e.ownerDocument.body:r(e)&&h(e)?e:y(g(e))}function b(e,n){var r;void 0===n&&(n=[]);var o=y(e),i=o===(null==(r=e.ownerDocument)?void 0:r.body),a=t(o),s=i?[a].concat(a.visualViewport||[],h(o)?o:[]):o,f=n.concat(s);return i?f:f.concat(b(g(s)))}function x(e){return["table","td","th"].indexOf(p(e))>=0}function w(e){return r(e)&&"fixed"!==d(e).position?e.offsetParent:null}function O(e){for(var n=t(e),i=w(e);i&&x(i)&&"static"===d(i).position;)i=w(i);return i&&("html"===p(i)||"body"===p(i)&&"static"===d(i).position)?n:i||function(e){var t=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&r(e)&&"fixed"===d(e).position)return null;var n=g(e);for(o(n)&&(n=n.host);r(n)&&["html","body"].indexOf(p(n))<0;){var i=d(n);if("none"!==i.transform||"none"!==i.perspective||"paint"===i.contain||-1!==["transform","perspective"].indexOf(i.willChange)||t&&"filter"===i.willChange||t&&i.filter&&"none"!==i.filter)return n;n=n.parentNode}return null}(e)||n}var j="top",E="bottom",D="right",A="left",L="auto",P=[j,E,D,A],M="start",k="end",W="viewport",B="popper",H=P.reduce((function(e,t){return e.concat([t+"-"+M,t+"-"+k])}),[]),T=[].concat(P,[L]).reduce((function(e,t){return e.concat([t,t+"-"+M,t+"-"+k])}),[]),R=["beforeRead","read","afterRead","beforeMain","main","afterMain","beforeWrite","write","afterWrite"];function S(e){var t=new Map,n=new Set,r=[];function o(e){n.add(e.name),[].concat(e.requires||[],e.requiresIfExists||[]).forEach((function(e){if(!n.has(e)){var r=t.get(e);r&&o(r)}})),r.push(e)}return e.forEach((function(e){t.set(e.name,e)})),e.forEach((function(e){n.has(e.name)||o(e)})),r}function C(e){return e.split("-")[0]}function q(e,t){var n=t.getRootNode&&t.getRootNode();if(e.contains(t))return!0;if(n&&o(n)){var r=t;do{if(r&&e.isSameNode(r))return!0;r=r.parentNode||r.host}while(r)}return!1}function V(e){return Object.assign({},e,{left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height})}function N(e,r){return r===W?V(function(e){var n=t(e),r=u(e),o=n.visualViewport,i=r.clientWidth,a=r.clientHeight,s=0,f=0;return o&&(i=o.width,a=o.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(s=o.offsetLeft,f=o.offsetTop)),{width:i,height:a,x:s+l(e),y:f}}(e)):n(r)?function(e){var t=f(e);return t.top=t.top+e.clientTop,t.left=t.left+e.clientLeft,t.bottom=t.top+e.clientHeight,t.right=t.left+e.clientWidth,t.width=e.clientWidth,t.height=e.clientHeight,t.x=t.left,t.y=t.top,t}(r):V(function(e){var t,n=u(e),r=c(e),o=null==(t=e.ownerDocument)?void 0:t.body,a=i(n.scrollWidth,n.clientWidth,o?o.scrollWidth:0,o?o.clientWidth:0),s=i(n.scrollHeight,n.clientHeight,o?o.scrollHeight:0,o?o.clientHeight:0),f=-r.scrollLeft+l(e),p=-r.scrollTop;return"rtl"===d(o||n).direction&&(f+=i(n.clientWidth,o?o.clientWidth:0)-a),{width:a,height:s,x:f,y:p}}(u(e)))}function I(e,t,o){var s="clippingParents"===t?function(e){var t=b(g(e)),o=["absolute","fixed"].indexOf(d(e).position)>=0&&r(e)?O(e):e;return n(o)?t.filter((function(e){return n(e)&&q(e,o)&&"body"!==p(e)})):[]}(e):[].concat(t),f=[].concat(s,[o]),c=f[0],u=f.reduce((function(t,n){var r=N(e,n);return t.top=i(r.top,t.top),t.right=a(r.right,t.right),t.bottom=a(r.bottom,t.bottom),t.left=i(r.left,t.left),t}),N(e,c));return u.width=u.right-u.left,u.height=u.bottom-u.top,u.x=u.left,u.y=u.top,u}function _(e){return e.split("-")[1]}function F(e){return["top","bottom"].indexOf(e)>=0?"x":"y"}function U(e){var t,n=e.reference,r=e.element,o=e.placement,i=o?C(o):null,a=o?_(o):null,s=n.x+n.width/2-r.width/2,f=n.y+n.height/2-r.height/2;switch(i){case j:t={x:s,y:n.y-r.height};break;case E:t={x:s,y:n.y+n.height};break;case D:t={x:n.x+n.width,y:f};break;case A:t={x:n.x-r.width,y:f};break;default:t={x:n.x,y:n.y}}var c=i?F(i):null;if(null!=c){var p="y"===c?"height":"width";switch(a){case M:t[c]=t[c]-(n[p]/2-r[p]/2);break;case k:t[c]=t[c]+(n[p]/2-r[p]/2)}}return t}function z(e){return Object.assign({},{top:0,right:0,bottom:0,left:0},e)}function X(e,t){return t.reduce((function(t,n){return t[n]=e,t}),{})}function Y(e,t){void 0===t&&(t={});var r=t,o=r.placement,i=void 0===o?e.placement:o,a=r.boundary,s=void 0===a?"clippingParents":a,c=r.rootBoundary,p=void 0===c?W:c,l=r.elementContext,d=void 0===l?B:l,h=r.altBoundary,m=void 0!==h&&h,v=r.padding,g=void 0===v?0:v,y=z("number"!=typeof g?g:X(g,P)),b=d===B?"reference":B,x=e.rects.popper,w=e.elements[m?b:d],O=I(n(w)?w:w.contextElement||u(e.elements.popper),s,p),A=f(e.elements.reference),L=U({reference:A,element:x,strategy:"absolute",placement:i}),M=V(Object.assign({},x,L)),k=d===B?M:A,H={top:O.top-k.top+y.top,bottom:k.bottom-O.bottom+y.bottom,left:O.left-k.left+y.left,right:k.right-O.right+y.right},T=e.modifiersData.offset;if(d===B&&T){var R=T[i];Object.keys(H).forEach((function(e){var t=[D,E].indexOf(e)>=0?1:-1,n=[j,E].indexOf(e)>=0?"y":"x";H[e]+=R[n]*t}))}return H}var G={placement:"bottom",modifiers:[],strategy:"absolute"};function J(){for(var e=arguments.length,t=new Array(e),n=0;n=0?-1:1,i="function"==typeof n?n(Object.assign({},t,{placement:e})):n,a=i[0],s=i[1];return a=a||0,s=(s||0)*o,[A,D].indexOf(r)>=0?{x:s,y:a}:{x:a,y:s}}(n,t.rects,i),e}),{}),s=a[t.placement],f=s.x,c=s.y;null!=t.modifiersData.popperOffsets&&(t.modifiersData.popperOffsets.x+=f,t.modifiersData.popperOffsets.y+=c),t.modifiersData[r]=a}},ie={left:"right",right:"left",bottom:"top",top:"bottom"};function ae(e){return e.replace(/left|right|bottom|top/g,(function(e){return ie[e]}))}var se={start:"end",end:"start"};function fe(e){return e.replace(/start|end/g,(function(e){return se[e]}))}function ce(e,t){void 0===t&&(t={});var n=t,r=n.placement,o=n.boundary,i=n.rootBoundary,a=n.padding,s=n.flipVariations,f=n.allowedAutoPlacements,c=void 0===f?T:f,p=_(r),u=p?s?H:H.filter((function(e){return _(e)===p})):P,l=u.filter((function(e){return c.indexOf(e)>=0}));0===l.length&&(l=u);var d=l.reduce((function(t,n){return t[n]=Y(e,{placement:n,boundary:o,rootBoundary:i,padding:a})[C(n)],t}),{});return Object.keys(d).sort((function(e,t){return d[e]-d[t]}))}var pe={name:"flip",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name;if(!t.modifiersData[r]._skip){for(var o=n.mainAxis,i=void 0===o||o,a=n.altAxis,s=void 0===a||a,f=n.fallbackPlacements,c=n.padding,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.flipVariations,h=void 0===d||d,m=n.allowedAutoPlacements,v=t.options.placement,g=C(v),y=f||(g===v||!h?[ae(v)]:function(e){if(C(e)===L)return[];var t=ae(e);return[fe(e),t,fe(t)]}(v)),b=[v].concat(y).reduce((function(e,n){return e.concat(C(n)===L?ce(t,{placement:n,boundary:p,rootBoundary:u,padding:c,flipVariations:h,allowedAutoPlacements:m}):n)}),[]),x=t.rects.reference,w=t.rects.popper,O=new Map,P=!0,k=b[0],W=0;W=0,S=R?"width":"height",q=Y(t,{placement:B,boundary:p,rootBoundary:u,altBoundary:l,padding:c}),V=R?T?D:A:T?E:j;x[S]>w[S]&&(V=ae(V));var N=ae(V),I=[];if(i&&I.push(q[H]<=0),s&&I.push(q[V]<=0,q[N]<=0),I.every((function(e){return e}))){k=B,P=!1;break}O.set(B,I)}if(P)for(var F=function(e){var t=b.find((function(t){var n=O.get(t);if(n)return n.slice(0,e).every((function(e){return e}))}));if(t)return k=t,"break"},U=h?3:1;U>0;U--){if("break"===F(U))break}t.placement!==k&&(t.modifiersData[r]._skip=!0,t.placement=k,t.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function ue(e,t,n){return i(e,a(t,n))}var le={name:"preventOverflow",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name,o=n.mainAxis,s=void 0===o||o,f=n.altAxis,c=void 0!==f&&f,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.padding,h=n.tether,m=void 0===h||h,g=n.tetherOffset,y=void 0===g?0:g,b=Y(t,{boundary:p,rootBoundary:u,padding:d,altBoundary:l}),x=C(t.placement),w=_(t.placement),L=!w,P=F(x),k="x"===P?"y":"x",W=t.modifiersData.popperOffsets,B=t.rects.reference,H=t.rects.popper,T="function"==typeof y?y(Object.assign({},t.rects,{placement:t.placement})):y,R="number"==typeof T?{mainAxis:T,altAxis:T}:Object.assign({mainAxis:0,altAxis:0},T),S=t.modifiersData.offset?t.modifiersData.offset[t.placement]:null,q={x:0,y:0};if(W){if(s){var V,N="y"===P?j:A,I="y"===P?E:D,U="y"===P?"height":"width",z=W[P],X=z+b[N],G=z-b[I],J=m?-H[U]/2:0,K=w===M?B[U]:H[U],Q=w===M?-H[U]:-B[U],Z=t.elements.arrow,$=m&&Z?v(Z):{width:0,height:0},ee=t.modifiersData["arrow#persistent"]?t.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},te=ee[N],ne=ee[I],re=ue(0,B[U],$[U]),oe=L?B[U]/2-J-re-te-R.mainAxis:K-re-te-R.mainAxis,ie=L?-B[U]/2+J+re+ne+R.mainAxis:Q+re+ne+R.mainAxis,ae=t.elements.arrow&&O(t.elements.arrow),se=ae?"y"===P?ae.clientTop||0:ae.clientLeft||0:0,fe=null!=(V=null==S?void 0:S[P])?V:0,ce=z+ie-fe,pe=ue(m?a(X,z+oe-fe-se):X,z,m?i(G,ce):G);W[P]=pe,q[P]=pe-z}if(c){var le,de="x"===P?j:A,he="x"===P?E:D,me=W[k],ve="y"===k?"height":"width",ge=me+b[de],ye=me-b[he],be=-1!==[j,A].indexOf(x),xe=null!=(le=null==S?void 0:S[k])?le:0,we=be?ge:me-B[ve]-H[ve]-xe+R.altAxis,Oe=be?me+B[ve]+H[ve]-xe-R.altAxis:ye,je=m&&be?function(e,t,n){var r=ue(e,t,n);return r>n?n:r}(we,me,Oe):ue(m?we:ge,me,m?Oe:ye);W[k]=je,q[k]=je-me}t.modifiersData[r]=q}},requiresIfExists:["offset"]};var de={name:"arrow",enabled:!0,phase:"main",fn:function(e){var t,n=e.state,r=e.name,o=e.options,i=n.elements.arrow,a=n.modifiersData.popperOffsets,s=C(n.placement),f=F(s),c=[A,D].indexOf(s)>=0?"height":"width";if(i&&a){var p=function(e,t){return z("number"!=typeof(e="function"==typeof e?e(Object.assign({},t.rects,{placement:t.placement})):e)?e:X(e,P))}(o.padding,n),u=v(i),l="y"===f?j:A,d="y"===f?E:D,h=n.rects.reference[c]+n.rects.reference[f]-a[f]-n.rects.popper[c],m=a[f]-n.rects.reference[f],g=O(i),y=g?"y"===f?g.clientHeight||0:g.clientWidth||0:0,b=h/2-m/2,x=p[l],w=y-u[c]-p[d],L=y/2-u[c]/2+b,M=ue(x,L,w),k=f;n.modifiersData[r]=((t={})[k]=M,t.centerOffset=M-L,t)}},effect:function(e){var t=e.state,n=e.options.element,r=void 0===n?"[data-popper-arrow]":n;null!=r&&("string"!=typeof r||(r=t.elements.popper.querySelector(r)))&&q(t.elements.popper,r)&&(t.elements.arrow=r)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function he(e,t,n){return void 0===n&&(n={x:0,y:0}),{top:e.top-t.height-n.y,right:e.right-t.width+n.x,bottom:e.bottom-t.height+n.y,left:e.left-t.width-n.x}}function me(e){return[j,D,E,A].some((function(t){return e[t]>=0}))}var ve={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(e){var t=e.state,n=e.name,r=t.rects.reference,o=t.rects.popper,i=t.modifiersData.preventOverflow,a=Y(t,{elementContext:"reference"}),s=Y(t,{altBoundary:!0}),f=he(a,r),c=he(s,o,i),p=me(f),u=me(c);t.modifiersData[n]={referenceClippingOffsets:f,popperEscapeOffsets:c,isReferenceHidden:p,hasPopperEscaped:u},t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-reference-hidden":p,"data-popper-escaped":u})}},ge=K({defaultModifiers:[Z,$,ne,re]}),ye=[Z,$,ne,re,oe,pe,le,de,ve],be=K({defaultModifiers:ye});e.applyStyles=re,e.arrow=de,e.computeStyles=ne,e.createPopper=be,e.createPopperLite=ge,e.defaultModifiers=ye,e.detectOverflow=Y,e.eventListeners=Z,e.flip=pe,e.hide=ve,e.offset=oe,e.popperGenerator=K,e.popperOffsets=$,e.preventOverflow=le,Object.defineProperty(e,"__esModule",{value:!0})})); - diff --git a/docs/site_libs/quarto-html/quarto-syntax-highlighting.css b/docs/site_libs/quarto-html/quarto-syntax-highlighting.css deleted file mode 100644 index 36cb3287..00000000 --- a/docs/site_libs/quarto-html/quarto-syntax-highlighting.css +++ /dev/null @@ -1,171 +0,0 @@ -/* quarto syntax highlight colors */ -:root { - --quarto-hl-ot-color: #003B4F; - --quarto-hl-at-color: #657422; - --quarto-hl-ss-color: #20794D; - --quarto-hl-an-color: #5E5E5E; - --quarto-hl-fu-color: #4758AB; - --quarto-hl-st-color: #20794D; - --quarto-hl-cf-color: #003B4F; - --quarto-hl-op-color: #5E5E5E; - --quarto-hl-er-color: #AD0000; - --quarto-hl-bn-color: #AD0000; - --quarto-hl-al-color: #AD0000; - --quarto-hl-va-color: #111111; - --quarto-hl-bu-color: inherit; - --quarto-hl-ex-color: inherit; - --quarto-hl-pp-color: #AD0000; - --quarto-hl-in-color: #5E5E5E; - --quarto-hl-vs-color: #20794D; - --quarto-hl-wa-color: #5E5E5E; - --quarto-hl-do-color: #5E5E5E; - --quarto-hl-im-color: #00769E; - --quarto-hl-ch-color: #20794D; - --quarto-hl-dt-color: #AD0000; - --quarto-hl-fl-color: #AD0000; - --quarto-hl-co-color: #5E5E5E; - --quarto-hl-cv-color: #5E5E5E; - --quarto-hl-cn-color: #8f5902; - --quarto-hl-sc-color: #5E5E5E; - --quarto-hl-dv-color: #AD0000; - --quarto-hl-kw-color: #003B4F; -} - -/* other quarto variables */ -:root { - --quarto-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; -} - -pre > code.sourceCode > span { - color: #003B4F; -} - -code span { - color: #003B4F; -} - -code.sourceCode > span { - color: #003B4F; -} - -div.sourceCode, -div.sourceCode pre.sourceCode { - color: #003B4F; -} - -code span.ot { - color: #003B4F; -} - -code span.at { - color: #657422; -} - -code span.ss { - color: #20794D; -} - -code span.an { - color: #5E5E5E; -} - -code span.fu { - color: #4758AB; -} - -code span.st { - color: #20794D; -} - -code span.cf { - color: #003B4F; -} - -code span.op { - color: #5E5E5E; -} - -code span.er { - color: #AD0000; -} - -code span.bn { - color: #AD0000; -} - -code span.al { - color: #AD0000; -} - -code span.va { - color: #111111; -} - -code span.pp { - color: #AD0000; -} - -code span.in { - color: #5E5E5E; -} - -code span.vs { - color: #20794D; -} - -code span.wa { - color: #5E5E5E; - font-style: italic; -} - -code span.do { - color: #5E5E5E; - font-style: italic; -} - -code span.im { - color: #00769E; -} - -code span.ch { - color: #20794D; -} - -code span.dt { - color: #AD0000; -} - -code span.fl { - color: #AD0000; -} - -code span.co { - color: #5E5E5E; -} - -code span.cv { - color: #5E5E5E; - font-style: italic; -} - -code span.cn { - color: #8f5902; -} - -code span.sc { - color: #5E5E5E; -} - -code span.dv { - color: #AD0000; -} - -code span.kw { - color: #003B4F; -} - -.prevent-inlining { - content: " { - const sibling = el.previousElementSibling; - if (sibling && sibling.tagName === "A") { - return sibling.classList.contains("active"); - } else { - return false; - } - }; - - // fire slideEnter for bootstrap tab activations (for htmlwidget resize behavior) - function fireSlideEnter(e) { - const event = window.document.createEvent("Event"); - event.initEvent("slideenter", true, true); - window.document.dispatchEvent(event); - } - const tabs = window.document.querySelectorAll('a[data-bs-toggle="tab"]'); - tabs.forEach((tab) => { - tab.addEventListener("shown.bs.tab", fireSlideEnter); - }); - - // Track scrolling and mark TOC links as active - // get table of contents and sidebar (bail if we don't have at least one) - const tocLinks = tocEl - ? [...tocEl.querySelectorAll("a[data-scroll-target]")] - : []; - const makeActive = (link) => tocLinks[link].classList.add("active"); - const removeActive = (link) => tocLinks[link].classList.remove("active"); - const removeAllActive = () => - [...Array(tocLinks.length).keys()].forEach((link) => removeActive(link)); - - // activate the anchor for a section associated with this TOC entry - tocLinks.forEach((link) => { - link.addEventListener("click", () => { - if (link.href.indexOf("#") !== -1) { - const anchor = link.href.split("#")[1]; - const heading = window.document.querySelector( - `[data-anchor-id=${anchor}]` - ); - if (heading) { - // Add the class - heading.classList.add("reveal-anchorjs-link"); - - // function to show the anchor - const handleMouseout = () => { - heading.classList.remove("reveal-anchorjs-link"); - heading.removeEventListener("mouseout", handleMouseout); - }; - - // add a function to clear the anchor when the user mouses out of it - heading.addEventListener("mouseout", handleMouseout); - } - } - }); - }); - - const sections = tocLinks.map((link) => { - const target = link.getAttribute("data-scroll-target"); - if (target.startsWith("#")) { - return window.document.getElementById(decodeURI(`${target.slice(1)}`)); - } else { - return window.document.querySelector(decodeURI(`${target}`)); - } - }); - - const sectionMargin = 200; - let currentActive = 0; - // track whether we've initialized state the first time - let init = false; - - const updateActiveLink = () => { - // The index from bottom to top (e.g. reversed list) - let sectionIndex = -1; - if ( - window.innerHeight + window.pageYOffset >= - window.document.body.offsetHeight - ) { - sectionIndex = 0; - } else { - sectionIndex = [...sections].reverse().findIndex((section) => { - if (section) { - return window.pageYOffset >= section.offsetTop - sectionMargin; - } else { - return false; - } - }); - } - if (sectionIndex > -1) { - const current = sections.length - sectionIndex - 1; - if (current !== currentActive) { - removeAllActive(); - currentActive = current; - makeActive(current); - if (init) { - window.dispatchEvent(sectionChanged); - } - init = true; - } - } - }; - - const inHiddenRegion = (top, bottom, hiddenRegions) => { - for (const region of hiddenRegions) { - if (top <= region.bottom && bottom >= region.top) { - return true; - } - } - return false; - }; - - const categorySelector = "header.quarto-title-block .quarto-category"; - const activateCategories = (href) => { - // Find any categories - // Surround them with a link pointing back to: - // #category=Authoring - try { - const categoryEls = window.document.querySelectorAll(categorySelector); - for (const categoryEl of categoryEls) { - const categoryText = categoryEl.textContent; - if (categoryText) { - const link = `${href}#category=${encodeURIComponent(categoryText)}`; - const linkEl = window.document.createElement("a"); - linkEl.setAttribute("href", link); - for (const child of categoryEl.childNodes) { - linkEl.append(child); - } - categoryEl.appendChild(linkEl); - } - } - } catch { - // Ignore errors - } - }; - function hasTitleCategories() { - return window.document.querySelector(categorySelector) !== null; - } - - function offsetRelativeUrl(url) { - const offset = getMeta("quarto:offset"); - return offset ? offset + url : url; - } - - function offsetAbsoluteUrl(url) { - const offset = getMeta("quarto:offset"); - const baseUrl = new URL(offset, window.location); - - const projRelativeUrl = url.replace(baseUrl, ""); - if (projRelativeUrl.startsWith("/")) { - return projRelativeUrl; - } else { - return "/" + projRelativeUrl; - } - } - - // read a meta tag value - function getMeta(metaName) { - const metas = window.document.getElementsByTagName("meta"); - for (let i = 0; i < metas.length; i++) { - if (metas[i].getAttribute("name") === metaName) { - return metas[i].getAttribute("content"); - } - } - return ""; - } - - async function findAndActivateCategories() { - const currentPagePath = offsetAbsoluteUrl(window.location.href); - const response = await fetch(offsetRelativeUrl("listings.json")); - if (response.status == 200) { - return response.json().then(function (listingPaths) { - const listingHrefs = []; - for (const listingPath of listingPaths) { - const pathWithoutLeadingSlash = listingPath.listing.substring(1); - for (const item of listingPath.items) { - if ( - item === currentPagePath || - item === currentPagePath + "index.html" - ) { - // Resolve this path against the offset to be sure - // we already are using the correct path to the listing - // (this adjusts the listing urls to be rooted against - // whatever root the page is actually running against) - const relative = offsetRelativeUrl(pathWithoutLeadingSlash); - const baseUrl = window.location; - const resolvedPath = new URL(relative, baseUrl); - listingHrefs.push(resolvedPath.pathname); - break; - } - } - } - - // Look up the tree for a nearby linting and use that if we find one - const nearestListing = findNearestParentListing( - offsetAbsoluteUrl(window.location.pathname), - listingHrefs - ); - if (nearestListing) { - activateCategories(nearestListing); - } else { - // See if the referrer is a listing page for this item - const referredRelativePath = offsetAbsoluteUrl(document.referrer); - const referrerListing = listingHrefs.find((listingHref) => { - const isListingReferrer = - listingHref === referredRelativePath || - listingHref === referredRelativePath + "index.html"; - return isListingReferrer; - }); - - if (referrerListing) { - // Try to use the referrer if possible - activateCategories(referrerListing); - } else if (listingHrefs.length > 0) { - // Otherwise, just fall back to the first listing - activateCategories(listingHrefs[0]); - } - } - }); - } - } - if (hasTitleCategories()) { - findAndActivateCategories(); - } - - const findNearestParentListing = (href, listingHrefs) => { - if (!href || !listingHrefs) { - return undefined; - } - // Look up the tree for a nearby linting and use that if we find one - const relativeParts = href.substring(1).split("/"); - while (relativeParts.length > 0) { - const path = relativeParts.join("/"); - for (const listingHref of listingHrefs) { - if (listingHref.startsWith(path)) { - return listingHref; - } - } - relativeParts.pop(); - } - - return undefined; - }; - - const manageSidebarVisiblity = (el, placeholderDescriptor) => { - let isVisible = true; - - return (hiddenRegions) => { - if (el === null) { - return; - } - - // Find the last element of the TOC - const lastChildEl = el.lastElementChild; - - if (lastChildEl) { - // Find the top and bottom o the element that is being managed - const elTop = el.offsetTop; - const elBottom = - elTop + lastChildEl.offsetTop + lastChildEl.offsetHeight; - - // Converts the sidebar to a menu - const convertToMenu = () => { - for (const child of el.children) { - child.style.opacity = 0; - child.style.overflow = "hidden"; - } - - const toggleContainer = window.document.createElement("div"); - toggleContainer.style.width = "100%"; - toggleContainer.classList.add("zindex-over-content"); - toggleContainer.classList.add("quarto-sidebar-toggle"); - toggleContainer.classList.add("headroom-target"); // Marks this to be managed by headeroom - toggleContainer.id = placeholderDescriptor.id; - toggleContainer.style.position = "fixed"; - - const toggleIcon = window.document.createElement("i"); - toggleIcon.classList.add("quarto-sidebar-toggle-icon"); - toggleIcon.classList.add("bi"); - toggleIcon.classList.add("bi-caret-down-fill"); - - const toggleTitle = window.document.createElement("div"); - const titleEl = window.document.body.querySelector( - placeholderDescriptor.titleSelector - ); - if (titleEl) { - toggleTitle.append(titleEl.innerText, toggleIcon); - } - toggleTitle.classList.add("zindex-over-content"); - toggleTitle.classList.add("quarto-sidebar-toggle-title"); - toggleContainer.append(toggleTitle); - - const toggleContents = window.document.createElement("div"); - toggleContents.classList = el.classList; - toggleContents.classList.add("zindex-over-content"); - toggleContents.classList.add("quarto-sidebar-toggle-contents"); - for (const child of el.children) { - if (child.id === "toc-title") { - continue; - } - - const clone = child.cloneNode(true); - clone.style.opacity = 1; - clone.style.display = null; - toggleContents.append(clone); - } - toggleContents.style.height = "0px"; - toggleContainer.append(toggleContents); - el.parentElement.prepend(toggleContainer); - - // Process clicks - let tocShowing = false; - // Allow the caller to control whether this is dismissed - // when it is clicked (e.g. sidebar navigation supports - // opening and closing the nav tree, so don't dismiss on click) - const clickEl = placeholderDescriptor.dismissOnClick - ? toggleContainer - : toggleTitle; - - const closeToggle = () => { - if (tocShowing) { - toggleContainer.classList.remove("expanded"); - toggleContents.style.height = "0px"; - tocShowing = false; - } - }; - - const positionToggle = () => { - // position the element (top left of parent, same width as parent) - const elRect = el.getBoundingClientRect(); - toggleContainer.style.left = `${elRect.left}px`; - toggleContainer.style.top = `${elRect.top}px`; - toggleContainer.style.width = `${elRect.width}px`; - }; - - // Get rid of any expanded toggle if the user scrolls - window.document.addEventListener( - "scroll", - throttle(() => { - closeToggle(); - }, 50) - ); - - // Handle positioning of the toggle - window.addEventListener( - "resize", - throttle(() => { - positionToggle(); - }, 50) - ); - positionToggle(); - - // Process the click - clickEl.onclick = () => { - if (!tocShowing) { - toggleContainer.classList.add("expanded"); - toggleContents.style.height = null; - tocShowing = true; - } else { - closeToggle(); - } - }; - }; - - // Converts a sidebar from a menu back to a sidebar - const convertToSidebar = () => { - for (const child of el.children) { - child.style.opacity = 1; - child.style.overflow = null; - } - - const placeholderEl = window.document.getElementById( - placeholderDescriptor.id - ); - if (placeholderEl) { - placeholderEl.remove(); - } - - el.classList.remove("rollup"); - }; - - if (isReaderMode()) { - convertToMenu(); - isVisible = false; - } else { - if (!isVisible) { - // If the element is current not visible reveal if there are - // no conflicts with overlay regions - if (!inHiddenRegion(elTop, elBottom, hiddenRegions)) { - convertToSidebar(); - isVisible = true; - } - } else { - // If the element is visible, hide it if it conflicts with overlay regions - // and insert a placeholder toggle (or if we're in reader mode) - if (inHiddenRegion(elTop, elBottom, hiddenRegions)) { - convertToMenu(); - isVisible = false; - } - } - } - } - }; - }; - - // Find any conflicting margin elements and add margins to the - // top to prevent overlap - const marginChildren = window.document.querySelectorAll( - ".column-margin.column-container > * " - ); - let lastBottom = 0; - for (const marginChild of marginChildren) { - const top = marginChild.getBoundingClientRect().top; - if (top < lastBottom) { - const margin = lastBottom - top; - marginChild.style.marginTop = `${margin}px`; - } - const styles = window.getComputedStyle(marginChild); - const marginTop = parseFloat(styles["marginTop"]); - - lastBottom = top + marginChild.getBoundingClientRect().height + marginTop; - } - - // Manage the visibility of the toc and the sidebar - const marginScrollVisibility = manageSidebarVisiblity(marginSidebarEl, { - id: "quarto-toc-toggle", - titleSelector: "#toc-title", - dismissOnClick: true, - }); - const sidebarScrollVisiblity = manageSidebarVisiblity(sidebarEl, { - id: "quarto-sidebarnav-toggle", - titleSelector: ".title", - dismissOnClick: false, - }); - let tocLeftScrollVisibility; - if (leftTocEl) { - tocLeftScrollVisibility = manageSidebarVisiblity(leftTocEl, { - id: "quarto-lefttoc-toggle", - titleSelector: "#toc-title", - dismissOnClick: true, - }); - } - - // Find the first element that uses formatting in special columns - const conflictingEls = window.document.body.querySelectorAll( - '[class^="column-"], [class*=" column-"], aside, [class*="margin-caption"], [class*=" margin-caption"], [class*="margin-ref"], [class*=" margin-ref"]' - ); - - // Filter all the possibly conflicting elements into ones - // the do conflict on the left or ride side - const arrConflictingEls = Array.from(conflictingEls); - const leftSideConflictEls = arrConflictingEls.filter((el) => { - if (el.tagName === "ASIDE") { - return false; - } - return Array.from(el.classList).find((className) => { - return ( - className !== "column-body" && - className.startsWith("column-") && - !className.endsWith("right") && - !className.endsWith("container") && - className !== "column-margin" - ); - }); - }); - const rightSideConflictEls = arrConflictingEls.filter((el) => { - if (el.tagName === "ASIDE") { - return true; - } - - const hasMarginCaption = Array.from(el.classList).find((className) => { - return className == "margin-caption"; - }); - if (hasMarginCaption) { - return true; - } - - return Array.from(el.classList).find((className) => { - return ( - className !== "column-body" && - !className.endsWith("container") && - className.startsWith("column-") && - !className.endsWith("left") - ); - }); - }); - - const kOverlapPaddingSize = 10; - function toRegions(els) { - return els.map((el) => { - const top = - el.getBoundingClientRect().top + - document.documentElement.scrollTop - - kOverlapPaddingSize; - return { - top, - bottom: top + el.scrollHeight + 2 * kOverlapPaddingSize, - }; - }); - } - - const hideOverlappedSidebars = () => { - marginScrollVisibility(toRegions(rightSideConflictEls)); - sidebarScrollVisiblity(toRegions(leftSideConflictEls)); - if (tocLeftScrollVisibility) { - tocLeftScrollVisibility(toRegions(leftSideConflictEls)); - } - }; - - window.quartoToggleReader = () => { - // Applies a slow class (or removes it) - // to update the transition speed - const slowTransition = (slow) => { - const manageTransition = (id, slow) => { - const el = document.getElementById(id); - if (el) { - if (slow) { - el.classList.add("slow"); - } else { - el.classList.remove("slow"); - } - } - }; - - manageTransition("TOC", slow); - manageTransition("quarto-sidebar", slow); - }; - - const readerMode = !isReaderMode(); - setReaderModeValue(readerMode); - - // If we're entering reader mode, slow the transition - if (readerMode) { - slowTransition(readerMode); - } - highlightReaderToggle(readerMode); - hideOverlappedSidebars(); - - // If we're exiting reader mode, restore the non-slow transition - if (!readerMode) { - slowTransition(!readerMode); - } - }; - - const highlightReaderToggle = (readerMode) => { - const els = document.querySelectorAll(".quarto-reader-toggle"); - if (els) { - els.forEach((el) => { - if (readerMode) { - el.classList.add("reader"); - } else { - el.classList.remove("reader"); - } - }); - } - }; - - const setReaderModeValue = (val) => { - if (window.location.protocol !== "file:") { - window.localStorage.setItem("quarto-reader-mode", val); - } else { - localReaderMode = val; - } - }; - - const isReaderMode = () => { - if (window.location.protocol !== "file:") { - return window.localStorage.getItem("quarto-reader-mode") === "true"; - } else { - return localReaderMode; - } - }; - let localReaderMode = null; - - // Walk the TOC and collapse/expand nodes - // Nodes are expanded if: - // - they are top level - // - they have children that are 'active' links - // - they are directly below an link that is 'active' - const walk = (el, depth) => { - // Tick depth when we enter a UL - if (el.tagName === "UL") { - depth = depth + 1; - } - - // It this is active link - let isActiveNode = false; - if (el.tagName === "A" && el.classList.contains("active")) { - isActiveNode = true; - } - - // See if there is an active child to this element - let hasActiveChild = false; - for (child of el.children) { - hasActiveChild = walk(child, depth) || hasActiveChild; - } - - // Process the collapse state if this is an UL - if (el.tagName === "UL") { - if (depth === 1 || hasActiveChild || prevSiblingIsActiveLink(el)) { - el.classList.remove("collapse"); - } else { - el.classList.add("collapse"); - } - - // untick depth when we leave a UL - depth = depth - 1; - } - return hasActiveChild || isActiveNode; - }; - - // walk the TOC and expand / collapse any items that should be shown - - if (tocEl) { - walk(tocEl, 0); - updateActiveLink(); - } - - // Throttle the scroll event and walk peridiocally - window.document.addEventListener( - "scroll", - throttle(() => { - if (tocEl) { - updateActiveLink(); - walk(tocEl, 0); - } - if (!isReaderMode()) { - hideOverlappedSidebars(); - } - }, 5) - ); - window.addEventListener( - "resize", - throttle(() => { - if (!isReaderMode()) { - hideOverlappedSidebars(); - } - }, 10) - ); - hideOverlappedSidebars(); - highlightReaderToggle(isReaderMode()); -}); - -// grouped tabsets -window.addEventListener("pageshow", (_event) => { - function getTabSettings() { - const data = localStorage.getItem("quarto-persistent-tabsets-data"); - if (!data) { - localStorage.setItem("quarto-persistent-tabsets-data", "{}"); - return {}; - } - if (data) { - return JSON.parse(data); - } - } - - function setTabSettings(data) { - localStorage.setItem( - "quarto-persistent-tabsets-data", - JSON.stringify(data) - ); - } - - function setTabState(groupName, groupValue) { - const data = getTabSettings(); - data[groupName] = groupValue; - setTabSettings(data); - } - - function toggleTab(tab, active) { - const tabPanelId = tab.getAttribute("aria-controls"); - const tabPanel = document.getElementById(tabPanelId); - if (active) { - tab.classList.add("active"); - tabPanel.classList.add("active"); - } else { - tab.classList.remove("active"); - tabPanel.classList.remove("active"); - } - } - - function toggleAll(selectedGroup, selectorsToSync) { - for (const [thisGroup, tabs] of Object.entries(selectorsToSync)) { - const active = selectedGroup === thisGroup; - for (const tab of tabs) { - toggleTab(tab, active); - } - } - } - - function findSelectorsToSyncByLanguage() { - const result = {}; - const tabs = Array.from( - document.querySelectorAll(`div[data-group] a[id^='tabset-']`) - ); - for (const item of tabs) { - const div = item.parentElement.parentElement.parentElement; - const group = div.getAttribute("data-group"); - if (!result[group]) { - result[group] = {}; - } - const selectorsToSync = result[group]; - const value = item.innerHTML; - if (!selectorsToSync[value]) { - selectorsToSync[value] = []; - } - selectorsToSync[value].push(item); - } - return result; - } - - function setupSelectorSync() { - const selectorsToSync = findSelectorsToSyncByLanguage(); - Object.entries(selectorsToSync).forEach(([group, tabSetsByValue]) => { - Object.entries(tabSetsByValue).forEach(([value, items]) => { - items.forEach((item) => { - item.addEventListener("click", (_event) => { - setTabState(group, value); - toggleAll(value, selectorsToSync[group]); - }); - }); - }); - }); - return selectorsToSync; - } - - const selectorsToSync = setupSelectorSync(); - for (const [group, selectedName] of Object.entries(getTabSettings())) { - const selectors = selectorsToSync[group]; - // it's possible that stale state gives us empty selections, so we explicitly check here. - if (selectors) { - toggleAll(selectedName, selectors); - } - } -}); - -function throttle(func, wait) { - let waiting = false; - return function () { - if (!waiting) { - func.apply(this, arguments); - waiting = true; - setTimeout(function () { - waiting = false; - }, wait); - } - }; -} diff --git a/docs/site_libs/quarto-html/tippy.css b/docs/site_libs/quarto-html/tippy.css deleted file mode 100644 index e6ae635c..00000000 --- a/docs/site_libs/quarto-html/tippy.css +++ /dev/null @@ -1 +0,0 @@ -.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;white-space:normal;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1} \ No newline at end of file diff --git a/docs/site_libs/quarto-html/tippy.umd.min.js b/docs/site_libs/quarto-html/tippy.umd.min.js deleted file mode 100644 index ca292be3..00000000 --- a/docs/site_libs/quarto-html/tippy.umd.min.js +++ /dev/null @@ -1,2 +0,0 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],t):(e=e||self).tippy=t(e.Popper)}(this,(function(e){"use strict";var t={passive:!0,capture:!0},n=function(){return document.body};function r(e,t,n){if(Array.isArray(e)){var r=e[t];return null==r?Array.isArray(n)?n[t]:n:r}return e}function o(e,t){var n={}.toString.call(e);return 0===n.indexOf("[object")&&n.indexOf(t+"]")>-1}function i(e,t){return"function"==typeof e?e.apply(void 0,t):e}function a(e,t){return 0===t?e:function(r){clearTimeout(n),n=setTimeout((function(){e(r)}),t)};var n}function s(e,t){var n=Object.assign({},e);return t.forEach((function(e){delete n[e]})),n}function u(e){return[].concat(e)}function c(e,t){-1===e.indexOf(t)&&e.push(t)}function p(e){return e.split("-")[0]}function f(e){return[].slice.call(e)}function l(e){return Object.keys(e).reduce((function(t,n){return void 0!==e[n]&&(t[n]=e[n]),t}),{})}function d(){return document.createElement("div")}function v(e){return["Element","Fragment"].some((function(t){return o(e,t)}))}function m(e){return o(e,"MouseEvent")}function g(e){return!(!e||!e._tippy||e._tippy.reference!==e)}function h(e){return v(e)?[e]:function(e){return o(e,"NodeList")}(e)?f(e):Array.isArray(e)?e:f(document.querySelectorAll(e))}function b(e,t){e.forEach((function(e){e&&(e.style.transitionDuration=t+"ms")}))}function y(e,t){e.forEach((function(e){e&&e.setAttribute("data-state",t)}))}function w(e){var t,n=u(e)[0];return null!=n&&null!=(t=n.ownerDocument)&&t.body?n.ownerDocument:document}function E(e,t,n){var r=t+"EventListener";["transitionend","webkitTransitionEnd"].forEach((function(t){e[r](t,n)}))}function O(e,t){for(var n=t;n;){var r;if(e.contains(n))return!0;n=null==n.getRootNode||null==(r=n.getRootNode())?void 0:r.host}return!1}var x={isTouch:!1},C=0;function T(){x.isTouch||(x.isTouch=!0,window.performance&&document.addEventListener("mousemove",A))}function A(){var e=performance.now();e-C<20&&(x.isTouch=!1,document.removeEventListener("mousemove",A)),C=e}function L(){var e=document.activeElement;if(g(e)){var t=e._tippy;e.blur&&!t.state.isVisible&&e.blur()}}var D=!!("undefined"!=typeof window&&"undefined"!=typeof document)&&!!window.msCrypto,R=Object.assign({appendTo:n,aria:{content:"auto",expanded:"auto"},delay:0,duration:[300,250],getReferenceClientRect:null,hideOnClick:!0,ignoreAttributes:!1,interactive:!1,interactiveBorder:2,interactiveDebounce:0,moveTransition:"",offset:[0,10],onAfterUpdate:function(){},onBeforeUpdate:function(){},onCreate:function(){},onDestroy:function(){},onHidden:function(){},onHide:function(){},onMount:function(){},onShow:function(){},onShown:function(){},onTrigger:function(){},onUntrigger:function(){},onClickOutside:function(){},placement:"top",plugins:[],popperOptions:{},render:null,showOnCreate:!1,touch:!0,trigger:"mouseenter focus",triggerTarget:null},{animateFill:!1,followCursor:!1,inlinePositioning:!1,sticky:!1},{allowHTML:!1,animation:"fade",arrow:!0,content:"",inertia:!1,maxWidth:350,role:"tooltip",theme:"",zIndex:9999}),k=Object.keys(R);function P(e){var t=(e.plugins||[]).reduce((function(t,n){var r,o=n.name,i=n.defaultValue;o&&(t[o]=void 0!==e[o]?e[o]:null!=(r=R[o])?r:i);return t}),{});return Object.assign({},e,t)}function j(e,t){var n=Object.assign({},t,{content:i(t.content,[e])},t.ignoreAttributes?{}:function(e,t){return(t?Object.keys(P(Object.assign({},R,{plugins:t}))):k).reduce((function(t,n){var r=(e.getAttribute("data-tippy-"+n)||"").trim();if(!r)return t;if("content"===n)t[n]=r;else try{t[n]=JSON.parse(r)}catch(e){t[n]=r}return t}),{})}(e,t.plugins));return n.aria=Object.assign({},R.aria,n.aria),n.aria={expanded:"auto"===n.aria.expanded?t.interactive:n.aria.expanded,content:"auto"===n.aria.content?t.interactive?null:"describedby":n.aria.content},n}function M(e,t){e.innerHTML=t}function V(e){var t=d();return!0===e?t.className="tippy-arrow":(t.className="tippy-svg-arrow",v(e)?t.appendChild(e):M(t,e)),t}function I(e,t){v(t.content)?(M(e,""),e.appendChild(t.content)):"function"!=typeof t.content&&(t.allowHTML?M(e,t.content):e.textContent=t.content)}function S(e){var t=e.firstElementChild,n=f(t.children);return{box:t,content:n.find((function(e){return e.classList.contains("tippy-content")})),arrow:n.find((function(e){return e.classList.contains("tippy-arrow")||e.classList.contains("tippy-svg-arrow")})),backdrop:n.find((function(e){return e.classList.contains("tippy-backdrop")}))}}function N(e){var t=d(),n=d();n.className="tippy-box",n.setAttribute("data-state","hidden"),n.setAttribute("tabindex","-1");var r=d();function o(n,r){var o=S(t),i=o.box,a=o.content,s=o.arrow;r.theme?i.setAttribute("data-theme",r.theme):i.removeAttribute("data-theme"),"string"==typeof r.animation?i.setAttribute("data-animation",r.animation):i.removeAttribute("data-animation"),r.inertia?i.setAttribute("data-inertia",""):i.removeAttribute("data-inertia"),i.style.maxWidth="number"==typeof r.maxWidth?r.maxWidth+"px":r.maxWidth,r.role?i.setAttribute("role",r.role):i.removeAttribute("role"),n.content===r.content&&n.allowHTML===r.allowHTML||I(a,e.props),r.arrow?s?n.arrow!==r.arrow&&(i.removeChild(s),i.appendChild(V(r.arrow))):i.appendChild(V(r.arrow)):s&&i.removeChild(s)}return r.className="tippy-content",r.setAttribute("data-state","hidden"),I(r,e.props),t.appendChild(n),n.appendChild(r),o(e.props,e.props),{popper:t,onUpdate:o}}N.$$tippy=!0;var B=1,H=[],U=[];function _(o,s){var v,g,h,C,T,A,L,k,M=j(o,Object.assign({},R,P(l(s)))),V=!1,I=!1,N=!1,_=!1,F=[],W=a(we,M.interactiveDebounce),X=B++,Y=(k=M.plugins).filter((function(e,t){return k.indexOf(e)===t})),$={id:X,reference:o,popper:d(),popperInstance:null,props:M,state:{isEnabled:!0,isVisible:!1,isDestroyed:!1,isMounted:!1,isShown:!1},plugins:Y,clearDelayTimeouts:function(){clearTimeout(v),clearTimeout(g),cancelAnimationFrame(h)},setProps:function(e){if($.state.isDestroyed)return;ae("onBeforeUpdate",[$,e]),be();var t=$.props,n=j(o,Object.assign({},t,l(e),{ignoreAttributes:!0}));$.props=n,he(),t.interactiveDebounce!==n.interactiveDebounce&&(ce(),W=a(we,n.interactiveDebounce));t.triggerTarget&&!n.triggerTarget?u(t.triggerTarget).forEach((function(e){e.removeAttribute("aria-expanded")})):n.triggerTarget&&o.removeAttribute("aria-expanded");ue(),ie(),J&&J(t,n);$.popperInstance&&(Ce(),Ae().forEach((function(e){requestAnimationFrame(e._tippy.popperInstance.forceUpdate)})));ae("onAfterUpdate",[$,e])},setContent:function(e){$.setProps({content:e})},show:function(){var e=$.state.isVisible,t=$.state.isDestroyed,o=!$.state.isEnabled,a=x.isTouch&&!$.props.touch,s=r($.props.duration,0,R.duration);if(e||t||o||a)return;if(te().hasAttribute("disabled"))return;if(ae("onShow",[$],!1),!1===$.props.onShow($))return;$.state.isVisible=!0,ee()&&(z.style.visibility="visible");ie(),de(),$.state.isMounted||(z.style.transition="none");if(ee()){var u=re(),p=u.box,f=u.content;b([p,f],0)}A=function(){var e;if($.state.isVisible&&!_){if(_=!0,z.offsetHeight,z.style.transition=$.props.moveTransition,ee()&&$.props.animation){var t=re(),n=t.box,r=t.content;b([n,r],s),y([n,r],"visible")}se(),ue(),c(U,$),null==(e=$.popperInstance)||e.forceUpdate(),ae("onMount",[$]),$.props.animation&&ee()&&function(e,t){me(e,t)}(s,(function(){$.state.isShown=!0,ae("onShown",[$])}))}},function(){var e,t=$.props.appendTo,r=te();e=$.props.interactive&&t===n||"parent"===t?r.parentNode:i(t,[r]);e.contains(z)||e.appendChild(z);$.state.isMounted=!0,Ce()}()},hide:function(){var e=!$.state.isVisible,t=$.state.isDestroyed,n=!$.state.isEnabled,o=r($.props.duration,1,R.duration);if(e||t||n)return;if(ae("onHide",[$],!1),!1===$.props.onHide($))return;$.state.isVisible=!1,$.state.isShown=!1,_=!1,V=!1,ee()&&(z.style.visibility="hidden");if(ce(),ve(),ie(!0),ee()){var i=re(),a=i.box,s=i.content;$.props.animation&&(b([a,s],o),y([a,s],"hidden"))}se(),ue(),$.props.animation?ee()&&function(e,t){me(e,(function(){!$.state.isVisible&&z.parentNode&&z.parentNode.contains(z)&&t()}))}(o,$.unmount):$.unmount()},hideWithInteractivity:function(e){ne().addEventListener("mousemove",W),c(H,W),W(e)},enable:function(){$.state.isEnabled=!0},disable:function(){$.hide(),$.state.isEnabled=!1},unmount:function(){$.state.isVisible&&$.hide();if(!$.state.isMounted)return;Te(),Ae().forEach((function(e){e._tippy.unmount()})),z.parentNode&&z.parentNode.removeChild(z);U=U.filter((function(e){return e!==$})),$.state.isMounted=!1,ae("onHidden",[$])},destroy:function(){if($.state.isDestroyed)return;$.clearDelayTimeouts(),$.unmount(),be(),delete o._tippy,$.state.isDestroyed=!0,ae("onDestroy",[$])}};if(!M.render)return $;var q=M.render($),z=q.popper,J=q.onUpdate;z.setAttribute("data-tippy-root",""),z.id="tippy-"+$.id,$.popper=z,o._tippy=$,z._tippy=$;var G=Y.map((function(e){return e.fn($)})),K=o.hasAttribute("aria-expanded");return he(),ue(),ie(),ae("onCreate",[$]),M.showOnCreate&&Le(),z.addEventListener("mouseenter",(function(){$.props.interactive&&$.state.isVisible&&$.clearDelayTimeouts()})),z.addEventListener("mouseleave",(function(){$.props.interactive&&$.props.trigger.indexOf("mouseenter")>=0&&ne().addEventListener("mousemove",W)})),$;function Q(){var e=$.props.touch;return Array.isArray(e)?e:[e,0]}function Z(){return"hold"===Q()[0]}function ee(){var e;return!(null==(e=$.props.render)||!e.$$tippy)}function te(){return L||o}function ne(){var e=te().parentNode;return e?w(e):document}function re(){return S(z)}function oe(e){return $.state.isMounted&&!$.state.isVisible||x.isTouch||C&&"focus"===C.type?0:r($.props.delay,e?0:1,R.delay)}function ie(e){void 0===e&&(e=!1),z.style.pointerEvents=$.props.interactive&&!e?"":"none",z.style.zIndex=""+$.props.zIndex}function ae(e,t,n){var r;(void 0===n&&(n=!0),G.forEach((function(n){n[e]&&n[e].apply(n,t)})),n)&&(r=$.props)[e].apply(r,t)}function se(){var e=$.props.aria;if(e.content){var t="aria-"+e.content,n=z.id;u($.props.triggerTarget||o).forEach((function(e){var r=e.getAttribute(t);if($.state.isVisible)e.setAttribute(t,r?r+" "+n:n);else{var o=r&&r.replace(n,"").trim();o?e.setAttribute(t,o):e.removeAttribute(t)}}))}}function ue(){!K&&$.props.aria.expanded&&u($.props.triggerTarget||o).forEach((function(e){$.props.interactive?e.setAttribute("aria-expanded",$.state.isVisible&&e===te()?"true":"false"):e.removeAttribute("aria-expanded")}))}function ce(){ne().removeEventListener("mousemove",W),H=H.filter((function(e){return e!==W}))}function pe(e){if(!x.isTouch||!N&&"mousedown"!==e.type){var t=e.composedPath&&e.composedPath()[0]||e.target;if(!$.props.interactive||!O(z,t)){if(u($.props.triggerTarget||o).some((function(e){return O(e,t)}))){if(x.isTouch)return;if($.state.isVisible&&$.props.trigger.indexOf("click")>=0)return}else ae("onClickOutside",[$,e]);!0===$.props.hideOnClick&&($.clearDelayTimeouts(),$.hide(),I=!0,setTimeout((function(){I=!1})),$.state.isMounted||ve())}}}function fe(){N=!0}function le(){N=!1}function de(){var e=ne();e.addEventListener("mousedown",pe,!0),e.addEventListener("touchend",pe,t),e.addEventListener("touchstart",le,t),e.addEventListener("touchmove",fe,t)}function ve(){var e=ne();e.removeEventListener("mousedown",pe,!0),e.removeEventListener("touchend",pe,t),e.removeEventListener("touchstart",le,t),e.removeEventListener("touchmove",fe,t)}function me(e,t){var n=re().box;function r(e){e.target===n&&(E(n,"remove",r),t())}if(0===e)return t();E(n,"remove",T),E(n,"add",r),T=r}function ge(e,t,n){void 0===n&&(n=!1),u($.props.triggerTarget||o).forEach((function(r){r.addEventListener(e,t,n),F.push({node:r,eventType:e,handler:t,options:n})}))}function he(){var e;Z()&&(ge("touchstart",ye,{passive:!0}),ge("touchend",Ee,{passive:!0})),(e=$.props.trigger,e.split(/\s+/).filter(Boolean)).forEach((function(e){if("manual"!==e)switch(ge(e,ye),e){case"mouseenter":ge("mouseleave",Ee);break;case"focus":ge(D?"focusout":"blur",Oe);break;case"focusin":ge("focusout",Oe)}}))}function be(){F.forEach((function(e){var t=e.node,n=e.eventType,r=e.handler,o=e.options;t.removeEventListener(n,r,o)})),F=[]}function ye(e){var t,n=!1;if($.state.isEnabled&&!xe(e)&&!I){var r="focus"===(null==(t=C)?void 0:t.type);C=e,L=e.currentTarget,ue(),!$.state.isVisible&&m(e)&&H.forEach((function(t){return t(e)})),"click"===e.type&&($.props.trigger.indexOf("mouseenter")<0||V)&&!1!==$.props.hideOnClick&&$.state.isVisible?n=!0:Le(e),"click"===e.type&&(V=!n),n&&!r&&De(e)}}function we(e){var t=e.target,n=te().contains(t)||z.contains(t);"mousemove"===e.type&&n||function(e,t){var n=t.clientX,r=t.clientY;return e.every((function(e){var t=e.popperRect,o=e.popperState,i=e.props.interactiveBorder,a=p(o.placement),s=o.modifiersData.offset;if(!s)return!0;var u="bottom"===a?s.top.y:0,c="top"===a?s.bottom.y:0,f="right"===a?s.left.x:0,l="left"===a?s.right.x:0,d=t.top-r+u>i,v=r-t.bottom-c>i,m=t.left-n+f>i,g=n-t.right-l>i;return d||v||m||g}))}(Ae().concat(z).map((function(e){var t,n=null==(t=e._tippy.popperInstance)?void 0:t.state;return n?{popperRect:e.getBoundingClientRect(),popperState:n,props:M}:null})).filter(Boolean),e)&&(ce(),De(e))}function Ee(e){xe(e)||$.props.trigger.indexOf("click")>=0&&V||($.props.interactive?$.hideWithInteractivity(e):De(e))}function Oe(e){$.props.trigger.indexOf("focusin")<0&&e.target!==te()||$.props.interactive&&e.relatedTarget&&z.contains(e.relatedTarget)||De(e)}function xe(e){return!!x.isTouch&&Z()!==e.type.indexOf("touch")>=0}function Ce(){Te();var t=$.props,n=t.popperOptions,r=t.placement,i=t.offset,a=t.getReferenceClientRect,s=t.moveTransition,u=ee()?S(z).arrow:null,c=a?{getBoundingClientRect:a,contextElement:a.contextElement||te()}:o,p=[{name:"offset",options:{offset:i}},{name:"preventOverflow",options:{padding:{top:2,bottom:2,left:5,right:5}}},{name:"flip",options:{padding:5}},{name:"computeStyles",options:{adaptive:!s}},{name:"$$tippy",enabled:!0,phase:"beforeWrite",requires:["computeStyles"],fn:function(e){var t=e.state;if(ee()){var n=re().box;["placement","reference-hidden","escaped"].forEach((function(e){"placement"===e?n.setAttribute("data-placement",t.placement):t.attributes.popper["data-popper-"+e]?n.setAttribute("data-"+e,""):n.removeAttribute("data-"+e)})),t.attributes.popper={}}}}];ee()&&u&&p.push({name:"arrow",options:{element:u,padding:3}}),p.push.apply(p,(null==n?void 0:n.modifiers)||[]),$.popperInstance=e.createPopper(c,z,Object.assign({},n,{placement:r,onFirstUpdate:A,modifiers:p}))}function Te(){$.popperInstance&&($.popperInstance.destroy(),$.popperInstance=null)}function Ae(){return f(z.querySelectorAll("[data-tippy-root]"))}function Le(e){$.clearDelayTimeouts(),e&&ae("onTrigger",[$,e]),de();var t=oe(!0),n=Q(),r=n[0],o=n[1];x.isTouch&&"hold"===r&&o&&(t=o),t?v=setTimeout((function(){$.show()}),t):$.show()}function De(e){if($.clearDelayTimeouts(),ae("onUntrigger",[$,e]),$.state.isVisible){if(!($.props.trigger.indexOf("mouseenter")>=0&&$.props.trigger.indexOf("click")>=0&&["mouseleave","mousemove"].indexOf(e.type)>=0&&V)){var t=oe(!1);t?g=setTimeout((function(){$.state.isVisible&&$.hide()}),t):h=requestAnimationFrame((function(){$.hide()}))}}else ve()}}function F(e,n){void 0===n&&(n={});var r=R.plugins.concat(n.plugins||[]);document.addEventListener("touchstart",T,t),window.addEventListener("blur",L);var o=Object.assign({},n,{plugins:r}),i=h(e).reduce((function(e,t){var n=t&&_(t,o);return n&&e.push(n),e}),[]);return v(e)?i[0]:i}F.defaultProps=R,F.setDefaultProps=function(e){Object.keys(e).forEach((function(t){R[t]=e[t]}))},F.currentInput=x;var W=Object.assign({},e.applyStyles,{effect:function(e){var t=e.state,n={popper:{position:t.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};Object.assign(t.elements.popper.style,n.popper),t.styles=n,t.elements.arrow&&Object.assign(t.elements.arrow.style,n.arrow)}}),X={mouseover:"mouseenter",focusin:"focus",click:"click"};var Y={name:"animateFill",defaultValue:!1,fn:function(e){var t;if(null==(t=e.props.render)||!t.$$tippy)return{};var n=S(e.popper),r=n.box,o=n.content,i=e.props.animateFill?function(){var e=d();return e.className="tippy-backdrop",y([e],"hidden"),e}():null;return{onCreate:function(){i&&(r.insertBefore(i,r.firstElementChild),r.setAttribute("data-animatefill",""),r.style.overflow="hidden",e.setProps({arrow:!1,animation:"shift-away"}))},onMount:function(){if(i){var e=r.style.transitionDuration,t=Number(e.replace("ms",""));o.style.transitionDelay=Math.round(t/10)+"ms",i.style.transitionDuration=e,y([i],"visible")}},onShow:function(){i&&(i.style.transitionDuration="0ms")},onHide:function(){i&&y([i],"hidden")}}}};var $={clientX:0,clientY:0},q=[];function z(e){var t=e.clientX,n=e.clientY;$={clientX:t,clientY:n}}var J={name:"followCursor",defaultValue:!1,fn:function(e){var t=e.reference,n=w(e.props.triggerTarget||t),r=!1,o=!1,i=!0,a=e.props;function s(){return"initial"===e.props.followCursor&&e.state.isVisible}function u(){n.addEventListener("mousemove",f)}function c(){n.removeEventListener("mousemove",f)}function p(){r=!0,e.setProps({getReferenceClientRect:null}),r=!1}function f(n){var r=!n.target||t.contains(n.target),o=e.props.followCursor,i=n.clientX,a=n.clientY,s=t.getBoundingClientRect(),u=i-s.left,c=a-s.top;!r&&e.props.interactive||e.setProps({getReferenceClientRect:function(){var e=t.getBoundingClientRect(),n=i,r=a;"initial"===o&&(n=e.left+u,r=e.top+c);var s="horizontal"===o?e.top:r,p="vertical"===o?e.right:n,f="horizontal"===o?e.bottom:r,l="vertical"===o?e.left:n;return{width:p-l,height:f-s,top:s,right:p,bottom:f,left:l}}})}function l(){e.props.followCursor&&(q.push({instance:e,doc:n}),function(e){e.addEventListener("mousemove",z)}(n))}function d(){0===(q=q.filter((function(t){return t.instance!==e}))).filter((function(e){return e.doc===n})).length&&function(e){e.removeEventListener("mousemove",z)}(n)}return{onCreate:l,onDestroy:d,onBeforeUpdate:function(){a=e.props},onAfterUpdate:function(t,n){var i=n.followCursor;r||void 0!==i&&a.followCursor!==i&&(d(),i?(l(),!e.state.isMounted||o||s()||u()):(c(),p()))},onMount:function(){e.props.followCursor&&!o&&(i&&(f($),i=!1),s()||u())},onTrigger:function(e,t){m(t)&&($={clientX:t.clientX,clientY:t.clientY}),o="focus"===t.type},onHidden:function(){e.props.followCursor&&(p(),c(),i=!0)}}}};var G={name:"inlinePositioning",defaultValue:!1,fn:function(e){var t,n=e.reference;var r=-1,o=!1,i=[],a={name:"tippyInlinePositioning",enabled:!0,phase:"afterWrite",fn:function(o){var a=o.state;e.props.inlinePositioning&&(-1!==i.indexOf(a.placement)&&(i=[]),t!==a.placement&&-1===i.indexOf(a.placement)&&(i.push(a.placement),e.setProps({getReferenceClientRect:function(){return function(e){return function(e,t,n,r){if(n.length<2||null===e)return t;if(2===n.length&&r>=0&&n[0].left>n[1].right)return n[r]||t;switch(e){case"top":case"bottom":var o=n[0],i=n[n.length-1],a="top"===e,s=o.top,u=i.bottom,c=a?o.left:i.left,p=a?o.right:i.right;return{top:s,bottom:u,left:c,right:p,width:p-c,height:u-s};case"left":case"right":var f=Math.min.apply(Math,n.map((function(e){return e.left}))),l=Math.max.apply(Math,n.map((function(e){return e.right}))),d=n.filter((function(t){return"left"===e?t.left===f:t.right===l})),v=d[0].top,m=d[d.length-1].bottom;return{top:v,bottom:m,left:f,right:l,width:l-f,height:m-v};default:return t}}(p(e),n.getBoundingClientRect(),f(n.getClientRects()),r)}(a.placement)}})),t=a.placement)}};function s(){var t;o||(t=function(e,t){var n;return{popperOptions:Object.assign({},e.popperOptions,{modifiers:[].concat(((null==(n=e.popperOptions)?void 0:n.modifiers)||[]).filter((function(e){return e.name!==t.name})),[t])})}}(e.props,a),o=!0,e.setProps(t),o=!1)}return{onCreate:s,onAfterUpdate:s,onTrigger:function(t,n){if(m(n)){var o=f(e.reference.getClientRects()),i=o.find((function(e){return e.left-2<=n.clientX&&e.right+2>=n.clientX&&e.top-2<=n.clientY&&e.bottom+2>=n.clientY})),a=o.indexOf(i);r=a>-1?a:r}},onHidden:function(){r=-1}}}};var K={name:"sticky",defaultValue:!1,fn:function(e){var t=e.reference,n=e.popper;function r(t){return!0===e.props.sticky||e.props.sticky===t}var o=null,i=null;function a(){var s=r("reference")?(e.popperInstance?e.popperInstance.state.elements.reference:t).getBoundingClientRect():null,u=r("popper")?n.getBoundingClientRect():null;(s&&Q(o,s)||u&&Q(i,u))&&e.popperInstance&&e.popperInstance.update(),o=s,i=u,e.state.isMounted&&requestAnimationFrame(a)}return{onMount:function(){e.props.sticky&&a()}}}};function Q(e,t){return!e||!t||(e.top!==t.top||e.right!==t.right||e.bottom!==t.bottom||e.left!==t.left)}return F.setDefaultProps({plugins:[Y,J,G,K],render:N}),F.createSingleton=function(e,t){var n;void 0===t&&(t={});var r,o=e,i=[],a=[],c=t.overrides,p=[],f=!1;function l(){a=o.map((function(e){return u(e.props.triggerTarget||e.reference)})).reduce((function(e,t){return e.concat(t)}),[])}function v(){i=o.map((function(e){return e.reference}))}function m(e){o.forEach((function(t){e?t.enable():t.disable()}))}function g(e){return o.map((function(t){var n=t.setProps;return t.setProps=function(o){n(o),t.reference===r&&e.setProps(o)},function(){t.setProps=n}}))}function h(e,t){var n=a.indexOf(t);if(t!==r){r=t;var s=(c||[]).concat("content").reduce((function(e,t){return e[t]=o[n].props[t],e}),{});e.setProps(Object.assign({},s,{getReferenceClientRect:"function"==typeof s.getReferenceClientRect?s.getReferenceClientRect:function(){var e;return null==(e=i[n])?void 0:e.getBoundingClientRect()}}))}}m(!1),v(),l();var b={fn:function(){return{onDestroy:function(){m(!0)},onHidden:function(){r=null},onClickOutside:function(e){e.props.showOnCreate&&!f&&(f=!0,r=null)},onShow:function(e){e.props.showOnCreate&&!f&&(f=!0,h(e,i[0]))},onTrigger:function(e,t){h(e,t.currentTarget)}}}},y=F(d(),Object.assign({},s(t,["overrides"]),{plugins:[b].concat(t.plugins||[]),triggerTarget:a,popperOptions:Object.assign({},t.popperOptions,{modifiers:[].concat((null==(n=t.popperOptions)?void 0:n.modifiers)||[],[W])})})),w=y.show;y.show=function(e){if(w(),!r&&null==e)return h(y,i[0]);if(!r||null!=e){if("number"==typeof e)return i[e]&&h(y,i[e]);if(o.indexOf(e)>=0){var t=e.reference;return h(y,t)}return i.indexOf(e)>=0?h(y,e):void 0}},y.showNext=function(){var e=i[0];if(!r)return y.show(0);var t=i.indexOf(r);y.show(i[t+1]||e)},y.showPrevious=function(){var e=i[i.length-1];if(!r)return y.show(e);var t=i.indexOf(r),n=i[t-1]||e;y.show(n)};var E=y.setProps;return y.setProps=function(e){c=e.overrides||c,E(e)},y.setInstances=function(e){m(!0),p.forEach((function(e){return e()})),o=e,m(!1),v(),l(),p=g(y),y.setProps({triggerTarget:a})},p=g(y),y},F.delegate=function(e,n){var r=[],o=[],i=!1,a=n.target,c=s(n,["target"]),p=Object.assign({},c,{trigger:"manual",touch:!1}),f=Object.assign({touch:R.touch},c,{showOnCreate:!0}),l=F(e,p);function d(e){if(e.target&&!i){var t=e.target.closest(a);if(t){var r=t.getAttribute("data-tippy-trigger")||n.trigger||R.trigger;if(!t._tippy&&!("touchstart"===e.type&&"boolean"==typeof f.touch||"touchstart"!==e.type&&r.indexOf(X[e.type])<0)){var s=F(t,f);s&&(o=o.concat(s))}}}}function v(e,t,n,o){void 0===o&&(o=!1),e.addEventListener(t,n,o),r.push({node:e,eventType:t,handler:n,options:o})}return u(l).forEach((function(e){var n=e.destroy,a=e.enable,s=e.disable;e.destroy=function(e){void 0===e&&(e=!0),e&&o.forEach((function(e){e.destroy()})),o=[],r.forEach((function(e){var t=e.node,n=e.eventType,r=e.handler,o=e.options;t.removeEventListener(n,r,o)})),r=[],n()},e.enable=function(){a(),o.forEach((function(e){return e.enable()})),i=!1},e.disable=function(){s(),o.forEach((function(e){return e.disable()})),i=!0},function(e){var n=e.reference;v(n,"touchstart",d,t),v(n,"mouseover",d),v(n,"focusin",d),v(n,"click",d)}(e)})),l},F.hideAll=function(e){var t=void 0===e?{}:e,n=t.exclude,r=t.duration;U.forEach((function(e){var t=!1;if(n&&(t=g(n)?e.reference===n:e.popper===n.popper),!t){var o=e.props.duration;e.setProps({duration:r}),e.hide(),e.state.isDestroyed||e.setProps({duration:o})}}))},F.roundArrow='',F})); - diff --git a/docs/site_libs/quarto-nav/headroom.min.js b/docs/site_libs/quarto-nav/headroom.min.js deleted file mode 100644 index b08f1dff..00000000 --- a/docs/site_libs/quarto-nav/headroom.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * headroom.js v0.12.0 - Give your page some headroom. Hide your header until you need it - * Copyright (c) 2020 Nick Williams - http://wicky.nillia.ms/headroom.js - * License: MIT - */ - -!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(t=t||self).Headroom=n()}(this,function(){"use strict";function t(){return"undefined"!=typeof window}function d(t){return function(t){return t&&t.document&&function(t){return 9===t.nodeType}(t.document)}(t)?function(t){var n=t.document,o=n.body,s=n.documentElement;return{scrollHeight:function(){return Math.max(o.scrollHeight,s.scrollHeight,o.offsetHeight,s.offsetHeight,o.clientHeight,s.clientHeight)},height:function(){return t.innerHeight||s.clientHeight||o.clientHeight},scrollY:function(){return void 0!==t.pageYOffset?t.pageYOffset:(s||o.parentNode||o).scrollTop}}}(t):function(t){return{scrollHeight:function(){return Math.max(t.scrollHeight,t.offsetHeight,t.clientHeight)},height:function(){return Math.max(t.offsetHeight,t.clientHeight)},scrollY:function(){return t.scrollTop}}}(t)}function n(t,s,e){var n,o=function(){var n=!1;try{var t={get passive(){n=!0}};window.addEventListener("test",t,t),window.removeEventListener("test",t,t)}catch(t){n=!1}return n}(),i=!1,r=d(t),l=r.scrollY(),a={};function c(){var t=Math.round(r.scrollY()),n=r.height(),o=r.scrollHeight();a.scrollY=t,a.lastScrollY=l,a.direction=ls.tolerance[a.direction],e(a),l=t,i=!1}function h(){i||(i=!0,n=requestAnimationFrame(c))}var u=!!o&&{passive:!0,capture:!1};return t.addEventListener("scroll",h,u),c(),{destroy:function(){cancelAnimationFrame(n),t.removeEventListener("scroll",h,u)}}}function o(t){return t===Object(t)?t:{down:t,up:t}}function s(t,n){n=n||{},Object.assign(this,s.options,n),this.classes=Object.assign({},s.options.classes,n.classes),this.elem=t,this.tolerance=o(this.tolerance),this.offset=o(this.offset),this.initialised=!1,this.frozen=!1}return s.prototype={constructor:s,init:function(){return s.cutsTheMustard&&!this.initialised&&(this.addClass("initial"),this.initialised=!0,setTimeout(function(t){t.scrollTracker=n(t.scroller,{offset:t.offset,tolerance:t.tolerance},t.update.bind(t))},100,this)),this},destroy:function(){this.initialised=!1,Object.keys(this.classes).forEach(this.removeClass,this),this.scrollTracker.destroy()},unpin:function(){!this.hasClass("pinned")&&this.hasClass("unpinned")||(this.addClass("unpinned"),this.removeClass("pinned"),this.onUnpin&&this.onUnpin.call(this))},pin:function(){this.hasClass("unpinned")&&(this.addClass("pinned"),this.removeClass("unpinned"),this.onPin&&this.onPin.call(this))},freeze:function(){this.frozen=!0,this.addClass("frozen")},unfreeze:function(){this.frozen=!1,this.removeClass("frozen")},top:function(){this.hasClass("top")||(this.addClass("top"),this.removeClass("notTop"),this.onTop&&this.onTop.call(this))},notTop:function(){this.hasClass("notTop")||(this.addClass("notTop"),this.removeClass("top"),this.onNotTop&&this.onNotTop.call(this))},bottom:function(){this.hasClass("bottom")||(this.addClass("bottom"),this.removeClass("notBottom"),this.onBottom&&this.onBottom.call(this))},notBottom:function(){this.hasClass("notBottom")||(this.addClass("notBottom"),this.removeClass("bottom"),this.onNotBottom&&this.onNotBottom.call(this))},shouldUnpin:function(t){return"down"===t.direction&&!t.top&&t.toleranceExceeded},shouldPin:function(t){return"up"===t.direction&&t.toleranceExceeded||t.top},addClass:function(t){this.elem.classList.add.apply(this.elem.classList,this.classes[t].split(" "))},removeClass:function(t){this.elem.classList.remove.apply(this.elem.classList,this.classes[t].split(" "))},hasClass:function(t){return this.classes[t].split(" ").every(function(t){return this.classList.contains(t)},this.elem)},update:function(t){t.isOutOfBounds||!0!==this.frozen&&(t.top?this.top():this.notTop(),t.bottom?this.bottom():this.notBottom(),this.shouldUnpin(t)?this.unpin():this.shouldPin(t)&&this.pin())}},s.options={tolerance:{up:0,down:0},offset:0,scroller:t()?window:null,classes:{frozen:"headroom--frozen",pinned:"headroom--pinned",unpinned:"headroom--unpinned",top:"headroom--top",notTop:"headroom--not-top",bottom:"headroom--bottom",notBottom:"headroom--not-bottom",initial:"headroom"}},s.cutsTheMustard=!!(t()&&function(){}.bind&&"classList"in document.documentElement&&Object.assign&&Object.keys&&requestAnimationFrame),s}); diff --git a/docs/site_libs/quarto-nav/quarto-nav.js b/docs/site_libs/quarto-nav/quarto-nav.js deleted file mode 100644 index 024fb1ff..00000000 --- a/docs/site_libs/quarto-nav/quarto-nav.js +++ /dev/null @@ -1,221 +0,0 @@ -const headroomChanged = new CustomEvent("quarto-hrChanged", { - detail: {}, - bubbles: true, - cancelable: false, - composed: false, -}); - -window.document.addEventListener("DOMContentLoaded", function () { - let init = false; - - function throttle(func, wait) { - var timeout; - return function () { - const context = this; - const args = arguments; - const later = function () { - clearTimeout(timeout); - timeout = null; - func.apply(context, args); - }; - - if (!timeout) { - timeout = setTimeout(later, wait); - } - }; - } - - function headerOffset() { - // Set an offset if there is are fixed top navbar - const headerEl = window.document.querySelector("header.fixed-top"); - if (headerEl) { - return headerEl.clientHeight; - } else { - return 0; - } - } - - function footerOffset() { - const footerEl = window.document.querySelector("footer.footer"); - if (footerEl) { - return footerEl.clientHeight; - } else { - return 0; - } - } - - function updateDocumentOffsetWithoutAnimation() { - updateDocumentOffset(false); - } - - function updateDocumentOffset(animated) { - // set body offset - const topOffset = headerOffset(); - const bodyOffset = topOffset + footerOffset(); - const bodyEl = window.document.body; - bodyEl.setAttribute("data-bs-offset", topOffset); - bodyEl.style.paddingTop = topOffset + "px"; - - // deal with sidebar offsets - const sidebars = window.document.querySelectorAll( - ".sidebar, .headroom-target" - ); - sidebars.forEach((sidebar) => { - if (!animated) { - sidebar.classList.add("notransition"); - // Remove the no transition class after the animation has time to complete - setTimeout(function () { - sidebar.classList.remove("notransition"); - }, 201); - } - - if (window.Headroom && sidebar.classList.contains("sidebar-unpinned")) { - sidebar.style.top = "0"; - sidebar.style.maxHeight = "100vh"; - } else { - sidebar.style.top = topOffset + "px"; - sidebar.style.maxHeight = "calc(100vh - " + topOffset + "px)"; - } - }); - - // allow space for footer - const mainContainer = window.document.querySelector(".quarto-container"); - if (mainContainer) { - mainContainer.style.minHeight = "calc(100vh - " + bodyOffset + "px)"; - } - - // link offset - let linkStyle = window.document.querySelector("#quarto-target-style"); - if (!linkStyle) { - linkStyle = window.document.createElement("style"); - window.document.head.appendChild(linkStyle); - } - while (linkStyle.firstChild) { - linkStyle.removeChild(linkStyle.firstChild); - } - if (topOffset > 0) { - linkStyle.appendChild( - window.document.createTextNode(` - section:target::before { - content: ""; - display: block; - height: ${topOffset}px; - margin: -${topOffset}px 0 0; - }`) - ); - } - if (init) { - window.dispatchEvent(headroomChanged); - } - init = true; - } - - // initialize headroom - var header = window.document.querySelector("#quarto-header"); - if (header && window.Headroom) { - const headroom = new window.Headroom(header, { - tolerance: 5, - onPin: function () { - const sidebars = window.document.querySelectorAll( - ".sidebar, .headroom-target" - ); - sidebars.forEach((sidebar) => { - sidebar.classList.remove("sidebar-unpinned"); - }); - updateDocumentOffset(); - }, - onUnpin: function () { - const sidebars = window.document.querySelectorAll( - ".sidebar, .headroom-target" - ); - sidebars.forEach((sidebar) => { - sidebar.classList.add("sidebar-unpinned"); - }); - updateDocumentOffset(); - }, - }); - headroom.init(); - - let frozen = false; - window.quartoToggleHeadroom = function () { - if (frozen) { - headroom.unfreeze(); - frozen = false; - } else { - headroom.freeze(); - frozen = true; - } - }; - } - - // Observe size changed for the header - const headerEl = window.document.querySelector("header.fixed-top"); - if (headerEl && window.ResizeObserver) { - const observer = new window.ResizeObserver( - throttle(updateDocumentOffsetWithoutAnimation, 50) - ); - observer.observe(headerEl, { - attributes: true, - childList: true, - characterData: true, - }); - } else { - window.addEventListener( - "resize", - throttle(updateDocumentOffsetWithoutAnimation, 50) - ); - setTimeout(updateDocumentOffsetWithoutAnimation, 500); - } - - // fixup index.html links if we aren't on the filesystem - if (window.location.protocol !== "file:") { - const links = window.document.querySelectorAll("a"); - for (let i = 0; i < links.length; i++) { - links[i].href = links[i].href.replace(/\/index\.html/, "/"); - } - - // Fixup any sharing links that require urls - // Append url to any sharing urls - const sharingLinks = window.document.querySelectorAll( - "a.sidebar-tools-main-item" - ); - for (let i = 0; i < sharingLinks.length; i++) { - const sharingLink = sharingLinks[i]; - const href = sharingLink.getAttribute("href"); - if (href) { - sharingLink.setAttribute( - "href", - href.replace("|url|", window.location.href) - ); - } - } - - // Scroll the active navigation item into view, if necessary - const navSidebar = window.document.querySelector("nav#quarto-sidebar"); - if (navSidebar) { - // Find the active item - const activeItem = navSidebar.querySelector("li.sidebar-item a.active"); - if (activeItem) { - // Wait for the scroll height and height to resolve by observing size changes on the - // nav element that is scrollable - const resizeObserver = new ResizeObserver((_entries) => { - // The bottom of the element - const elBottom = activeItem.offsetTop; - const viewBottom = navSidebar.scrollTop + navSidebar.clientHeight; - - // The element height and scroll height are the same, then we are still loading - if (viewBottom !== navSidebar.scrollHeight) { - // Determine if the item isn't visible and scroll to it - if (elBottom >= viewBottom) { - navSidebar.scrollTop = elBottom; - } - - // stop observing now since we've completed the scroll - resizeObserver.unobserve(navSidebar); - } - }); - resizeObserver.observe(navSidebar); - } - } - } -}); diff --git a/docs/site_libs/quarto-search/autocomplete.umd.js b/docs/site_libs/quarto-search/autocomplete.umd.js deleted file mode 100644 index 3f2dcf0d..00000000 --- a/docs/site_libs/quarto-search/autocomplete.umd.js +++ /dev/null @@ -1,3 +0,0 @@ -/*! @algolia/autocomplete-js 1.5.3 | MIT License | © Algolia, Inc. and contributors | https://github.com/algolia/autocomplete */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self)["@algolia/autocomplete-js"]={})}(this,(function(e){"use strict";function t(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function n(e){for(var n=1;n=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function a(e){return function(e){if(Array.isArray(e))return c(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return c(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return c(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function c(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n=n?null===r?null:0:o}function j(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function w(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function S(e,t){var n=[];return Promise.resolve(e(t)).then((function(e){return Promise.all(e.filter((function(e){return Boolean(e)})).map((function(e){if(e.sourceId,n.includes(e.sourceId))throw new Error("[Autocomplete] The `sourceId` ".concat(JSON.stringify(e.sourceId)," is not unique."));n.push(e.sourceId);var t=function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var oe,ie,ue,ae=null,ce=(oe=-1,ie=-1,ue=void 0,function(e){var t=++oe;return Promise.resolve(e).then((function(e){return ue&&t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var me=["props","refresh","store"],he=["inputElement","formElement","panelElement"],ge=["inputElement"],ye=["inputElement","maxLength"],be=["item","source"];function Oe(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function _e(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function we(e){var t=e.props,n=e.refresh,r=e.store,o=je(e,me);return{getEnvironmentProps:function(e){var n=e.inputElement,o=e.formElement,i=e.panelElement;return _e({onTouchStart:function(e){!r.getState().isOpen&&r.pendingRequests.isEmpty()||e.target===n||!1===[o,i].some((function(t){return n=t,r=e.target,n===r||n.contains(r);var n,r}))&&(r.dispatch("blur",null),t.debug||r.pendingRequests.cancelAll())},onTouchMove:function(e){!1!==r.getState().isOpen&&n===t.environment.document.activeElement&&e.target!==n&&n.blur()}},je(e,he))},getRootProps:function(e){return _e({role:"combobox","aria-expanded":r.getState().isOpen,"aria-haspopup":"listbox","aria-owns":r.getState().isOpen?"".concat(t.id,"-list"):void 0,"aria-labelledby":"".concat(t.id,"-label")},e)},getFormProps:function(e){return e.inputElement,_e({action:"",noValidate:!0,role:"search",onSubmit:function(i){var u;i.preventDefault(),t.onSubmit(_e({event:i,refresh:n,state:r.getState()},o)),r.dispatch("submit",null),null===(u=e.inputElement)||void 0===u||u.blur()},onReset:function(i){var u;i.preventDefault(),t.onReset(_e({event:i,refresh:n,state:r.getState()},o)),r.dispatch("reset",null),null===(u=e.inputElement)||void 0===u||u.focus()}},je(e,ge))},getLabelProps:function(e){return _e({htmlFor:"".concat(t.id,"-input"),id:"".concat(t.id,"-label")},e)},getInputProps:function(e){function i(e){(t.openOnFocus||Boolean(r.getState().query))&&le(_e({event:e,props:t,query:r.getState().completion||r.getState().query,refresh:n,store:r},o)),r.dispatch("focus",null)}var u="ontouchstart"in t.environment,a=e||{};a.inputElement;var c=a.maxLength,l=void 0===c?512:c,s=je(a,ye),p=I(r.getState());return _e({"aria-autocomplete":"both","aria-activedescendant":r.getState().isOpen&&null!==r.getState().activeItemId?"".concat(t.id,"-item-").concat(r.getState().activeItemId):void 0,"aria-controls":r.getState().isOpen?"".concat(t.id,"-list"):void 0,"aria-labelledby":"".concat(t.id,"-label"),value:r.getState().completion||r.getState().query,id:"".concat(t.id,"-input"),autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",enterKeyHint:null!=p&&p.itemUrl?"go":"search",spellCheck:"false",autoFocus:t.autoFocus,placeholder:t.placeholder,maxLength:l,type:"search",onChange:function(e){le(_e({event:e,props:t,query:e.currentTarget.value.slice(0,l),refresh:n,store:r},o))},onKeyDown:function(e){!function(e){var t=e.event,n=e.props,r=e.refresh,o=e.store,i=ve(e,se);if("ArrowUp"===t.key||"ArrowDown"===t.key){var u=function(){var e=n.environment.document.getElementById("".concat(n.id,"-item-").concat(o.getState().activeItemId));e&&(e.scrollIntoViewIfNeeded?e.scrollIntoViewIfNeeded(!1):e.scrollIntoView(!1))},a=function(){var e=I(o.getState());if(null!==o.getState().activeItemId&&e){var n=e.item,u=e.itemInputValue,a=e.itemUrl,c=e.source;c.onActive(fe({event:t,item:n,itemInputValue:u,itemUrl:a,refresh:r,source:c,state:o.getState()},i))}};t.preventDefault(),!1===o.getState().isOpen&&(n.openOnFocus||Boolean(o.getState().query))?le(fe({event:t,props:n,query:o.getState().query,refresh:r,store:o},i)).then((function(){o.dispatch(t.key,{nextActiveItemId:n.defaultActiveItemId}),a(),setTimeout(u,0)})):(o.dispatch(t.key,{}),a(),u())}else if("Escape"===t.key)t.preventDefault(),o.dispatch(t.key,null),o.pendingRequests.cancelAll();else if("Enter"===t.key){if(null===o.getState().activeItemId||o.getState().collections.every((function(e){return 0===e.items.length})))return;t.preventDefault();var c=I(o.getState()),l=c.item,s=c.itemInputValue,p=c.itemUrl,f=c.source;if(t.metaKey||t.ctrlKey)void 0!==p&&(f.onSelect(fe({event:t,item:l,itemInputValue:s,itemUrl:p,refresh:r,source:f,state:o.getState()},i)),n.navigator.navigateNewTab({itemUrl:p,item:l,state:o.getState()}));else if(t.shiftKey)void 0!==p&&(f.onSelect(fe({event:t,item:l,itemInputValue:s,itemUrl:p,refresh:r,source:f,state:o.getState()},i)),n.navigator.navigateNewWindow({itemUrl:p,item:l,state:o.getState()}));else if(t.altKey);else{if(void 0!==p)return f.onSelect(fe({event:t,item:l,itemInputValue:s,itemUrl:p,refresh:r,source:f,state:o.getState()},i)),void n.navigator.navigate({itemUrl:p,item:l,state:o.getState()});le(fe({event:t,nextState:{isOpen:!1},props:n,query:s,refresh:r,store:o},i)).then((function(){f.onSelect(fe({event:t,item:l,itemInputValue:s,itemUrl:p,refresh:r,source:f,state:o.getState()},i))}))}}}(_e({event:e,props:t,refresh:n,store:r},o))},onFocus:i,onBlur:function(){u||(r.dispatch("blur",null),t.debug||r.pendingRequests.cancelAll())},onClick:function(n){e.inputElement!==t.environment.document.activeElement||r.getState().isOpen||i(n)}},s)},getPanelProps:function(e){return _e({onMouseDown:function(e){e.preventDefault()},onMouseLeave:function(){r.dispatch("mouseleave",null)}},e)},getListProps:function(e){return _e({role:"listbox","aria-labelledby":"".concat(t.id,"-label"),id:"".concat(t.id,"-list")},e)},getItemProps:function(e){var i=e.item,u=e.source,a=je(e,be);return _e({id:"".concat(t.id,"-item-").concat(i.__autocomplete_id),role:"option","aria-selected":r.getState().activeItemId===i.__autocomplete_id,onMouseMove:function(e){if(i.__autocomplete_id!==r.getState().activeItemId){r.dispatch("mousemove",i.__autocomplete_id);var t=I(r.getState());if(null!==r.getState().activeItemId&&t){var u=t.item,a=t.itemInputValue,c=t.itemUrl,l=t.source;l.onActive(_e({event:e,item:u,itemInputValue:a,itemUrl:c,refresh:n,source:l,state:r.getState()},o))}}},onMouseDown:function(e){e.preventDefault()},onClick:function(e){var a=u.getItemInputValue({item:i,state:r.getState()}),c=u.getItemUrl({item:i,state:r.getState()});(c?Promise.resolve():le(_e({event:e,nextState:{isOpen:!1},props:t,query:a,refresh:n,store:r},o))).then((function(){u.onSelect(_e({event:e,item:i,itemInputValue:a,itemUrl:c,refresh:n,source:u,state:r.getState()},o))}))}},a)}}}function Se(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Ie(e){for(var t=1;t0},reshape:function(e){return e.sources}},e),{},{id:null!==(n=e.id)&&void 0!==n?n:d(),plugins:o,initialState:F({activeItemId:null,query:"",completion:null,collections:[],isOpen:!1,status:"idle",context:{}},e.initialState),onStateChange:function(t){var n;null===(n=e.onStateChange)||void 0===n||n.call(e,t),o.forEach((function(e){var n;return null===(n=e.onStateChange)||void 0===n?void 0:n.call(e,t)}))},onSubmit:function(t){var n;null===(n=e.onSubmit)||void 0===n||n.call(e,t),o.forEach((function(e){var n;return null===(n=e.onSubmit)||void 0===n?void 0:n.call(e,t)}))},onReset:function(t){var n;null===(n=e.onReset)||void 0===n||n.call(e,t),o.forEach((function(e){var n;return null===(n=e.onReset)||void 0===n?void 0:n.call(e,t)}))},getSources:function(n){return Promise.all([].concat(R(o.map((function(e){return e.getSources}))),[e.getSources]).filter(Boolean).map((function(e){return S(e,n)}))).then((function(e){return p(e)})).then((function(e){return e.map((function(e){return F(F({},e),{},{onSelect:function(n){e.onSelect(n),t.forEach((function(e){var t;return null===(t=e.onSelect)||void 0===t?void 0:t.call(e,n)}))},onActive:function(n){e.onActive(n),t.forEach((function(e){var t;return null===(t=e.onActive)||void 0===t?void 0:t.call(e,n)}))}})}))}))},navigator:F({navigate:function(e){var t=e.itemUrl;r.location.assign(t)},navigateNewTab:function(e){var t=e.itemUrl,n=r.open(t,"_blank","noopener");null==n||n.focus()},navigateNewWindow:function(e){var t=e.itemUrl;r.open(t,"_blank","noopener")}},e.navigator)})}(e,t),r=x(qe,n,(function(e){var t=e.prevState,r=e.state;n.onStateChange(Le({prevState:t,state:r,refresh:u},o))})),o=function(e){var t=e.store;return{setActiveItemId:function(e){t.dispatch("setActiveItemId",e)},setQuery:function(e){t.dispatch("setQuery",e)},setCollections:function(e){var n=0,r=e.map((function(e){return N(N({},e),{},{items:p(e.items).map((function(e){return N(N({},e),{},{__autocomplete_id:n++})}))})}));t.dispatch("setCollections",r)},setIsOpen:function(e){t.dispatch("setIsOpen",e)},setStatus:function(e){t.dispatch("setStatus",e)},setContext:function(e){t.dispatch("setContext",e)}}}({store:r}),i=we(Le({props:n,refresh:u,store:r},o));function u(){return le(Le({event:new Event("input"),nextState:{isOpen:r.getState().isOpen},props:n,query:r.getState().query,refresh:u,store:r},o))}return n.plugins.forEach((function(e){var n;return null===(n=e.subscribe)||void 0===n?void 0:n.call(e,Le(Le({},o),{},{refresh:u,onSelect:function(e){t.push({onSelect:e})},onActive:function(e){t.push({onActive:e})}}))})),function(e){var t,n=e.metadata,r=e.environment;if(null===(t=r.navigator)||void 0===t?void 0:t.userAgent.includes("Algolia Crawler")){var o=r.document.createElement("meta"),i=r.document.querySelector("head");o.name="algolia:metadata",setTimeout((function(){o.content=JSON.stringify(n),i.appendChild(o)}),0)}}({metadata:Ae({plugins:n.plugins,options:e}),environment:n.environment}),Le(Le({refresh:u},i),o)}var Te=function(e){var t=e.environment,n=t.document.createElementNS("http://www.w3.org/2000/svg","svg");n.setAttribute("class","aa-ClearIcon"),n.setAttribute("viewBox","0 0 24 24"),n.setAttribute("width","18"),n.setAttribute("height","18"),n.setAttribute("fill","currentColor");var r=t.document.createElementNS("http://www.w3.org/2000/svg","path");return r.setAttribute("d","M5.293 6.707l5.293 5.293-5.293 5.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l5.293-5.293 5.293 5.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-5.293-5.293 5.293-5.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-5.293 5.293-5.293-5.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z"),n.appendChild(r),n};function Fe(e,t){if("string"==typeof t){var n=e.document.querySelector(t);return"The element ".concat(JSON.stringify(t)," is not in the document."),n}return t}function Ue(){for(var e=arguments.length,t=new Array(e),n=0;n2&&(u.children=arguments.length>3?tt.call(arguments,2):n),"function"==typeof e&&null!=e.defaultProps)for(i in e.defaultProps)void 0===u[i]&&(u[i]=e.defaultProps[i]);return dt(e,u,r,o,null)}function dt(e,t,n,r,o){var i={type:e,props:t,key:n,ref:r,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,__h:null,constructor:void 0,__v:null==o?++rt:o};return null==o&&null!=nt.vnode&&nt.vnode(i),i}function vt(e){return e.children}function mt(e,t){this.props=e,this.context=t}function ht(e,t){if(null==t)return e.__?ht(e.__,e.__.__k.indexOf(e)+1):null;for(var n;t0?dt(d.type,d.props,d.key,null,d.__v):d)){if(d.__=n,d.__b=n.__b+1,null===(f=g[s])||f&&d.key==f.key&&d.type===f.type)g[s]=void 0;else for(p=0;p0&&void 0!==arguments[0]?arguments[0]:[];return{get:function(){return e},add:function(t){var n=e[e.length-1];(null==n?void 0:n.isHighlighted)===t.isHighlighted?e[e.length-1]={value:n.value+t.value,isHighlighted:n.isHighlighted}:e.push(t)}}}(n?[{value:n,isHighlighted:!1}]:[]);return t.forEach((function(e){var t=e.split(Nt);r.add({value:t[0],isHighlighted:!0}),""!==t[1]&&r.add({value:t[1],isHighlighted:!1})})),r.get()}function Rt(e){return function(e){if(Array.isArray(e))return Bt(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return Bt(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return Bt(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Bt(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n",""":'"',"'":"'"},Ut=new RegExp(/\w/i),Mt=/&(amp|quot|lt|gt|#39);/g,Ht=RegExp(Mt.source);function Vt(e,t){var n,r,o,i=e[t],u=(null===(n=e[t+1])||void 0===n?void 0:n.isHighlighted)||!0,a=(null===(r=e[t-1])||void 0===r?void 0:r.isHighlighted)||!0;return Ut.test((o=i.value)&&Ht.test(o)?o.replace(Mt,(function(e){return Ft[e]})):o)||a!==u?i.isHighlighted:a}function Wt(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Qt(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function un(e){return function(e){if(Array.isArray(e))return an(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return an(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return an(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function an(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n0;if(!O.value.core.openOnFocus&&!t.query)return n;var r=Boolean(g.current||O.value.renderer.renderNoResults);return!n&&r||n},__autocomplete_metadata:{userAgents:hn,options:e}}))})),j=l(n({collections:[],completion:null,context:{},isOpen:!1,query:"",activeItemId:null,status:"idle"},O.value.core.initialState)),w={getEnvironmentProps:O.value.renderer.getEnvironmentProps,getFormProps:O.value.renderer.getFormProps,getInputProps:O.value.renderer.getInputProps,getItemProps:O.value.renderer.getItemProps,getLabelProps:O.value.renderer.getLabelProps,getListProps:O.value.renderer.getListProps,getPanelProps:O.value.renderer.getPanelProps,getRootProps:O.value.renderer.getRootProps},S={setActiveItemId:P.value.setActiveItemId,setQuery:P.value.setQuery,setCollections:P.value.setCollections,setIsOpen:P.value.setIsOpen,setStatus:P.value.setStatus,setContext:P.value.setContext,refresh:P.value.refresh},I=v((function(){return et({autocomplete:P.value,autocompleteScopeApi:S,classNames:O.value.renderer.classNames,environment:O.value.core.environment,isDetached:_.value,placeholder:O.value.core.placeholder,propGetters:w,setIsModalOpen:D,state:j.current,translations:O.value.renderer.translations})}));function E(){ze(I.value.panel,{style:_.value?{}:mn({panelPlacement:O.value.renderer.panelPlacement,container:I.value.root,form:I.value.form,environment:O.value.core.environment})})}function A(e){j.current=e;var t={autocomplete:P.value,autocompleteScopeApi:S,classNames:O.value.renderer.classNames,components:O.value.renderer.components,container:O.value.renderer.container,createElement:O.value.renderer.renderer.createElement,dom:I.value,Fragment:O.value.renderer.renderer.Fragment,panelContainer:_.value?I.value.detachedContainer:O.value.renderer.panelContainer,propGetters:w,state:j.current},r=!m(e)&&!g.current&&O.value.renderer.renderNoResults||O.value.renderer.render;!function(e){var t=e.autocomplete,r=e.autocompleteScopeApi,o=e.dom,i=e.propGetters,u=e.state;Ge(o.root,i.getRootProps(n({state:u,props:t.getRootProps({})},r))),Ge(o.input,i.getInputProps(n({state:u,props:t.getInputProps({inputElement:o.input}),inputElement:o.input},r))),ze(o.label,{hidden:"stalled"===u.status}),ze(o.loadingIndicator,{hidden:"stalled"!==u.status}),ze(o.clearButton,{hidden:!u.query})}(t),function(e,t){var r=t.autocomplete,o=t.autocompleteScopeApi,u=t.classNames,a=t.createElement,c=t.dom,l=t.Fragment,s=t.panelContainer,p=t.propGetters,f=t.state,d=t.components;if(f.isOpen){s.contains(c.panel)||"loading"===f.status||s.appendChild(c.panel),c.panel.classList.toggle("aa-Panel--stalled","stalled"===f.status);var v=f.collections.filter((function(e){var t=e.source,n=e.items;return t.templates.noResults||n.length>0})).map((function(e,t){var c=e.source,s=e.items;return a("section",{key:t,className:u.source,"data-autocomplete-source-id":c.sourceId},c.templates.header&&a("div",{className:u.sourceHeader},c.templates.header({components:d,createElement:a,Fragment:l,items:s,source:c,state:f})),c.templates.noResults&&0===s.length?a("div",{className:u.sourceNoResults},c.templates.noResults({components:d,createElement:a,Fragment:l,source:c,state:f})):a("ul",i({className:u.list},p.getListProps(n({state:f,props:r.getListProps({})},o))),s.map((function(e){var t=r.getItemProps({item:e,source:c});return a("li",i({key:t.id,className:u.item},p.getItemProps(n({state:f,props:t},o))),c.templates.item({components:d,createElement:a,Fragment:l,item:e,state:f}))}))),c.templates.footer&&a("div",{className:u.sourceFooter},c.templates.footer({components:d,createElement:a,Fragment:l,items:s,source:c,state:f})))})),m=a(l,null,a("div",{className:u.panelLayout},v),a("div",{className:"aa-GradientBottom"})),h=v.reduce((function(e,t){return e[t.props["data-autocomplete-source-id"]]=t,e}),{});e(n({children:m,state:f,sections:v,elements:h,createElement:a,Fragment:l,components:d},o),c.panel)}else s.contains(c.panel)&&s.removeChild(c.panel)}(r,t)}function C(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};c(),y.current=He(O.value.renderer,O.value.core,{initialState:j.current},e),h(),p(),P.value.refresh().then((function(){A(j.current)}))}function D(e){requestAnimationFrame((function(){var t=O.value.core.environment.document.body.contains(I.value.detachedOverlay);e!==t&&(e?(O.value.core.environment.document.body.appendChild(I.value.detachedOverlay),O.value.core.environment.document.body.classList.add("aa-Detached"),I.value.input.focus()):(O.value.core.environment.document.body.removeChild(I.value.detachedOverlay),O.value.core.environment.document.body.classList.remove("aa-Detached"),P.value.setQuery(""),P.value.refresh()))}))}return a((function(){var e=P.value.getEnvironmentProps({formElement:I.value.form,panelElement:I.value.panel,inputElement:I.value.input});return ze(O.value.core.environment,e),function(){ze(O.value.core.environment,Object.keys(e).reduce((function(e,t){return n(n({},e),{},o({},t,void 0))}),{}))}})),a((function(){var e=_.value?O.value.core.environment.document.body:O.value.renderer.panelContainer,t=_.value?I.value.detachedOverlay:I.value.panel;return _.value&&j.current.isOpen&&D(!0),A(j.current),function(){e.contains(t)&&e.removeChild(t)}})),a((function(){var e=O.value.renderer.container;return e.appendChild(I.value.root),function(){e.removeChild(I.value.root)}})),a((function(){var e=s((function(e){A(e.state)}),0);return b.current=function(t){var n=t.state,r=t.prevState;(_.value&&r.isOpen!==n.isOpen&&D(n.isOpen),_.value||!n.isOpen||r.isOpen||E(),n.query!==r.query)&&O.value.core.environment.document.querySelectorAll(".aa-Panel--scrollable").forEach((function(e){0!==e.scrollTop&&(e.scrollTop=0)}));e({state:n})},function(){b.current=void 0}})),a((function(){var e=s((function(){var e=_.value;_.value=O.value.core.environment.matchMedia(O.value.renderer.detachedMediaQuery).matches,e!==_.value?C({}):requestAnimationFrame(E)}),20);return O.value.core.environment.addEventListener("resize",e),function(){O.value.core.environment.removeEventListener("resize",e)}})),a((function(){if(!_.value)return function(){};function e(e){I.value.detachedContainer.classList.toggle("aa-DetachedContainer--modal",e)}function t(t){e(t.matches)}var n=O.value.core.environment.matchMedia(getComputedStyle(O.value.core.environment.document.documentElement).getPropertyValue("--aa-detached-modal-media-query"));e(n.matches);var r=Boolean(n.addEventListener);return r?n.addEventListener("change",t):n.addListener(t),function(){r?n.removeEventListener("change",t):n.removeListener(t)}})),a((function(){return requestAnimationFrame(E),function(){}})),n(n({},S),{},{update:C,destroy:function(){c()}})},e.getAlgoliaFacets=function(e){var t=gn({transformResponse:function(e){return e.facetHits}}),r=e.queries.map((function(e){return n(n({},e),{},{type:"facet"})}));return t(n(n({},e),{},{queries:r}))},e.getAlgoliaResults=yn,Object.defineProperty(e,"__esModule",{value:!0})})); - diff --git a/docs/site_libs/quarto-search/fuse.min.js b/docs/site_libs/quarto-search/fuse.min.js deleted file mode 100644 index ca37378c..00000000 --- a/docs/site_libs/quarto-search/fuse.min.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Fuse.js v6.5.3 - Lightweight fuzzy-search (http://fusejs.io) - * - * Copyright (c) 2021 Kiro Risk (http://kiro.me) - * All Rights Reserved. Apache Software License 2.0 - * - * http://www.apache.org/licenses/LICENSE-2.0 - */ -var e,t;e=this,t=function(){"use strict";function e(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function t(t){for(var n=1;ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n0&&void 0!==arguments[0]?arguments[0]:1,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:3,n=new Map,r=Math.pow(10,t);return{get:function(t){var i=t.match(C).length;if(n.has(i))return n.get(i);var o=1/Math.pow(i,.5*e),c=parseFloat(Math.round(o*r)/r);return n.set(i,c),c},clear:function(){n.clear()}}}var $=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.getFn,i=void 0===n?I.getFn:n,o=t.fieldNormWeight,c=void 0===o?I.fieldNormWeight:o;r(this,e),this.norm=E(c,3),this.getFn=i,this.isCreated=!1,this.setIndexRecords()}return o(e,[{key:"setSources",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.docs=e}},{key:"setIndexRecords",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.records=e}},{key:"setKeys",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.keys=t,this._keysMap={},t.forEach((function(t,n){e._keysMap[t.id]=n}))}},{key:"create",value:function(){var e=this;!this.isCreated&&this.docs.length&&(this.isCreated=!0,g(this.docs[0])?this.docs.forEach((function(t,n){e._addString(t,n)})):this.docs.forEach((function(t,n){e._addObject(t,n)})),this.norm.clear())}},{key:"add",value:function(e){var t=this.size();g(e)?this._addString(e,t):this._addObject(e,t)}},{key:"removeAt",value:function(e){this.records.splice(e,1);for(var t=e,n=this.size();t2&&void 0!==arguments[2]?arguments[2]:{},r=n.getFn,i=void 0===r?I.getFn:r,o=n.fieldNormWeight,c=void 0===o?I.fieldNormWeight:o,a=new $({getFn:i,fieldNormWeight:c});return a.setKeys(e.map(_)),a.setSources(t),a.create(),a}function F(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.errors,r=void 0===n?0:n,i=t.currentLocation,o=void 0===i?0:i,c=t.expectedLocation,a=void 0===c?0:c,s=t.distance,u=void 0===s?I.distance:s,h=t.ignoreLocation,f=void 0===h?I.ignoreLocation:h,l=r/e.length;if(f)return l;var d=Math.abs(a-o);return u?l+d/u:d?1:l}function N(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:I.minMatchCharLength,n=[],r=-1,i=-1,o=0,c=e.length;o=t&&n.push([r,i]),r=-1)}return e[o-1]&&o-r>=t&&n.push([r,o-1]),n}var P=32;function W(e){for(var t={},n=0,r=e.length;n1&&void 0!==arguments[1]?arguments[1]:{},o=i.location,c=void 0===o?I.location:o,a=i.threshold,s=void 0===a?I.threshold:a,u=i.distance,h=void 0===u?I.distance:u,f=i.includeMatches,l=void 0===f?I.includeMatches:f,d=i.findAllMatches,v=void 0===d?I.findAllMatches:d,g=i.minMatchCharLength,y=void 0===g?I.minMatchCharLength:g,p=i.isCaseSensitive,m=void 0===p?I.isCaseSensitive:p,k=i.ignoreLocation,M=void 0===k?I.ignoreLocation:k;if(r(this,e),this.options={location:c,threshold:s,distance:h,includeMatches:l,findAllMatches:v,minMatchCharLength:y,isCaseSensitive:m,ignoreLocation:M},this.pattern=m?t:t.toLowerCase(),this.chunks=[],this.pattern.length){var b=function(e,t){n.chunks.push({pattern:e,alphabet:W(e),startIndex:t})},x=this.pattern.length;if(x>P){for(var w=0,L=x%P,S=x-L;w3&&void 0!==arguments[3]?arguments[3]:{},i=r.location,o=void 0===i?I.location:i,c=r.distance,a=void 0===c?I.distance:c,s=r.threshold,u=void 0===s?I.threshold:s,h=r.findAllMatches,f=void 0===h?I.findAllMatches:h,l=r.minMatchCharLength,d=void 0===l?I.minMatchCharLength:l,v=r.includeMatches,g=void 0===v?I.includeMatches:v,y=r.ignoreLocation,p=void 0===y?I.ignoreLocation:y;if(t.length>P)throw new Error(w(P));for(var m,k=t.length,M=e.length,b=Math.max(0,Math.min(o,M)),x=u,L=b,S=d>1||g,_=S?Array(M):[];(m=e.indexOf(t,L))>-1;){var O=F(t,{currentLocation:m,expectedLocation:b,distance:a,ignoreLocation:p});if(x=Math.min(O,x),L=m+k,S)for(var j=0;j=z;q-=1){var B=q-1,J=n[e.charAt(B)];if(S&&(_[B]=+!!J),K[q]=(K[q+1]<<1|1)&J,R&&(K[q]|=(A[q+1]|A[q])<<1|1|A[q+1]),K[q]&$&&(C=F(t,{errors:R,currentLocation:B,expectedLocation:b,distance:a,ignoreLocation:p}))<=x){if(x=C,(L=B)<=b)break;z=Math.max(1,2*b-L)}}if(F(t,{errors:R+1,currentLocation:b,expectedLocation:b,distance:a,ignoreLocation:p})>x)break;A=K}var U={isMatch:L>=0,score:Math.max(.001,C)};if(S){var V=N(_,d);V.length?g&&(U.indices=V):U.isMatch=!1}return U}(e,n,i,{location:c+o,distance:a,threshold:s,findAllMatches:u,minMatchCharLength:h,includeMatches:r,ignoreLocation:f}),p=y.isMatch,m=y.score,k=y.indices;p&&(g=!0),v+=m,p&&k&&(d=[].concat(l(d),l(k)))}));var y={isMatch:g,score:g?v/this.chunks.length:1};return g&&r&&(y.indices=d),y}}]),e}(),z=function(){function e(t){r(this,e),this.pattern=t}return o(e,[{key:"search",value:function(){}}],[{key:"isMultiMatch",value:function(e){return D(e,this.multiRegex)}},{key:"isSingleMatch",value:function(e){return D(e,this.singleRegex)}}]),e}();function D(e,t){var n=e.match(t);return n?n[1]:null}var K=function(e){a(n,e);var t=f(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=e===this.pattern;return{isMatch:t,score:t?0:1,indices:[0,this.pattern.length-1]}}}],[{key:"type",get:function(){return"exact"}},{key:"multiRegex",get:function(){return/^="(.*)"$/}},{key:"singleRegex",get:function(){return/^=(.*)$/}}]),n}(z),q=function(e){a(n,e);var t=f(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=-1===e.indexOf(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}}],[{key:"type",get:function(){return"inverse-exact"}},{key:"multiRegex",get:function(){return/^!"(.*)"$/}},{key:"singleRegex",get:function(){return/^!(.*)$/}}]),n}(z),B=function(e){a(n,e);var t=f(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=e.startsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,this.pattern.length-1]}}}],[{key:"type",get:function(){return"prefix-exact"}},{key:"multiRegex",get:function(){return/^\^"(.*)"$/}},{key:"singleRegex",get:function(){return/^\^(.*)$/}}]),n}(z),J=function(e){a(n,e);var t=f(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=!e.startsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}}],[{key:"type",get:function(){return"inverse-prefix-exact"}},{key:"multiRegex",get:function(){return/^!\^"(.*)"$/}},{key:"singleRegex",get:function(){return/^!\^(.*)$/}}]),n}(z),U=function(e){a(n,e);var t=f(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=e.endsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[e.length-this.pattern.length,e.length-1]}}}],[{key:"type",get:function(){return"suffix-exact"}},{key:"multiRegex",get:function(){return/^"(.*)"\$$/}},{key:"singleRegex",get:function(){return/^(.*)\$$/}}]),n}(z),V=function(e){a(n,e);var t=f(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=!e.endsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}}],[{key:"type",get:function(){return"inverse-suffix-exact"}},{key:"multiRegex",get:function(){return/^!"(.*)"\$$/}},{key:"singleRegex",get:function(){return/^!(.*)\$$/}}]),n}(z),G=function(e){a(n,e);var t=f(n);function n(e){var i,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},c=o.location,a=void 0===c?I.location:c,s=o.threshold,u=void 0===s?I.threshold:s,h=o.distance,f=void 0===h?I.distance:h,l=o.includeMatches,d=void 0===l?I.includeMatches:l,v=o.findAllMatches,g=void 0===v?I.findAllMatches:v,y=o.minMatchCharLength,p=void 0===y?I.minMatchCharLength:y,m=o.isCaseSensitive,k=void 0===m?I.isCaseSensitive:m,M=o.ignoreLocation,b=void 0===M?I.ignoreLocation:M;return r(this,n),(i=t.call(this,e))._bitapSearch=new T(e,{location:a,threshold:u,distance:f,includeMatches:d,findAllMatches:g,minMatchCharLength:p,isCaseSensitive:k,ignoreLocation:b}),i}return o(n,[{key:"search",value:function(e){return this._bitapSearch.searchIn(e)}}],[{key:"type",get:function(){return"fuzzy"}},{key:"multiRegex",get:function(){return/^"(.*)"$/}},{key:"singleRegex",get:function(){return/^(.*)$/}}]),n}(z),H=function(e){a(n,e);var t=f(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){for(var t,n=0,r=[],i=this.pattern.length;(t=e.indexOf(this.pattern,n))>-1;)n=t+i,r.push([t,n-1]);var o=!!r.length;return{isMatch:o,score:o?0:1,indices:r}}}],[{key:"type",get:function(){return"include"}},{key:"multiRegex",get:function(){return/^'"(.*)"$/}},{key:"singleRegex",get:function(){return/^'(.*)$/}}]),n}(z),Q=[K,H,B,J,V,U,q,G],X=Q.length,Y=/ +(?=([^\"]*\"[^\"]*\")*[^\"]*$)/;function Z(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return e.split("|").map((function(e){for(var n=e.trim().split(Y).filter((function(e){return e&&!!e.trim()})),r=[],i=0,o=n.length;i1&&void 0!==arguments[1]?arguments[1]:{},i=n.isCaseSensitive,o=void 0===i?I.isCaseSensitive:i,c=n.includeMatches,a=void 0===c?I.includeMatches:c,s=n.minMatchCharLength,u=void 0===s?I.minMatchCharLength:s,h=n.ignoreLocation,f=void 0===h?I.ignoreLocation:h,l=n.findAllMatches,d=void 0===l?I.findAllMatches:l,v=n.location,g=void 0===v?I.location:v,y=n.threshold,p=void 0===y?I.threshold:y,m=n.distance,k=void 0===m?I.distance:m;r(this,e),this.query=null,this.options={isCaseSensitive:o,includeMatches:a,minMatchCharLength:u,findAllMatches:d,ignoreLocation:f,location:g,threshold:p,distance:k},this.pattern=o?t:t.toLowerCase(),this.query=Z(this.pattern,this.options)}return o(e,[{key:"searchIn",value:function(e){var t=this.query;if(!t)return{isMatch:!1,score:1};var n=this.options,r=n.includeMatches;e=n.isCaseSensitive?e:e.toLowerCase();for(var i=0,o=[],c=0,a=0,s=t.length;a-1&&(n.refIndex=e.idx),t.matches.push(n)}}))}function ve(e,t){t.score=e.score}function ge(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=n.includeMatches,i=void 0===r?I.includeMatches:r,o=n.includeScore,c=void 0===o?I.includeScore:o,a=[];return i&&a.push(de),c&&a.push(ve),e.map((function(e){var n=e.idx,r={item:t[n],refIndex:n};return a.length&&a.forEach((function(t){t(e,r)})),r}))}var ye=function(){function e(n){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=arguments.length>2?arguments[2]:void 0;r(this,e),this.options=t(t({},I),i),this.options.useExtendedSearch,this._keyStore=new S(this.options.keys),this.setCollection(n,o)}return o(e,[{key:"setCollection",value:function(e,t){if(this._docs=e,t&&!(t instanceof $))throw new Error("Incorrect 'index' type");this._myIndex=t||R(this.options.keys,this._docs,{getFn:this.options.getFn,fieldNormWeight:this.options.fieldNormWeight})}},{key:"add",value:function(e){k(e)&&(this._docs.push(e),this._myIndex.add(e))}},{key:"remove",value:function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:function(){return!1},t=[],n=0,r=this._docs.length;n1&&void 0!==arguments[1]?arguments[1]:{},n=t.limit,r=void 0===n?-1:n,i=this.options,o=i.includeMatches,c=i.includeScore,a=i.shouldSort,s=i.sortFn,u=i.ignoreFieldNorm,h=g(e)?g(this._docs[0])?this._searchStringList(e):this._searchObjectList(e):this._searchLogical(e);return le(h,{ignoreFieldNorm:u}),a&&h.sort(s),y(r)&&r>-1&&(h=h.slice(0,r)),ge(h,this._docs,{includeMatches:o,includeScore:c})}},{key:"_searchStringList",value:function(e){var t=re(e,this.options),n=this._myIndex.records,r=[];return n.forEach((function(e){var n=e.v,i=e.i,o=e.n;if(k(n)){var c=t.searchIn(n),a=c.isMatch,s=c.score,u=c.indices;a&&r.push({item:n,idx:i,matches:[{score:s,value:n,norm:o,indices:u}]})}})),r}},{key:"_searchLogical",value:function(e){var t=this,n=function(e,t){var n=(arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).auto,r=void 0===n||n,i=function e(n){var i=Object.keys(n),o=ue(n);if(!o&&i.length>1&&!se(n))return e(fe(n));if(he(n)){var c=o?n[ce]:i[0],a=o?n[ae]:n[c];if(!g(a))throw new Error(x(c));var s={keyId:j(c),pattern:a};return r&&(s.searcher=re(a,t)),s}var u={children:[],operator:i[0]};return i.forEach((function(t){var r=n[t];v(r)&&r.forEach((function(t){u.children.push(e(t))}))})),u};return se(e)||(e=fe(e)),i(e)}(e,this.options),r=function e(n,r,i){if(!n.children){var o=n.keyId,c=n.searcher,a=t._findMatches({key:t._keyStore.get(o),value:t._myIndex.getValueForItemAtKeyId(r,o),searcher:c});return a&&a.length?[{idx:i,item:r,matches:a}]:[]}for(var s=[],u=0,h=n.children.length;u1&&void 0!==arguments[1]?arguments[1]:{},n=t.getFn,r=void 0===n?I.getFn:n,i=t.fieldNormWeight,o=void 0===i?I.fieldNormWeight:i,c=e.keys,a=e.records,s=new $({getFn:r,fieldNormWeight:o});return s.setKeys(c),s.setIndexRecords(a),s},ye.config=I,function(){ne.push.apply(ne,arguments)}(te),ye},"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Fuse=t(); \ No newline at end of file diff --git a/docs/site_libs/quarto-search/quarto-search.js b/docs/site_libs/quarto-search/quarto-search.js deleted file mode 100644 index 6fd4b5b9..00000000 --- a/docs/site_libs/quarto-search/quarto-search.js +++ /dev/null @@ -1,1123 +0,0 @@ -const kQueryArg = "q"; -const kResultsArg = "show-results"; - -// If items don't provide a URL, then both the navigator and the onSelect -// function aren't called (and therefore, the default implementation is used) -// -// We're using this sentinel URL to signal to those handlers that this -// item is a more item (along with the type) and can be handled appropriately -const kItemTypeMoreHref = "0767FDFD-0422-4E5A-BC8A-3BE11E5BBA05"; - -window.document.addEventListener("DOMContentLoaded", function (_event) { - // Ensure that search is available on this page. If it isn't, - // should return early and not do anything - var searchEl = window.document.getElementById("quarto-search"); - if (!searchEl) return; - - const { autocomplete } = window["@algolia/autocomplete-js"]; - - let quartoSearchOptions = {}; - let language = {}; - const searchOptionEl = window.document.getElementById( - "quarto-search-options" - ); - if (searchOptionEl) { - const jsonStr = searchOptionEl.textContent; - quartoSearchOptions = JSON.parse(jsonStr); - language = quartoSearchOptions.language; - } - - // note the search mode - if (quartoSearchOptions.type === "overlay") { - searchEl.classList.add("type-overlay"); - } else { - searchEl.classList.add("type-textbox"); - } - - // Used to determine highlighting behavior for this page - // A `q` query param is expected when the user follows a search - // to this page - const currentUrl = new URL(window.location); - const query = currentUrl.searchParams.get(kQueryArg); - const showSearchResults = currentUrl.searchParams.get(kResultsArg); - const mainEl = window.document.querySelector("main"); - - // highlight matches on the page - if (query !== null && mainEl) { - // perform any highlighting - highlight(query, mainEl); - - // fix up the URL to remove the q query param - const replacementUrl = new URL(window.location); - replacementUrl.searchParams.delete(kQueryArg); - window.history.replaceState({}, "", replacementUrl); - } - - // function to clear highlighting on the page when the search query changes - // (e.g. if the user edits the query or clears it) - let highlighting = true; - const resetHighlighting = (searchTerm) => { - if (mainEl && highlighting && query !== null && searchTerm !== query) { - clearHighlight(query, mainEl); - highlighting = false; - } - }; - - // Clear search highlighting when the user scrolls sufficiently - const resetFn = () => { - resetHighlighting(""); - window.removeEventListener("quarto-hrChanged", resetFn); - window.removeEventListener("quarto-sectionChanged", resetFn); - }; - - // Register this event after the initial scrolling and settling of events - // on the page - window.addEventListener("quarto-hrChanged", resetFn); - window.addEventListener("quarto-sectionChanged", resetFn); - - // Responsively switch to overlay mode if the search is present on the navbar - // Note that switching the sidebar to overlay mode requires more coordinate (not just - // the media query since we generate different HTML for sidebar overlays than we do - // for sidebar input UI) - const detachedMediaQuery = - quartoSearchOptions.type === "overlay" - ? "all" - : quartoSearchOptions.location === "navbar" - ? "(max-width: 991px)" - : "none"; - - // If configured, include the analytics client to send insights - const plugins = configurePlugins(quartoSearchOptions); - - let lastState = null; - const { setIsOpen } = autocomplete({ - container: searchEl, - detachedMediaQuery: detachedMediaQuery, - defaultActiveItemId: 0, - panelContainer: "#quarto-search-results", - panelPlacement: quartoSearchOptions["panel-placement"], - debug: false, - plugins, - classNames: { - form: "d-flex", - }, - translations: { - clearButtonTitle: language["search-clear-button-title"], - detachedCancelButtonText: language["search-detached-cancel-button-title"], - submitButtonTitle: language["search-submit-button-title"], - }, - initialState: { - query, - }, - getItemUrl({ item }) { - return item.href; - }, - onStateChange({ state }) { - // Perhaps reset highlighting - resetHighlighting(state.query); - - // If the panel just opened, ensure the panel is positioned properly - if (state.isOpen) { - if (lastState && !lastState.isOpen) { - setTimeout(() => { - positionPanel(quartoSearchOptions["panel-placement"]); - }, 150); - } - } - - // Perhaps show the copy link - showCopyLink(state.query, quartoSearchOptions); - - lastState = state; - }, - reshape({ sources, state }) { - return sources.map((source) => { - try { - const items = source.getItems(); - - // Validate the items - validateItems(items); - - // group the items by document - const groupedItems = new Map(); - items.forEach((item) => { - const hrefParts = item.href.split("#"); - const baseHref = hrefParts[0]; - const isDocumentItem = hrefParts.length === 1; - - const items = groupedItems.get(baseHref); - if (!items) { - groupedItems.set(baseHref, [item]); - } else { - // If the href for this item matches the document - // exactly, place this item first as it is the item that represents - // the document itself - if (isDocumentItem) { - items.unshift(item); - } else { - items.push(item); - } - groupedItems.set(baseHref, items); - } - }); - - const reshapedItems = []; - let count = 1; - for (const [_key, value] of groupedItems) { - const firstItem = value[0]; - reshapedItems.push({ - ...firstItem, - type: kItemTypeDoc, - }); - - const collapseMatches = quartoSearchOptions["collapse-after"]; - const collapseCount = - typeof collapseMatches === "number" ? collapseMatches : 1; - - if (value.length > 1) { - const target = `search-more-${count}`; - const isExpanded = - state.context.expanded && - state.context.expanded.includes(target); - - const remainingCount = value.length - collapseCount; - - for (let i = 1; i < value.length; i++) { - if (collapseMatches && i === collapseCount) { - reshapedItems.push({ - target, - title: isExpanded - ? language["search-hide-matches-text"] - : remainingCount === 1 - ? `${remainingCount} ${language["search-more-match-text"]}` - : `${remainingCount} ${language["search-more-matches-text"]}`, - type: kItemTypeMore, - href: kItemTypeMoreHref, - }); - } - - if (isExpanded || !collapseMatches || i < collapseCount) { - reshapedItems.push({ - ...value[i], - type: kItemTypeItem, - target, - }); - } - } - } - count += 1; - } - - return { - ...source, - getItems() { - return reshapedItems; - }, - }; - } catch (error) { - // Some form of error occurred - return { - ...source, - getItems() { - return [ - { - title: error.name || "An Error Occurred While Searching", - text: - error.message || - "An unknown error occurred while attempting to perform the requested search.", - type: kItemTypeError, - }, - ]; - }, - }; - } - }); - }, - navigator: { - navigate({ itemUrl }) { - if (itemUrl !== offsetURL(kItemTypeMoreHref)) { - window.location.assign(itemUrl); - } - }, - navigateNewTab({ itemUrl }) { - if (itemUrl !== offsetURL(kItemTypeMoreHref)) { - const windowReference = window.open(itemUrl, "_blank", "noopener"); - if (windowReference) { - windowReference.focus(); - } - } - }, - navigateNewWindow({ itemUrl }) { - if (itemUrl !== offsetURL(kItemTypeMoreHref)) { - window.open(itemUrl, "_blank", "noopener"); - } - }, - }, - getSources({ state, setContext, setActiveItemId, refresh }) { - return [ - { - sourceId: "documents", - getItemUrl({ item }) { - if (item.href) { - return offsetURL(item.href); - } else { - return undefined; - } - }, - onSelect({ - item, - state, - setContext, - setIsOpen, - setActiveItemId, - refresh, - }) { - if (item.type === kItemTypeMore) { - toggleExpanded(item, state, setContext, setActiveItemId, refresh); - - // Toggle more - setIsOpen(true); - } - }, - getItems({ query }) { - const limit = quartoSearchOptions.limit; - if (quartoSearchOptions.algolia) { - return algoliaSearch(query, limit, quartoSearchOptions.algolia); - } else { - // Fuse search options - const fuseSearchOptions = { - isCaseSensitive: false, - shouldSort: true, - minMatchCharLength: 2, - limit: limit, - }; - - return readSearchData().then(function (fuse) { - return fuseSearch(query, fuse, fuseSearchOptions); - }); - } - }, - templates: { - noResults({ createElement }) { - return createElement( - "div", - { class: "quarto-search-no-results" }, - language["search-no-results-text"] - ); - }, - header({ items, createElement }) { - // count the documents - const count = items.filter((item) => { - return item.type === kItemTypeDoc; - }).length; - - if (count > 0) { - return createElement( - "div", - { class: "search-result-header" }, - `${count} ${language["search-matching-documents-text"]}` - ); - } else { - return createElement( - "div", - { class: "search-result-header-no-results" }, - `` - ); - } - }, - footer({ _items, createElement }) { - if ( - quartoSearchOptions.algolia && - quartoSearchOptions.algolia["show-logo"] - ) { - const libDir = quartoSearchOptions.algolia["libDir"]; - const logo = createElement("img", { - src: offsetURL( - `${libDir}/quarto-search/search-by-algolia.svg` - ), - class: "algolia-search-logo", - }); - return createElement( - "a", - { href: "http://www.algolia.com/" }, - logo - ); - } - }, - - item({ item, createElement }) { - return renderItem( - item, - createElement, - state, - setActiveItemId, - setContext, - refresh - ); - }, - }, - }, - ]; - }, - }); - - // Remove the labeleledby attribute since it is pointing - // to a non-existent label - if (quartoSearchOptions.type === "overlay") { - const inputEl = window.document.querySelector( - "#quarto-search .aa-Autocomplete" - ); - if (inputEl) { - inputEl.removeAttribute("aria-labelledby"); - } - } - - // If the main document scrolls dismiss the search results - // (otherwise, since they're floating in the document they can scroll with the document) - window.document.body.onscroll = () => { - setIsOpen(false); - }; - - if (showSearchResults) { - setIsOpen(true); - focusSearchInput(); - } -}); - -function configurePlugins(quartoSearchOptions) { - const autocompletePlugins = []; - const algoliaOptions = quartoSearchOptions.algolia; - if ( - algoliaOptions && - algoliaOptions["analytics-events"] && - algoliaOptions["search-only-api-key"] && - algoliaOptions["application-id"] - ) { - const apiKey = algoliaOptions["search-only-api-key"]; - const appId = algoliaOptions["application-id"]; - - // Aloglia insights may not be loaded because they require cookie consent - // Use deferred loading so events will start being recorded when/if consent - // is granted. - const algoliaInsightsDeferredPlugin = deferredLoadPlugin(() => { - if ( - window.aa && - window["@algolia/autocomplete-plugin-algolia-insights"] - ) { - window.aa("init", { - appId, - apiKey, - useCookie: true, - }); - - const { createAlgoliaInsightsPlugin } = - window["@algolia/autocomplete-plugin-algolia-insights"]; - // Register the insights client - const algoliaInsightsPlugin = createAlgoliaInsightsPlugin({ - insightsClient: window.aa, - onItemsChange({ insights, insightsEvents }) { - const events = insightsEvents.map((event) => { - const maxEvents = event.objectIDs.slice(0, 20); - return { - ...event, - objectIDs: maxEvents, - }; - }); - - insights.viewedObjectIDs(...events); - }, - }); - return algoliaInsightsPlugin; - } - }); - - // Add the plugin - autocompletePlugins.push(algoliaInsightsDeferredPlugin); - return autocompletePlugins; - } -} - -// For plugins that may not load immediately, create a wrapper -// plugin and forward events and plugin data once the plugin -// is initialized. This is useful for cases like cookie consent -// which may prevent the analytics insights event plugin from initializing -// immediately. -function deferredLoadPlugin(createPlugin) { - let plugin = undefined; - let subscribeObj = undefined; - const wrappedPlugin = () => { - if (!plugin && subscribeObj) { - plugin = createPlugin(); - if (plugin && plugin.subscribe) { - plugin.subscribe(subscribeObj); - } - } - return plugin; - }; - - return { - subscribe: (obj) => { - subscribeObj = obj; - }, - onStateChange: (obj) => { - const plugin = wrappedPlugin(); - if (plugin && plugin.onStateChange) { - plugin.onStateChange(obj); - } - }, - onSubmit: (obj) => { - const plugin = wrappedPlugin(); - if (plugin && plugin.onSubmit) { - plugin.onSubmit(obj); - } - }, - onReset: (obj) => { - const plugin = wrappedPlugin(); - if (plugin && plugin.onReset) { - plugin.onReset(obj); - } - }, - getSources: (obj) => { - const plugin = wrappedPlugin(); - if (plugin && plugin.getSources) { - return plugin.getSources(obj); - } else { - return Promise.resolve([]); - } - }, - data: (obj) => { - const plugin = wrappedPlugin(); - if (plugin && plugin.data) { - plugin.data(obj); - } - }, - }; -} - -function validateItems(items) { - // Validate the first item - if (items.length > 0) { - const item = items[0]; - const missingFields = []; - if (item.href == undefined) { - missingFields.push("href"); - } - if (!item.title == undefined) { - missingFields.push("title"); - } - if (!item.text == undefined) { - missingFields.push("text"); - } - - if (missingFields.length === 1) { - throw { - name: `Error: Search index is missing the ${missingFields[0]} field.`, - message: `The items being returned for this search do not include all the required fields. Please ensure that your index items include the ${missingFields[0]} field or use index-fields in your _quarto.yml file to specify the field names.`, - }; - } else if (missingFields.length > 1) { - const missingFieldList = missingFields - .map((field) => { - return `${field}`; - }) - .join(", "); - - throw { - name: `Error: Search index is missing the following fields: ${missingFieldList}.`, - message: `The items being returned for this search do not include all the required fields. Please ensure that your index items includes the following fields: ${missingFieldList}, or use index-fields in your _quarto.yml file to specify the field names.`, - }; - } - } -} - -let lastQuery = null; -function showCopyLink(query, options) { - const language = options.language; - lastQuery = query; - // Insert share icon - const inputSuffixEl = window.document.body.querySelector( - ".aa-Form .aa-InputWrapperSuffix" - ); - - if (inputSuffixEl) { - let copyButtonEl = window.document.body.querySelector( - ".aa-Form .aa-InputWrapperSuffix .aa-CopyButton" - ); - - if (copyButtonEl === null) { - copyButtonEl = window.document.createElement("button"); - copyButtonEl.setAttribute("class", "aa-CopyButton"); - copyButtonEl.setAttribute("type", "button"); - copyButtonEl.setAttribute("title", language["search-copy-link-title"]); - copyButtonEl.onmousedown = (e) => { - e.preventDefault(); - e.stopPropagation(); - }; - - const linkIcon = "bi-clipboard"; - const checkIcon = "bi-check2"; - - const shareIconEl = window.document.createElement("i"); - shareIconEl.setAttribute("class", `bi ${linkIcon}`); - copyButtonEl.appendChild(shareIconEl); - inputSuffixEl.prepend(copyButtonEl); - - const clipboard = new window.ClipboardJS(".aa-CopyButton", { - text: function (_trigger) { - const copyUrl = new URL(window.location); - copyUrl.searchParams.set(kQueryArg, lastQuery); - copyUrl.searchParams.set(kResultsArg, "1"); - return copyUrl.toString(); - }, - }); - clipboard.on("success", function (e) { - // Focus the input - - // button target - const button = e.trigger; - const icon = button.querySelector("i.bi"); - - // flash "checked" - icon.classList.add(checkIcon); - icon.classList.remove(linkIcon); - setTimeout(function () { - icon.classList.remove(checkIcon); - icon.classList.add(linkIcon); - }, 1000); - }); - } - - // If there is a query, show the link icon - if (copyButtonEl) { - if (lastQuery && options["copy-button"]) { - copyButtonEl.style.display = "flex"; - } else { - copyButtonEl.style.display = "none"; - } - } - } -} - -/* Search Index Handling */ -// create the index -var fuseIndex = undefined; -async function readSearchData() { - // Initialize the search index on demand - if (fuseIndex === undefined) { - // create fuse index - const options = { - keys: [ - { name: "title", weight: 20 }, - { name: "section", weight: 20 }, - { name: "text", weight: 10 }, - ], - ignoreLocation: true, - threshold: 0.1, - }; - const fuse = new window.Fuse([], options); - - // fetch the main search.json - const response = await fetch(offsetURL("search.json")); - if (response.status == 200) { - return response.json().then(function (searchDocs) { - searchDocs.forEach(function (searchDoc) { - fuse.add(searchDoc); - }); - fuseIndex = fuse; - return fuseIndex; - }); - } else { - return Promise.reject( - new Error( - "Unexpected status from search index request: " + response.status - ) - ); - } - } - return fuseIndex; -} - -function inputElement() { - return window.document.body.querySelector(".aa-Form .aa-Input"); -} - -function focusSearchInput() { - setTimeout(() => { - const inputEl = inputElement(); - if (inputEl) { - inputEl.focus(); - } - }, 50); -} - -/* Panels */ -const kItemTypeDoc = "document"; -const kItemTypeMore = "document-more"; -const kItemTypeItem = "document-item"; -const kItemTypeError = "error"; - -function renderItem( - item, - createElement, - state, - setActiveItemId, - setContext, - refresh -) { - switch (item.type) { - case kItemTypeDoc: - return createDocumentCard( - createElement, - "file-richtext", - item.title, - item.section, - item.text, - item.href - ); - case kItemTypeMore: - return createMoreCard( - createElement, - item, - state, - setActiveItemId, - setContext, - refresh - ); - case kItemTypeItem: - return createSectionCard( - createElement, - item.section, - item.text, - item.href - ); - case kItemTypeError: - return createErrorCard(createElement, item.title, item.text); - default: - return undefined; - } -} - -function createDocumentCard(createElement, icon, title, section, text, href) { - const iconEl = createElement("i", { - class: `bi bi-${icon} search-result-icon`, - }); - const titleEl = createElement("p", { class: "search-result-title" }, title); - const titleContainerEl = createElement( - "div", - { class: "search-result-title-container" }, - [iconEl, titleEl] - ); - - const textEls = []; - if (section) { - const sectionEl = createElement( - "p", - { class: "search-result-section" }, - section - ); - textEls.push(sectionEl); - } - const descEl = createElement("p", { - class: "search-result-text", - dangerouslySetInnerHTML: { - __html: text, - }, - }); - textEls.push(descEl); - - const textContainerEl = createElement( - "div", - { class: "search-result-text-container" }, - textEls - ); - - const containerEl = createElement( - "div", - { - class: "search-result-container", - }, - [titleContainerEl, textContainerEl] - ); - - const linkEl = createElement( - "a", - { - href: offsetURL(href), - class: "search-result-link", - }, - containerEl - ); - - const classes = ["search-result-doc", "search-item"]; - if (!section) { - classes.push("document-selectable"); - } - - return createElement( - "div", - { - class: classes.join(" "), - }, - linkEl - ); -} - -function createMoreCard( - createElement, - item, - state, - setActiveItemId, - setContext, - refresh -) { - const moreCardEl = createElement( - "div", - { - class: "search-result-more search-item", - onClick: (e) => { - // Handle expanding the sections by adding the expanded - // section to the list of expanded sections - toggleExpanded(item, state, setContext, setActiveItemId, refresh); - e.stopPropagation(); - }, - }, - item.title - ); - - return moreCardEl; -} - -function toggleExpanded(item, state, setContext, setActiveItemId, refresh) { - const expanded = state.context.expanded || []; - if (expanded.includes(item.target)) { - setContext({ - expanded: expanded.filter((target) => target !== item.target), - }); - } else { - setContext({ expanded: [...expanded, item.target] }); - } - - refresh(); - setActiveItemId(item.__autocomplete_id); -} - -function createSectionCard(createElement, section, text, href) { - const sectionEl = createSection(createElement, section, text, href); - return createElement( - "div", - { - class: "search-result-doc-section search-item", - }, - sectionEl - ); -} - -function createSection(createElement, title, text, href) { - const descEl = createElement("p", { - class: "search-result-text", - dangerouslySetInnerHTML: { - __html: text, - }, - }); - - const titleEl = createElement("p", { class: "search-result-section" }, title); - const linkEl = createElement( - "a", - { - href: offsetURL(href), - class: "search-result-link", - }, - [titleEl, descEl] - ); - return linkEl; -} - -function createErrorCard(createElement, title, text) { - const descEl = createElement("p", { - class: "search-error-text", - dangerouslySetInnerHTML: { - __html: text, - }, - }); - - const titleEl = createElement("p", { - class: "search-error-title", - dangerouslySetInnerHTML: { - __html: ` ${title}`, - }, - }); - const errorEl = createElement("div", { class: "search-error" }, [ - titleEl, - descEl, - ]); - return errorEl; -} - -function positionPanel(pos) { - const panelEl = window.document.querySelector( - "#quarto-search-results .aa-Panel" - ); - const inputEl = window.document.querySelector( - "#quarto-search .aa-Autocomplete" - ); - - if (panelEl && inputEl) { - panelEl.style.top = `${Math.round(panelEl.offsetTop)}px`; - if (pos === "start") { - panelEl.style.left = `${Math.round(inputEl.left)}px`; - } else { - panelEl.style.right = `${Math.round(inputEl.offsetRight)}px`; - } - } -} - -/* Highlighting */ -// highlighting functions -function highlightMatch(query, text) { - if (text) { - const start = text.toLowerCase().indexOf(query.toLowerCase()); - if (start !== -1) { - const startMark = ""; - const endMark = ""; - - const end = start + query.length; - text = - text.slice(0, start) + - startMark + - text.slice(start, end) + - endMark + - text.slice(end); - const startInfo = clipStart(text, start); - const endInfo = clipEnd( - text, - startInfo.position + startMark.length + endMark.length - ); - text = - startInfo.prefix + - text.slice(startInfo.position, endInfo.position) + - endInfo.suffix; - - return text; - } else { - return text; - } - } else { - return text; - } -} - -function clipStart(text, pos) { - const clipStart = pos - 50; - if (clipStart < 0) { - // This will just return the start of the string - return { - position: 0, - prefix: "", - }; - } else { - // We're clipping before the start of the string, walk backwards to the first space. - const spacePos = findSpace(text, pos, -1); - return { - position: spacePos.position, - prefix: "", - }; - } -} - -function clipEnd(text, pos) { - const clipEnd = pos + 200; - if (clipEnd > text.length) { - return { - position: text.length, - suffix: "", - }; - } else { - const spacePos = findSpace(text, clipEnd, 1); - return { - position: spacePos.position, - suffix: spacePos.clipped ? "…" : "", - }; - } -} - -function findSpace(text, start, step) { - let stepPos = start; - while (stepPos > -1 && stepPos < text.length) { - const char = text[stepPos]; - if (char === " " || char === "," || char === ":") { - return { - position: step === 1 ? stepPos : stepPos - step, - clipped: stepPos > 1 && stepPos < text.length, - }; - } - stepPos = stepPos + step; - } - - return { - position: stepPos - step, - clipped: false, - }; -} - -// removes highlighting as implemented by the mark tag -function clearHighlight(searchterm, el) { - const childNodes = el.childNodes; - for (let i = childNodes.length - 1; i >= 0; i--) { - const node = childNodes[i]; - if (node.nodeType === Node.ELEMENT_NODE) { - if ( - node.tagName === "MARK" && - node.innerText.toLowerCase() === searchterm.toLowerCase() - ) { - el.replaceChild(document.createTextNode(node.innerText), node); - } else { - clearHighlight(searchterm, node); - } - } - } -} - -// highlight matches -function highlight(term, el) { - const termRegex = new RegExp(term, "ig"); - const childNodes = el.childNodes; - - // walk back to front avoid mutating elements in front of us - for (let i = childNodes.length - 1; i >= 0; i--) { - const node = childNodes[i]; - - if (node.nodeType === Node.TEXT_NODE) { - // Search text nodes for text to highlight - const text = node.nodeValue; - - let startIndex = 0; - let matchIndex = text.search(termRegex); - if (matchIndex > -1) { - const markFragment = document.createDocumentFragment(); - while (matchIndex > -1) { - const prefix = text.slice(startIndex, matchIndex); - markFragment.appendChild(document.createTextNode(prefix)); - - const mark = document.createElement("mark"); - mark.appendChild( - document.createTextNode( - text.slice(matchIndex, matchIndex + term.length) - ) - ); - markFragment.appendChild(mark); - - startIndex = matchIndex + term.length; - matchIndex = text.slice(startIndex).search(new RegExp(term, "ig")); - if (matchIndex > -1) { - matchIndex = startIndex + matchIndex; - } - } - if (startIndex < text.length) { - markFragment.appendChild( - document.createTextNode(text.slice(startIndex, text.length)) - ); - } - - el.replaceChild(markFragment, node); - } - } else if (node.nodeType === Node.ELEMENT_NODE) { - // recurse through elements - highlight(term, node); - } - } -} - -/* Link Handling */ -// get the offset from this page for a given site root relative url -function offsetURL(url) { - var offset = getMeta("quarto:offset"); - return offset ? offset + url : url; -} - -// read a meta tag value -function getMeta(metaName) { - var metas = window.document.getElementsByTagName("meta"); - for (let i = 0; i < metas.length; i++) { - if (metas[i].getAttribute("name") === metaName) { - return metas[i].getAttribute("content"); - } - } - return ""; -} - -function algoliaSearch(query, limit, algoliaOptions) { - const { getAlgoliaResults } = window["@algolia/autocomplete-preset-algolia"]; - - const applicationId = algoliaOptions["application-id"]; - const searchOnlyApiKey = algoliaOptions["search-only-api-key"]; - const indexName = algoliaOptions["index-name"]; - const indexFields = algoliaOptions["index-fields"]; - const searchClient = window.algoliasearch(applicationId, searchOnlyApiKey); - const searchParams = algoliaOptions["params"]; - const searchAnalytics = !!algoliaOptions["analytics-events"]; - - return getAlgoliaResults({ - searchClient, - queries: [ - { - indexName: indexName, - query, - params: { - hitsPerPage: limit, - clickAnalytics: searchAnalytics, - ...searchParams, - }, - }, - ], - transformResponse: (response) => { - if (!indexFields) { - return response.hits.map((hit) => { - return hit.map((item) => { - return { - ...item, - text: highlightMatch(query, item.text), - }; - }); - }); - } else { - const remappedHits = response.hits.map((hit) => { - return hit.map((item) => { - const newItem = { ...item }; - ["href", "section", "title", "text"].forEach((keyName) => { - const mappedName = indexFields[keyName]; - if ( - mappedName && - item[mappedName] !== undefined && - mappedName !== keyName - ) { - newItem[keyName] = item[mappedName]; - delete newItem[mappedName]; - } - }); - newItem.text = highlightMatch(query, newItem.text); - return newItem; - }); - }); - return remappedHits; - } - }, - }); -} - -function fuseSearch(query, fuse, fuseOptions) { - return fuse.search(query, fuseOptions).map((result) => { - const addParam = (url, name, value) => { - const anchorParts = url.split("#"); - const baseUrl = anchorParts[0]; - const sep = baseUrl.search("\\?") > 0 ? "&" : "?"; - anchorParts[0] = baseUrl + sep + name + "=" + value; - return anchorParts.join("#"); - }; - - return { - title: result.item.title, - section: result.item.section, - href: addParam(result.item.href, kQueryArg, query), - text: highlightMatch(query, result.item.text), - }; - }); -} diff --git a/docs/sitemap.xml b/docs/sitemap.xml deleted file mode 100644 index 675d7bc5..00000000 --- a/docs/sitemap.xml +++ /dev/null @@ -1,91 +0,0 @@ - - - - https://MannLabs.github.io/alphabase/utils.html - 2022-09-29T14:47:40.051Z - - - https://MannLabs.github.io/alphabase/psm_reader/msfragger_reader.html - 2022-09-29T14:47:40.381Z - - - https://MannLabs.github.io/alphabase/psm_reader/maxquant_reader.html - 2022-09-29T14:47:40.833Z - - - https://MannLabs.github.io/alphabase/psm_reader/psm_reader.html - 2022-09-29T14:47:41.211Z - - - https://MannLabs.github.io/alphabase/psm_reader/alphapept_reader.html - 2022-09-29T14:47:41.591Z - - - https://MannLabs.github.io/alphabase/psm_reader/pfind_reader.html - 2022-09-29T14:47:41.874Z - - - https://MannLabs.github.io/alphabase/psm_reader/dia_psm_reader.html - 2022-09-29T14:47:42.481Z - - - https://MannLabs.github.io/alphabase/peptide/precursor.html - 2022-09-29T14:47:42.825Z - - - https://MannLabs.github.io/alphabase/peptide/fragment.html - 2022-09-29T14:47:43.314Z - - - https://MannLabs.github.io/alphabase/peptide/mass_calc.html - 2022-09-29T14:47:43.612Z - - - https://MannLabs.github.io/alphabase/peptide/mobility.html - 2022-09-29T14:47:43.904Z - - - https://MannLabs.github.io/alphabase/spectral_library/decoy_library.html - 2022-09-29T14:47:44.204Z - - - https://MannLabs.github.io/alphabase/spectral_library/library_base.html - 2022-09-29T14:47:44.564Z - - - https://MannLabs.github.io/alphabase/constants/modification.html - 2022-09-29T14:47:44.929Z - - - https://MannLabs.github.io/alphabase/constants/element.html - 2022-09-29T14:47:45.267Z - - - https://MannLabs.github.io/alphabase/constants/isotope.html - 2022-09-29T14:47:45.583Z - - - https://MannLabs.github.io/alphabase/constants/aa.html - 2022-09-29T14:47:45.887Z - - - https://MannLabs.github.io/alphabase/protein/fasta.html - 2022-09-29T14:47:46.453Z - - - https://MannLabs.github.io/alphabase/protein/test_fasta.html - 2022-09-29T14:47:46.726Z - - - https://MannLabs.github.io/alphabase/io/hdf.html - 2022-09-29T14:47:46.986Z - - - https://MannLabs.github.io/alphabase/yaml_utils.html - 2022-09-29T14:47:47.257Z - - - https://MannLabs.github.io/alphabase/index.html - 2022-09-29T14:47:47.582Z - - diff --git a/docs/spectral_library/base.rst b/docs/spectral_library/base.rst new file mode 100644 index 00000000..f4c508dc --- /dev/null +++ b/docs/spectral_library/base.rst @@ -0,0 +1,7 @@ +alphabase.spectral_library.base +=================================== + +.. automodule:: alphabase.spectral_library.base + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/spectral_library/decoy.rst b/docs/spectral_library/decoy.rst new file mode 100644 index 00000000..5017802f --- /dev/null +++ b/docs/spectral_library/decoy.rst @@ -0,0 +1,7 @@ +alphabase.spectral_library.decoy +================================= + +.. automodule:: alphabase.spectral_library.decoy + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/spectral_library/decoy_library.html b/docs/spectral_library/decoy_library.html deleted file mode 100644 index 79f74a46..00000000 --- a/docs/spectral_library/decoy_library.html +++ /dev/null @@ -1,659 +0,0 @@ - - - - - - - - - -alphabase - Decoy Libraries - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- -
- - - - - -
- -
-
-

Decoy Libraries

-
- - - -
- - - -
- - -
- - -
-

source

-
-

DiaNNDecoyLib

-
-
 DiaNNDecoyLib
-                (target_lib:alphabase.spectral_library.library_base.SpecLi
-                bBase, raw_AAs:str='GAVLIFMPWSCTYHKRQEND',
-                mutated_AAs:str='LLLVVLLLLTSSSSLLNDQE', **kwargs)
-
-

DiaNN-like decoy peptide generator

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
target_libSpecLibBaseTarget library object
raw_AAsstrGAVLIFMPWSCTYHKRQENDAAs those DiaNN decoy from.
Defaults to ‘GAVLIFMPWSCTYHKRQEND’.
mutated_AAsstrLLLVVLLLLTSSSSLLNDQEDiaNN
kwargs
-
-

source

-
-
-

DecoyLib

-
-
 DecoyLib (target_lib:alphabase.spectral_library.library_base.SpecLibBase,
-           fix_C_term=True, **kwargs)
-
-

Pseudo-reverse peptide decoy generator Currently, only sequence-level decoy is implemented, but AlphaPeptDeep will add modifications onto both target and decoy sequences, so it is enough for practical uses.

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
target_libSpecLibBaseTarget library to decoy.
fix_C_termboolTrueIf fix C-term AA when decoy.
Defaults to True.
kwargs
-
-

source

-
-
-

DecoyLib.decoy_sequence

-
-
 DecoyLib.decoy_sequence ()
-
-

Generate decoy sequences from self.target_lib

-
-

source

-
-
-

DecoyLibProvider

-
-
 DecoyLibProvider ()
-
-

Initialize self. See help(type(self)) for accurate signature.

-
-

source

-
-
-

DecoyLibProvider.get_decoy_lib

-
-
 DecoyLibProvider.get_decoy_lib (name:str,
-                                 target_lib:alphabase.spectral_library.lib
-                                 rary_base.SpecLibBase, **kwargs)
-
-

Get an object of a subclass of DecoyLib based on registered name.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDetails
namestrRegistered decoy class name
target_libSpecLibBaseTarget library for decoy generation
kwargs
ReturnsDecoyLibDecoy library object
-
-
-

Registered decoy methods

-
-
decoy_lib_provider.decoy_dict
-
-
{'pseudo_reverse': __main__.DecoyLib, 'diann': __main__.DiaNNDecoyLib}
-
-
- - -
- -
- -
- - - - \ No newline at end of file diff --git a/docs/spectral_library/flat.rst b/docs/spectral_library/flat.rst new file mode 100644 index 00000000..b554ebdf --- /dev/null +++ b/docs/spectral_library/flat.rst @@ -0,0 +1,7 @@ +alphabase.spectral_library.flat +================================ + +.. automodule:: alphabase.spectral_library.flat + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/spectral_library/library_base.html b/docs/spectral_library/library_base.html deleted file mode 100644 index f3120900..00000000 --- a/docs/spectral_library/library_base.html +++ /dev/null @@ -1,1183 +0,0 @@ - - - - - - - - - -alphabase - Base Class for Spectral Libraries - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- -
- - - - - -
- -
-
-

Base Class for Spectral Libraries

-
- - - -
- - - -
- - -
- - -
/Users/zengwenfeng/opt/anaconda3/lib/python3.8/site-packages/fastcore/docscrape.py:225: UserWarning: Unknown section Attributes
-  else: warn(msg)
-
-

source

-
-

SpecLibBase

-
-
 SpecLibBase (charged_frag_types:List[str]=['b_z1', 'b_z2', 'y_z1',
-              'y_z2'], precursor_mz_min=400, precursor_mz_max=6000,
-              decoy:str=None)
-
-

Base spectral library in alphabase and alphapeptdeep.

- ------ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
charged_frag_typestyping.List[str][‘b_z1’, ‘b_z2’, ‘y_z1’, ‘y_z2’][‘b_z1’,‘b_z2’,‘y_z1’,‘y_modloss_z1’, …];
‘b_z1’: ‘b’ is the fragment type and
‘z1’ is the charge state z=1.
precursor_mz_minint400Use this to clip precursor df.
Defaults to 400.
precursor_mz_maxint6000Use this to clip precursor df.
Defaults to 6000.
decoystrNoneDecoy methods, could be “pseudo_reverse” or “diann”.
Defaults to None.
-
-

source

-
-
-

SpecLibBase.append_decoy_sequence

-
-
 SpecLibBase.append_decoy_sequence ()
-
-

Append decoy sequence into precursor_df. Decoy method is based on self.decoy(str).

-
decoy_lib = (
-    decoy_lib_provider.get_decoy_lib(
-        self.decoy, self
-    )
-)
-decoy_lib.decoy_sequence()
-...
-
-

source

-
-
-

SpecLibBase.hash_precursor_df

-
-
 SpecLibBase.hash_precursor_df ()
-
-

Insert hash codes for peptides and precursors

-
-

source

-
-
-

SpecLibBase.calc_precursor_isotope

-
-
 SpecLibBase.calc_precursor_isotope (multiprocessing:bool=True,
-                                     mp_process_num:int=8,
-                                     mp_process_bar=None,
-                                     min_num_for_mp:int=1000)
-
-

Append isotope columns into self.precursor_df. See alphabase.peptide.precursor.calc_precursor_isotope for details.

-
-

source

-
-
-

SpecLibBase.flatten_fragment_data

-
-
 SpecLibBase.flatten_fragment_data ()
-
-

Create flattened (1-D) np.ndarray for fragment mz and intensity dataframes, respectively. The arrays are references to original data, that means: 1. This method is fast; 2. Changing the array values will change the df values. They can be unraveled back using: array.reshape(len(self._fragment_mz_df.columns), -1)

-
-

source

-
-
-

SpecLibBase.calc_precursor_mz

-
-
 SpecLibBase.calc_precursor_mz ()
-
-

Calculate precursor mz for self._precursor_df, and clip the self._precursor_df using self.clip_by_precursor_mz_

-
-

source

-
-
-

SpecLibBase.clip_by_precursor_mz_

-
-
 SpecLibBase.clip_by_precursor_mz_ ()
-
-

Clip self._precursor_df inplace by self.min_precursor_mz and self.max_precursor_mz

-
-

source

-
-
-

SpecLibBase.load_hdf

-
-
 SpecLibBase.load_hdf (hdf_file:str, load_mod_seq:bool=False)
-
-

Load the hdf library from hdf_file

- ------ - - - - - - - - - - - - - - - - - - - - - - -
TypeDefaultDetails
hdf_filestrhdf library path to load
load_mod_seqboolFalseif also load mod_seq_df.
Defaults to False.
-
-

source

-
-
-

SpecLibBase.load_df_from_hdf

-
-
 SpecLibBase.load_df_from_hdf (hdf_file:str, df_name:str)
-
-

Load specific dataset (dataframe) from hdf_file.

- - - - - - - - - - - - - - - - - - - - - - - - - -
TypeDetails
hdf_filestrThe hdf file name
df_namestrThe dataset/dataframe name in the hdf file
ReturnsDataFrameLoaded dataframe
-
-

source

-
-
-

SpecLibBase.save_hdf

-
-
 SpecLibBase.save_hdf (hdf_file:str)
-
-

Save library dataframes into hdf_file. For self.precursor_df, this method will save it into two hdf groups: hdf_file: library/precursor_df and library/mod_seq_df.

-

library/precursor_df contains all essential numberic columns those can be loaded faster from hdf file into memory: ‘precursor_mz’, ‘charge’, ‘mod_seq_hash’, ‘mod_seq_charge_hash’, ‘frag_start_idx’, ‘frag_end_idx’, ‘decoy’, ‘rt_pred’, ‘ccs_pred’, ‘mobility_pred’, ‘miss_cleave’, ‘nAA’, [‘isotope_mz_m1’, ‘isotope_intensity_m1’], …

-

library/mod_seq_df contains all string columns and the other not essential columns: ‘sequence’,‘mods’,‘mod_sites’, [‘proteins’, ‘genes’]… as well as ‘mod_seq_hash’, ‘mod_seq_charge_hash’ columns to map back to precursor_df

- - - - - - - - - - - - - - - -
TypeDetails
hdf_filestrthe hdf file path to save
-
-

source

-
-
-

SpecLibBase.save_df_to_hdf

-
-
 SpecLibBase.save_df_to_hdf (hdf_file:str, df_key:str,
-                             df:pandas.core.frame.DataFrame,
-                             delete_existing=False)
-
-

Save a new HDF group or dataset into existing HDF file

-
-

source

-
-
-

SpecLibBase.refine_df

-
-
 SpecLibBase.refine_df ()
-
-

Sort nAA and reset_index for faster calculation (or prediction)

-
-

source

-
-
-

SpecLibBase.calc_precursor_isotope

-
-
 SpecLibBase.calc_precursor_isotope (multiprocessing:bool=True,
-                                     mp_process_num:int=8,
-                                     mp_process_bar=None,
-                                     min_num_for_mp:int=1000)
-
-

Append isotope columns into self.precursor_df. See alphabase.peptide.precursor.calc_precursor_isotope for details.

-
-
-

Testing

-
-
import pandas as pd
-import os
-
-
-
repeat = 3
-peptides = ['AGHCEWQMK']*repeat
-mods = ['Acetyl@Protein N-term;Carbamidomethyl@C;Oxidation@M']*repeat
-sites = ['0;4;8']*repeat
-peptides += ['AGHCEWQMKAADER']*repeat
-mods += ['']*repeat
-sites += ['']*repeat
-
-precursor_df = pd.DataFrame({
-    'sequence': peptides,
-    'mods': mods,
-    'mod_sites': sites
-})
-precursor_df['nAA'] = precursor_df['sequence'].str.len()
-precursor_df['charge'] = 2
-target_lib = SpecLibBase(
-    ['b_z1','b_z2','y_z1','y_z2'],
-    decoy='pseudo_reverse'
-)
-target_lib._precursor_df = precursor_df
-target_lib.calc_precursor_mz()
-target_lib._fragment_mz_df = pd.DataFrame()
-target_lib._fragment_intensity_df = pd.DataFrame()
-if not os.path.isdir('sandbox'):
-    os.makedirs('sandbox')
-target_lib.save_hdf('sandbox/test_lib.hdf')
-target_lib.save_df_to_hdf('sandbox/test_lib.hdf','protein_df',pd.DataFrame(
-    {
-        'id':[1,2],
-        'full_name': [1,2],
-        'description': [1,2],
-        'sequence': [1,2]
-    })
-)
-new_lib = SpecLibBase([])
-new_lib.load_hdf('sandbox/test_lib.hdf')
-
-assert len(new_lib.precursor_df) > 0
-assert len(new_lib.fragment_mz_df) == 0
-assert len(new_lib.fragment_intensity_df) == 0
-
-assert 'sequence' not in new_lib.precursor_df.columns
-assert 'mod_seq_hash' in new_lib.precursor_df.columns
-
-
-new_lib = SpecLibBase([])
-new_lib.load_hdf('sandbox/test_lib.hdf', load_mod_seq=True)
-assert 'sequence' in new_lib.precursor_df.columns
-assert 'mod_seq_hash' in new_lib.precursor_df.columns
-
-df = target_lib.load_df_from_hdf('sandbox/test_lib.hdf', 'precursor_df')
-assert len(precursor_df)==len(df)
-df = target_lib.load_df_from_hdf('sandbox/test_lib.hdf', 'protein_df')
-assert len(df)==2
-os.remove('sandbox/test_lib.hdf')
-precursor_df
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sequencemodsmod_sitesnAAchargeprecursor_mzmod_seq_hashmod_seq_charge_hash
0AGHCEWQMKAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;892602.747333-5783464648586361190-5783464648586361188
1AGHCEWQMKAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;892602.747333-5783464648586361190-5783464648586361188
2AGHCEWQMKAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;892602.747333-5783464648586361190-5783464648586361188
3AGHCEWQMKAADER142816.356299-1606275412423975023-1606275412423975021
4AGHCEWQMKAADER142816.356299-1606275412423975023-1606275412423975021
5AGHCEWQMKAADER142816.356299-1606275412423975023-1606275412423975021
-
-
-
-
-
target_lib.append_decoy_sequence()
-assert len(target_lib.precursor_df) == len(precursor_df)*2
-target_lib.precursor_df
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sequencemodsmod_sitesnAAchargeprecursor_mzmod_seq_hashmod_seq_charge_hashdecoy
0AGHCEWQMKAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;892602.747333-5783464648586361190-57834646485863611880
1AGHCEWQMKAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;892602.747333-5783464648586361190-57834646485863611880
2AGHCEWQMKAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;892602.747333-5783464648586361190-57834646485863611880
3MQWECHGAKAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;892602.747333-5783464648586361190-57834646485863611881
4MQWECHGAKAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;892602.747333-5783464648586361190-57834646485863611881
5MQWECHGAKAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;892602.747333-5783464648586361190-57834646485863611881
6AGHCEWQMKAADER142816.356299-1606275412423975023-16062754124239750210
7AGHCEWQMKAADER142816.356299-1606275412423975023-16062754124239750210
8AGHCEWQMKAADER142816.356299-1606275412423975023-16062754124239750210
9EDAAKMQWECHGAR142816.356299-1606275412423975023-16062754124239750211
10EDAAKMQWECHGAR142816.356299-1606275412423975023-16062754124239750211
11EDAAKMQWECHGAR142816.356299-1606275412423975023-16062754124239750211
-
-
-
-
-
target_lib.calc_fragment_mz_df()
-assert 'b_z1' in target_lib.fragment_mz_df
-assert len(target_lib.fragment_mz_df) == np.sum(target_lib.precursor_df.nAA-1)
-target_lib.fragment_mz_df
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
b_z1b_z2y_z1y_z2
0114.05495557.5311161091.439712546.223494
1171.07641986.0418481034.418248517.712762
2308.135331154.571303897.359336449.183306
3468.165979234.586628737.328687369.167982
4597.208572299.107924608.286094304.646685
...............
1211089.466972545.237124543.245626272.126451
1221192.476157596.741717440.236442220.621859
1231329.535069665.271173303.177530152.092403
1241386.556532693.781904246.156066123.581671
1251457.593646729.300461175.11895288.063114
-

126 rows × 4 columns

-
-
-
- - -
- -
- -
- - - - \ No newline at end of file diff --git a/docs/spectral_library/reader.rst b/docs/spectral_library/reader.rst new file mode 100644 index 00000000..085223b3 --- /dev/null +++ b/docs/spectral_library/reader.rst @@ -0,0 +1,9 @@ +alphabase.spectral_library.reader +================================== + +See examples in :doc:`library_reader notebook <../nbs/library_reader>`. + +.. automodule:: alphabase.spectral_library.reader + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/spectral_library/translate.rst b/docs/spectral_library/translate.rst new file mode 100644 index 00000000..99eee904 --- /dev/null +++ b/docs/spectral_library/translate.rst @@ -0,0 +1,7 @@ +alphabase.spectral_library.translate +===================================== + +.. automodule:: alphabase.spectral_library.translate + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/statistics/regression.rst b/docs/statistics/regression.rst new file mode 100644 index 00000000..d547e9cb --- /dev/null +++ b/docs/statistics/regression.rst @@ -0,0 +1,7 @@ +alphabase.statistics.regression +=================================== + +.. automodule:: alphabase.statistics.regression + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/styles.css b/docs/styles.css deleted file mode 100644 index 66ccc49e..00000000 --- a/docs/styles.css +++ /dev/null @@ -1,37 +0,0 @@ -.cell { - margin-bottom: 1rem; -} - -.cell > .sourceCode { - margin-bottom: 0; -} - -.cell-output > pre { - margin-bottom: 0; -} - -.cell-output > pre, .cell-output > .sourceCode > pre, .cell-output-stdout > pre { - margin-left: 0.8rem; - margin-top: 0; - background: none; - border-left: 2px solid lightsalmon; - border-top-left-radius: 0; - border-top-right-radius: 0; -} - -.cell-output > .sourceCode { - border: none; -} - -.cell-output > .sourceCode { - background: none; - margin-top: 0; -} - -div.description { - padding-left: 2px; - padding-top: 5px; - font-style: italic; - font-size: 135%; - opacity: 70%; -} diff --git a/docs/utils.html b/docs/utils.html deleted file mode 100644 index 65dfdc4d..00000000 --- a/docs/utils.html +++ /dev/null @@ -1,439 +0,0 @@ - - - - - - - - - -alphabase - Utils - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- -
- - - - - -
- -
-
-

Utils

-
- - - -
- - - -
- - -
- - -
-

source

-
-

explode_multiple_columns

-
-
 explode_multiple_columns (df:pandas.core.frame.DataFrame, columns:list)
-
-
-

source

-
-
-

process_bar

-
-
 process_bar (iterator, len_iter)
-
- - -
- -
- -
- - - - \ No newline at end of file diff --git a/docs/yaml_utils.html b/docs/yaml_utils.html deleted file mode 100644 index 57c285c2..00000000 --- a/docs/yaml_utils.html +++ /dev/null @@ -1,439 +0,0 @@ - - - - - - - - - -alphabase - YAML Utils - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- - -
- -
- - - - - -
- -
-
-

YAML Utils

-
- - - -
- - - -
- - -
- - -
-

source

-
-

save_yaml

-
-
 save_yaml (filename, settings)
-
-
-

source

-
-
-

load_yaml

-
-
 load_yaml (filename)
-
- - -
- -
- -
- - - - \ No newline at end of file diff --git a/misc/conda_dev_env.yaml b/misc/conda_dev_env.yaml new file mode 100644 index 00000000..b324c186 --- /dev/null +++ b/misc/conda_dev_env.yaml @@ -0,0 +1,7 @@ +name: alphabase +channels: + - defaults +dependencies: + - python=3.8 + - pip: + - -e ../.[development] -U \ No newline at end of file diff --git a/misc/loose_pip_install.sh b/misc/loose_pip_install.sh index 27c000ef..629a3258 100644 --- a/misc/loose_pip_install.sh +++ b/misc/loose_pip_install.sh @@ -1,5 +1,5 @@ conda create -n alphabase python=3.8 -y conda activate alphabase -pip install -e '../.[development]' +pip install -e '../.[development]' -U alphabase conda deactivate diff --git a/misc/stable_pip_install.sh b/misc/stable_pip_install.sh index 228c620c..21869426 100644 --- a/misc/stable_pip_install.sh +++ b/misc/stable_pip_install.sh @@ -1,5 +1,5 @@ conda create -n alphabase python=3.8 -y conda activate alphabase -pip install -e '../.[stable,development-stable]' +pip install -e '../.[stable,development-stable]' -U alphabase conda deactivate diff --git a/nbdev_nbs/constants/aa.ipynb b/nbdev_nbs/constants/aa.ipynb index bad302a9..6c4ce489 100644 --- a/nbdev_nbs/constants/aa.ipynb +++ b/nbdev_nbs/constants/aa.ipynb @@ -6,7 +6,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| default_exp constants.aa" + "#---#| default_exp constants.aa" ] }, { @@ -16,43 +16,6 @@ "# Amino acid information" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - " \n", - "import os\n", - "import pandas as pd\n", - "import numpy as np\n", - "\n", - "from typing import Union, Tuple\n", - "\n", - "from alphabase.yaml_utils import load_yaml\n", - "\n", - "from alphabase.constants.element import (\n", - " calc_mass_from_formula, \n", - " MASS_H2O, parse_formula,\n", - ")\n", - "\n", - "from alphabase.constants._const import CONST_FILE_FOLDER" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "AA_CHEM:dict = load_yaml(\n", - " os.path.join(CONST_FILE_FOLDER, 'amino_acid.yaml')\n", - ")" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -70,40 +33,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| export\n", - "\n", - "def reset_AA_mass()->np.ndarray:\n", - " \"\"\"AA mass in np.array with shape (128,)\"\"\"\n", - " AA_ASCII_MASS = np.ones(128)*1e8\n", - " for aa, chem in AA_CHEM.items():\n", - " AA_ASCII_MASS[ord(aa)] = calc_mass_from_formula(chem)\n", - " return AA_ASCII_MASS\n", - "\n", - "#: AA mass array with ASCII code, mass of 'A' is AA_ASCII_MASS[ord('A')]\n", - "AA_ASCII_MASS:np.ndarray = reset_AA_mass()\n", - "\n", - "def reset_AA_df():\n", - " AA_DF = pd.DataFrame()\n", - " AA_DF['aa'] = [chr(aa) for aa in range(len(AA_ASCII_MASS))]\n", - " AA_DF['formula'] = ['']*len(AA_ASCII_MASS)\n", - " aa_idxes = []\n", - " formulas = []\n", - " for aa, formula in AA_CHEM.items():\n", - " aa_idxes.append(ord(aa))\n", - " formulas.append(formula)\n", - " AA_DF.loc[aa_idxes, 'formula'] = formulas\n", - " AA_DF['mass'] = AA_ASCII_MASS\n", - " return AA_DF\n", - "\n", - "#: 128-len AA dataframe\n", - "AA_DF:pd.DataFrame = reset_AA_df()\n", - "\n", - "#: AA to formula dict of dict. For example: {'K': {'C': n, 'O': m, ...}}\n", - "AA_formula:dict = {}\n", - "for aa, formula, mass in AA_DF.values:\n", - " AA_formula[aa] = dict(\n", - " parse_formula(formula)\n", - " )" + "from alphabase.constants.aa import *" ] }, { @@ -347,30 +277,6 @@ "Note that this function is rarely used in alphabase as it is not fast for a set of peptides." ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def calc_sequence_mass(\n", - " sequence: str\n", - ")->np.ndarray:\n", - " '''\n", - " Parameters\n", - " ----------\n", - " sequence : str\n", - " Unmodified peptide sequence\n", - "\n", - " Returns\n", - " -------\n", - " np.ndarray\n", - " Masses of each amino acid.\n", - " '''\n", - " return AA_ASCII_MASS[np.array(sequence,'c').view(np.int8)]" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -378,67 +284,6 @@ "We provide `calc_AA_masses_for_same_len_seqs` and `calc_sequence_masses_for_same_len_seqs` functions to fast calculate masses for a given array of AA sequences with same length. They are fast because they both use `slicing` and `reshape` operation based on `AA_ASCII_MASS` array." ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def calc_AA_masses_for_same_len_seqs(\n", - " sequence_array: np.ndarray\n", - ")->np.ndarray:\n", - " '''\n", - " Calculate AA masses for the array of same-len AA sequences.\n", - "\n", - " Parameters\n", - " ----------\n", - " sequence_array : np.ndarray\n", - " unmodified sequences with the same length.\n", - "\n", - " Returns\n", - " -------\n", - " np.ndarray\n", - " 2-D (array_size, sequence_len) array of masses.\n", - "\n", - " Raises\n", - " -------\n", - " ValueError\n", - " If sequences are not with the same length.\n", - " '''\n", - " return AA_ASCII_MASS[\n", - " # we use np.int32 here because unicode str \n", - " # uses 4 bytes for a char.\n", - " np.array(sequence_array).view(np.int32) \n", - " ].reshape(len(sequence_array), -1)\n", - "\n", - "def calc_sequence_masses_for_same_len_seqs(\n", - " sequence_array: np.ndarray\n", - ")->np.ndarray:\n", - " '''\n", - " Calculate sequence masses for the array of same-len AA sequences.\n", - "\n", - " Parameters\n", - " ----------\n", - " sequence_array : np.ndarray\n", - " unmodified sequences with the same length.\n", - "\n", - " Returns\n", - " -------\n", - " np.ndarray\n", - " 1-D (array_size, sequence_len) array of masses.\n", - " \n", - " Raises\n", - " -------\n", - " ValueError\n", - " If sequences are not with the same length.\n", - " '''\n", - " return np.sum(\n", - " calc_AA_masses_for_same_len_seqs(sequence_array),\n", - " axis=1\n", - " )+MASS_H2O\n" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -557,34 +402,6 @@ "`calc_AA_masses_for_var_len_seqs` is rarely used in alphabase." ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def calc_AA_masses_for_var_len_seqs(\n", - " sequence_array: np.ndarray\n", - ")->np.ndarray:\n", - " '''\n", - " We recommend to use `calc_AA_masses_for_same_len_seqs` as it is much faster.\n", - "\n", - " Parameters\n", - " ----------\n", - " sequence_array : np.ndarray\n", - " Sequences with variable lengths.\n", - " \n", - " Returns\n", - " -------\n", - " np.ndarray\n", - " 1D array of masses, zero values are padded to fill the max length.\n", - " '''\n", - " return AA_ASCII_MASS[\n", - " np.array(sequence_array).view(np.int32)\n", - " ].reshape(len(sequence_array), -1)" - ] - }, { "cell_type": "code", "execution_count": null, diff --git a/nbdev_nbs/constants/element.ipynb b/nbdev_nbs/constants/element.ipynb index eb9b6f01..ed515c0f 100644 --- a/nbdev_nbs/constants/element.ipynb +++ b/nbdev_nbs/constants/element.ipynb @@ -6,7 +6,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| default_exp constants.element" + "#---#| default_exp constants.element" ] }, { @@ -16,39 +16,6 @@ "# Atom element information" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "import os\n", - "import numpy as np\n", - "import numba\n", - "\n", - "from alphabase.yaml_utils import load_yaml\n", - "\n", - "from alphabase.constants._const import CONST_FILE_FOLDER" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "common_const_dict:dict = load_yaml(\n", - " os.path.join(CONST_FILE_FOLDER, 'common_constants.yaml')\n", - ")\n", - "\n", - "MASS_PROTON:float = common_const_dict['MASS_PROTON']\n", - "MASS_ISOTOPE:float = common_const_dict['MASS_ISOTOPE']" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -58,67 +25,6 @@ "`EMPTY_DIST` defines a \"zero element\", its monoisotopic position is 0 with abundance 1. It is used for abundance convolution between different isotopes (see `abundance_convolution`)." ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "MAX_ISOTOPE_LEN = common_const_dict['MAX_ISOTOPE_LEN']\n", - "EMPTY_DIST = np.zeros(MAX_ISOTOPE_LEN)\n", - "EMPTY_DIST[0] = 1\n", - "\n", - "@numba.njit\n", - "def truncate_isotope(\n", - " isotopes: np.ndarray, mono_idx: int\n", - ")->tuple:\n", - " '''\n", - " For a given isotope distribution (intensity patterns), \n", - " this function truncates the distribution by top \n", - " `MAX_ISOTOPE_LEN` neighbors those contain the monoisotopic \n", - " peak pointed by `mono_idx`.\n", - "\n", - " Parameters\n", - " ----------\n", - " isotopes : np.ndarray\n", - "\n", - " Isotope patterns with size > `MAX_ISOTOPE_LEN`.\n", - "\n", - " mono_idx : int\n", - "\n", - " Monoisotopic peak position (index) in the isotope patterns\n", - " \n", - " Returns\n", - " -------\n", - " int\n", - " \n", - " the new position of `mono_idx`\n", - "\n", - " int\n", - " \n", - " the start position of the truncated isotopes\n", - "\n", - " int\n", - " \n", - " the end position of the truncated isotopes\n", - " '''\n", - " trunc_start = mono_idx - 1\n", - " trunc_end = mono_idx + 1\n", - " while trunc_start >= 0 and trunc_end < len(isotopes) and (trunc_end-trunc_start-1)= isotopes[trunc_start]:\n", - " trunc_end += 1\n", - " else:\n", - " trunc_start -= 1\n", - " if trunc_end-trunc_start-1 < MAX_ISOTOPE_LEN:\n", - " if trunc_start == -1:\n", - " trunc_end = MAX_ISOTOPE_LEN\n", - " elif trunc_end == len(isotopes):\n", - " trunc_start = len(isotopes)-MAX_ISOTOPE_LEN-1\n", - " return mono_idx-trunc_start-1, trunc_start+1, trunc_end" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -135,109 +41,19 @@ ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "#| export\n", - "\n", - "#: chemical element information in dict defined by `nist_element.yaml`\n", - "CHEM_INFO_DICT = {}\n", - "\n", - "#: {element: mass}\n", - "CHEM_MONO_MASS = {}\n", - "\n", - "#: {element: np.ndarray of abundance distribution}\n", - "CHEM_ISOTOPE_DIST:numba.typed.Dict = numba.typed.Dict.empty(\n", - " key_type=numba.types.unicode_type,\n", - " value_type=numba.types.float64[:]\n", - ")\n", - "\n", - "#: {element: int (mono position)}\n", - "CHEM_MONO_IDX:numba.typed.Dict = numba.typed.Dict.empty(\n", - " key_type=numba.types.unicode_type,\n", - " value_type=numba.types.int64\n", - ")\n", - "\n", - "MASS_H2O:int = None #raise errors if the value is not reset\n", - "MASS_NH3:int = None\n", - "\n", - "def reset_elements():\n", - " for elem, items in CHEM_INFO_DICT.items():\n", - " isotopes = np.array(items['abundance'])\n", - " masses = np.array(items['mass'])\n", - " _sort_idx = np.argsort(masses)\n", - " masses = masses[_sort_idx]\n", - " isotopes = isotopes[_sort_idx]\n", - " _mass_pos = np.round(masses).astype(int)\n", - " _mass_pos = _mass_pos - _mass_pos[0]\n", - " if _mass_pos[-1] - _mass_pos[0] + 1 <= MAX_ISOTOPE_LEN:\n", - " _isos = np.zeros(MAX_ISOTOPE_LEN)\n", - " _isos[_mass_pos] = isotopes\n", - " _masses = np.zeros(MAX_ISOTOPE_LEN)\n", - " _masses[_mass_pos] = masses\n", - " mono_idx = np.argmax(_isos)\n", - "\n", - " CHEM_MONO_MASS[elem] = _masses[mono_idx]\n", - " CHEM_ISOTOPE_DIST[elem] = _isos\n", - " CHEM_MONO_IDX[elem] = mono_idx\n", - " else:\n", - " _isos = np.zeros(_mass_pos[-1] - _mass_pos[0] + 1)\n", - " _isos[_mass_pos] = isotopes\n", - " _masses = np.zeros(_mass_pos[-1] - _mass_pos[0] + 1)\n", - " _masses[_mass_pos] = masses\n", - " mono_idx = np.argmax(_isos)\n", - " CHEM_MONO_MASS[elem] = _masses[mono_idx]\n", - "\n", - " _mono_idx, start, end = truncate_isotope(_isos, mono_idx)\n", - "\n", - " CHEM_ISOTOPE_DIST[elem] = _isos[start:end]\n", - " CHEM_MONO_IDX[elem] = _mono_idx\n", - "\n", - "def load_elem_yaml(yaml_file:str):\n", - " '''Load built-in or user-defined element yaml file. Default yaml is: \n", - " os.path.join(_base_dir, 'nist_element.yaml')\n", - " '''\n", - " global CHEM_INFO_DICT\n", - " global CHEM_MONO_MASS\n", - " global CHEM_ISOTOPE_DIST\n", - " global CHEM_MONO_IDX\n", - " global MASS_H2O\n", - " global MASS_NH3\n", - "\n", - " CHEM_INFO_DICT = load_yaml(yaml_file)\n", - "\n", - " CHEM_MONO_MASS = {}\n", - " CHEM_ISOTOPE_DIST = numba.typed.Dict.empty(\n", - " key_type=numba.types.unicode_type,\n", - " value_type=numba.types.float64[:]\n", - " )\n", - " \n", - " CHEM_MONO_IDX = numba.typed.Dict.empty(\n", - " key_type=numba.types.unicode_type,\n", - " value_type=numba.types.int64\n", - " )\n", - "\n", - " reset_elements()\n", - " \n", - " MASS_H2O = CHEM_MONO_MASS['H']*2 + CHEM_MONO_MASS['O']\n", - " MASS_NH3 = CHEM_MONO_MASS['H']*3 + CHEM_MONO_MASS['N']\n", + "### Calculate mass from a formula\n", "\n", - "load_elem_yaml(\n", - " os.path.join(CONST_FILE_FOLDER,\n", - " 'nist_element.yaml'\n", - " )\n", - ")" + "Now we have `CHEM_MONO_MASS`, we can calculate the mass of different chemical formula. Formula format: `H(1)C(2)O(3)...`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Calculate mass from a formula\n", - "\n", - "Now we have `CHEM_MONO_MASS`, we can calculate the mass of different chemical formula. Formula format: `H(1)C(2)O(3)...`" + "Example" ] }, { @@ -246,46 +62,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| export\n", - "def parse_formula(\n", - " formula:str\n", - ")->list:\n", - " '''\n", - " Given a formula (str, e.g. `H(1)C(2)O(3)`), \n", - " it generates `[('H', 2), ('C', 2), ('O', 1)]`\n", - " '''\n", - " if not formula: return []\n", - " items = [item.split('(') for item in \n", - " formula.strip(')').split(')')\n", - " ]\n", - " return [(elem, int(n)) for elem, n in items]\n", - "\n", - "\n", - "def calc_mass_from_formula(formula:str):\n", - " '''\n", - " Calculates the mass of the formula`\n", - "\n", - " Parameters\n", - " ----------\n", - " formula : str\n", - " e.g. `H(1)C(2)O(3)`\n", - " \n", - " Returns\n", - " -------\n", - " float\n", - " mass of the formula\n", - " '''\n", - " return np.sum([\n", - " CHEM_MONO_MASS[elem]*n \n", - " for elem, n in parse_formula(formula)\n", - " ])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Example" + "from alphabase.constants.element import *" ] }, { diff --git a/nbdev_nbs/constants/isotope.ipynb b/nbdev_nbs/constants/isotope.ipynb index de66b6c5..56be1296 100644 --- a/nbdev_nbs/constants/isotope.ipynb +++ b/nbdev_nbs/constants/isotope.ipynb @@ -6,7 +6,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| default_exp constants.isotope" + "#---#| default_exp constants.isotope" ] }, { @@ -24,76 +24,19 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "import numba\n", - "import numpy as np\n", - "import typing\n", - "\n", - "from alphabase.constants.element import (\n", - " MAX_ISOTOPE_LEN, EMPTY_DIST,\n", - " CHEM_ISOTOPE_DIST, CHEM_MONO_IDX, CHEM_MONO_MASS,\n", - " truncate_isotope, parse_formula\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "#| export\n", - "@numba.njit\n", - "def abundance_convolution(\n", - " d1:np.ndarray,\n", - " mono1:int,\n", - " d2:np.ndarray,\n", - " mono2:int,\n", - ")->typing.Tuple[np.ndarray, int]:\n", - " '''\n", - " If we have two isotope distributions, \n", - " we can convolute them into one distribution. \n", - " \n", - " Parameters\n", - " ----------\n", - " d1 : np.ndarray\n", - " isotope distribution to convolute\n", - "\n", - " mono1 : int\n", - " mono position of d1.\n", - "\n", - " d2 : np.ndarray\n", - " isotope distribution to convolute\n", - "\n", - " mono2 : int\n", - " mono position of d2\n", - " \n", - " Returns\n", - " -------\n", - " tuple[np.ndarray,int]\n", - " np.ndarray, convoluted isotope distribution\n", - " int, new mono position.\n", - " '''\n", - " mono_idx = mono1 + mono2\n", - " ret = np.zeros(MAX_ISOTOPE_LEN*2-1)\n", - " for i in range(len(d1)):\n", - " for j in range(len(d2)):\n", - " ret[i+j] += d1[i]*d2[j]\n", - "\n", - " mono_idx, start, end = truncate_isotope(ret, mono_idx)\n", - " return ret[start:end], mono_idx" + "For a given chemical formula, e.g. `H(100)O(50)N(20)`, we first calculate the isotope distribution using \"binary search\"-like method for each type of element (here are `H(100)`, `O(50)` and `N(20)`) (see `one_element_dist`). And then we convolute these distributions of all types into one distribution (see `formula_dist`)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "For a given chemical formula, e.g. `H(100)O(50)N(20)`, we first calculate the isotope distribution using \"binary search\"-like method for each type of element (here are `H(100)`, `O(50)` and `N(20)`) (see `one_element_dist`). And then we convolute these distributions of all types into one distribution (see `formula_dist`)." + "Compare calculated isotope distributions with sisweb.com/mstools/isotope.htm\n", + "\n", + "Desired distribution for H10: (100, 0.16, 0.0001) calculated from sisweb.com/mstools/isotope.htm in low resolution mode (centroid mode)" ] }, { @@ -102,84 +45,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| export\n", - "@numba.njit\n", - "def one_element_dist(\n", - " elem: str,\n", - " n: int,\n", - " chem_isotope_dist: numba.typed.Dict,\n", - " chem_mono_idx: numba.typed.Dict,\n", - ")->typing.Tuple[np.ndarray, int]:\n", - " '''\n", - " Calculate the isotope distribution for \n", - " an element and its numbers.\n", - " \n", - " Parameters\n", - " ----------\n", - " elem : str\n", - " element.\n", - "\n", - " n : int\n", - " element number.\n", - "\n", - " chem_isotope_dist : numba.typed.Dict\n", - " use `CHEM_ISOTOPE_DIST` as parameter.\n", - "\n", - " chem_mono_idx : numba.typed.Dict\n", - " use `CHEM_MONO_IDX` as parameter.\n", - "\n", - " Returns\n", - " -------\n", - " tuple[np.ndarray, int]\n", - " np.ndarray, isotope distribution of the element.\n", - " int, mono position in the distribution\n", - " '''\n", - " if n == 0: return EMPTY_DIST.copy(), 0\n", - " elif n == 1: return chem_isotope_dist[elem], chem_mono_idx[elem]\n", - " tmp_dist, mono_idx = one_element_dist(elem, n//2, chem_isotope_dist, chem_mono_idx)\n", - " tmp_dist, mono_idx = abundance_convolution(tmp_dist, mono_idx, tmp_dist, mono_idx)\n", - " if n%2 == 0:\n", - " return tmp_dist, mono_idx\n", - " else:\n", - " return abundance_convolution(tmp_dist, mono_idx, chem_isotope_dist[elem], chem_mono_idx[elem])\n", - "\n", - "def formula_dist(\n", - " formula: typing.Union[list, str]\n", - ")->typing.Tuple[np.ndarray, int]:\n", - " '''\n", - " Generate the isotope distribution and the mono index for \n", - " a given formula (as a list, e.g. `[('H', 2), ('C', 2), ('O', 1)]`).\n", - "\n", - " Parameters\n", - " ----------\n", - " formula : Union[list, str]\n", - " chemical formula, could be str or list.\n", - " If str: \"H(1)N(2)O(3)\".\n", - " If list: \"[('H',1),('H',2),('H',3)]\".\n", - " \n", - " Returns\n", - " -------\n", - " tuple[np.ndarray,int]\n", - " np.ndarray, isotope distribution\n", - " int, mono position\n", - " '''\n", - " if isinstance(formula, str):\n", - " formula = parse_formula(formula)\n", - " calc_dist = EMPTY_DIST.copy()\n", - " mono_idx = 0\n", - " for elem, n in formula:\n", - " _dist, _mono = one_element_dist(elem, n, CHEM_ISOTOPE_DIST, CHEM_MONO_IDX)\n", - " calc_dist, mono_idx = abundance_convolution(calc_dist, mono_idx, _dist, _mono)\n", - " return calc_dist, mono_idx" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Compare calculated isotope distributions with sisweb.com/mstools/isotope.htm\n", - "\n", - "Desired distribution for H10: (100, 0.16, 0.0001) calculated from sisweb.com/mstools/isotope.htm in low resolution mode (centroid mode)" + "from alphabase.constants.isotope import *" ] }, { @@ -512,188 +378,6 @@ "`formula_dist` always calculates the distribution of each element based on the element number (using binary-search-like operation) and convolute distributions of different elements. If we have many peptides to calculate, each element's distribution will be calculated repeatly. In `IsotopeDistribution`, instead of generating on-the-fly, we pre-built the isotope distribution table for each of the most common elements (C,H,N,O,S,P) with the element number from 0 to N, and N is large enough to cover all composition in shotgun proteomics. Thus, for a given chemical formula, we just need to check the distribution table for each element and convolute distributions among different elements." ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def _calc_one_elem_cum_dist(\n", - " element_cum_dist:np.ndarray, \n", - " element_cum_mono:np.ndarray\n", - "):\n", - " \"\"\"Pre-build isotope abundance distribution for an element for fast calculation.\n", - " Internel function.\n", - " \n", - " Added information inplace into element_cum_dist and element_cum_mono\n", - "\n", - " Parameters\n", - " ----------\n", - " element_cum_dist : np.ndarray\n", - " Cumulated element abundance distribution\n", - "\n", - " element_cum_mono : np.ndarray\n", - " Cumulated element mono position in the distribution\n", - " \"\"\"\n", - " for n in range(2, len(element_cum_dist)):\n", - " (\n", - " element_cum_dist[n], \n", - " element_cum_mono[n]\n", - " ) = abundance_convolution(\n", - " element_cum_dist[n-1],\n", - " element_cum_mono[n-1],\n", - " element_cum_dist[1],\n", - " element_cum_mono[1]\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "class IsotopeDistribution:\n", - " def __init__(self, \n", - " max_elem_num_dict:dict = {\n", - " 'C': 2000,\n", - " 'H': 5000,\n", - " 'N': 1000,\n", - " 'O': 1000,\n", - " 'S': 200,\n", - " 'P': 200,\n", - " }\n", - " ):\n", - " \"\"\"Faster calculation of isotope abundance distribution by pre-building\n", - " isotope distribution tables for most common elements.\n", - "\n", - " We have considered large enough number of elements for shotgun proteomics.\n", - " We can increase `max_elem_num_dict` to support larger peptide or top-down \n", - " in the future. However, current `MAX_ISOTOPE_LEN` is not suitable for top-down,\n", - " it must be extended to a larger number (100?).\n", - " Note that non-standard amino acids have 1000000 C elements in AlphaBase,\n", - " We clip 1000000 C to the maximal number of C in `max_elem_num_dict`.\n", - " As they have very large masses thus impossible to identify,\n", - " their isotope distributions do not matter.\n", - "\n", - " Parameters\n", - " ----------\n", - " max_elem_num_dict : dict, optional\n", - " Define the maximal number of the elements. \n", - " Defaults to { 'C': 2000, 'H': 5000, 'N': 1000, 'O': 1000, 'S': 200, 'P': 200, } \n", - " \n", - " Attributes\n", - " ----------\n", - " element_to_cum_dist_dict : dict \n", - " {element: cumulated isotope distribution array},\n", - " and the cumulated isotope distribution array is a 2-D float np.ndarray with \n", - " shape (element_max_number, MAX_ISOTOPE_LEN).\n", - "\n", - " element_to_cum_mono_idx : dict\n", - " {element: mono position array of cumulated isotope distribution},\n", - " and mono position array is a 1-D int np.ndarray.\n", - " \"\"\"\n", - " self.element_to_cum_dist_dict = {}\n", - " self.element_to_cum_mono_idx = {}\n", - " for elem, n in max_elem_num_dict.items():\n", - " if n < 2: n = 2\n", - " self.element_to_cum_dist_dict[elem] = np.zeros((n, MAX_ISOTOPE_LEN))\n", - " self.element_to_cum_mono_idx[elem] = -np.ones(n,dtype=np.int64)\n", - " self.element_to_cum_dist_dict[elem][0,:] = EMPTY_DIST\n", - " self.element_to_cum_mono_idx[elem][0] = 0\n", - " self.element_to_cum_dist_dict[elem][1,:] = CHEM_ISOTOPE_DIST[elem]\n", - " self.element_to_cum_mono_idx[elem][1] = CHEM_MONO_IDX[elem]\n", - " _calc_one_elem_cum_dist(\n", - " self.element_to_cum_dist_dict[elem],\n", - " self.element_to_cum_mono_idx[elem]\n", - " )\n", - "\n", - " def calc_formula_distribution(self,\n", - " formula: typing.List[typing.Tuple[str,int]],\n", - " )->typing.Tuple[np.ndarray, int]:\n", - " \"\"\"Calculate isotope abundance distribution for a given formula\n", - "\n", - " Parameters\n", - " ----------\n", - " formula : List[tuple(str,int)]\n", - " chemical formula: \"[('H',1),('C',2),('O',3)]\".\n", - "\n", - " Returns\n", - " -------\n", - " tuple[np.ndarray, int]\n", - " np.ndarray, isotope abundance distribution\n", - " int, monoisotope position in the distribution array\n", - " \n", - " Examples\n", - " --------\n", - " >>> from alphabase.constants import IsotopeDistribution, parse_formula\n", - " >>> iso = IsotopeDistribution()\n", - " >>> formula = 'C(100)H(100)O(10)Na(1)Fe(1)'\n", - " >>> formula = parse_formula(formula)\n", - " >>> dist, mono = iso.calc_formula_distribution(formula)\n", - " >>> dist\n", - " array([1.92320044e-02, 2.10952666e-02, 3.13753566e-01, 3.42663681e-01,\n", - " 1.95962632e-01, 7.69157517e-02, 2.31993814e-02, 5.71948249e-03,\n", - " 1.19790438e-03, 2.18815385e-04])\n", - " >>> # Fe's mono position is 2 Da larger than its smallest mass, \n", - " >>> # so the mono position of this formula shifts by +2 (Da).\n", - " >>> mono \n", - " 2\n", - "\n", - " >>> formula = 'C(100)H(100)O(10)13C(1)Na(1)' \n", - " >>> formula = parse_formula(formula)\n", - " >>> dist, mono = iso.calc_formula_distribution(formula)\n", - " >>> dist\n", - " array([3.29033438e-03, 3.29352217e-01, 3.59329960e-01, 2.01524592e-01,\n", - " 7.71395498e-02, 2.26229845e-02, 5.41229894e-03, 1.09842389e-03,\n", - " 1.94206388e-04, 3.04911585e-05])\n", - " >>> # 13C's mono position is +1 Da shifted\n", - " >>> mono\n", - " 1\n", - "\n", - " >>> formula = 'C(100)H(100)O(10)Na(1)' \n", - " >>> formula = parse_formula(formula)\n", - " >>> dist, mono = iso.calc_formula_distribution(formula)\n", - " >>> dist\n", - " array([3.29033438e-01, 3.60911319e-01, 2.02775462e-01, 7.76884706e-02,\n", - " 2.27963906e-02, 5.45578135e-03, 1.10754072e-03, 1.95857410e-04,\n", - " 3.07552058e-05, 4.35047710e-06])\n", - " >>> # mono position is normal (=0) for regular formulas\n", - " >>> mono\n", - " 0\n", - " \n", - " \"\"\"\n", - " first_elem = 'H'\n", - " for elem, n in formula:\n", - " if elem == first_elem:\n", - " if n >= len(self.element_to_cum_mono_idx[elem]):\n", - " n = len(self.element_to_cum_mono_idx[elem])-1\n", - " mono = self.element_to_cum_mono_idx[elem][n]\n", - " dist = self.element_to_cum_dist_dict[elem][n]\n", - " break\n", - " for elem, n in formula:\n", - " if elem in self.element_to_cum_dist_dict:\n", - " if elem == first_elem: continue\n", - " if n >= len(self.element_to_cum_mono_idx[elem]):\n", - " n = len(self.element_to_cum_mono_idx[elem])-1\n", - " dist, mono = abundance_convolution(\n", - " dist, mono,\n", - " self.element_to_cum_dist_dict[elem][n],\n", - " self.element_to_cum_mono_idx[elem][n],\n", - " )\n", - " else:\n", - " dist, mono = abundance_convolution(\n", - " dist, mono, *one_element_dist(\n", - " elem,n,CHEM_ISOTOPE_DIST, CHEM_MONO_IDX\n", - " )\n", - " )\n", - " return dist, mono\n" - ] - }, { "cell_type": "code", "execution_count": null, diff --git a/nbdev_nbs/constants/modification.ipynb b/nbdev_nbs/constants/modification.ipynb index 045dc774..a9f0bea9 100644 --- a/nbdev_nbs/constants/modification.ipynb +++ b/nbdev_nbs/constants/modification.ipynb @@ -6,7 +6,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| default_exp constants.modification" + "#---#| default_exp constants.modification" ] }, { @@ -35,118 +35,8 @@ "metadata": {}, "outputs": [], "source": [ - "#| export\n", - "\n", - "import os\n", - "import numba\n", - "import numpy as np\n", - "import pandas as pd\n", - "from typing import Union, List\n", - "\n", - "from alphabase.constants.element import (\n", - " calc_mass_from_formula, parse_formula,\n", - ")\n", - "\n", - "from alphabase.constants._const import CONST_FILE_FOLDER" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "MOD_DF:pd.DataFrame = pd.DataFrame()\n", - "\n", - "MOD_INFO_DICT:dict = {}\n", - "#: Modification to formula str dict. {mod_name: formula str ('H(1)C(2)O(3)')}\n", - "MOD_CHEM:dict = {}\n", - "#: Modification to mass dict.\n", - "MOD_MASS:dict = {}\n", - "#: Modification to modification neutral loss dict.\n", - "MOD_LOSS_MASS:dict = {}\n", - "#: Modification to formula dict of dict. i.e. {modname: {'C': n, 'H': m, ...}}\n", - "MOD_formula:dict = {}\n", - "#: Modification loss importance\n", - "MOD_LOSS_IMPORTANCE:dict = {}\n", - "\n", - "def update_all_by_MOD_DF():\n", - " \"\"\"\n", - " As DataFrame is more conveneint in data operation, \n", - " we can also process MOD_DF and then update all global \n", - " modification variables from MOD_DF\n", - " \"\"\"\n", - " \n", - " MOD_INFO_DICT.clear()\n", - " MOD_INFO_DICT.update(MOD_DF.to_dict(orient='index'))\n", - " MOD_CHEM.clear()\n", - " MOD_CHEM.update(MOD_DF['composition'].to_dict())\n", - " MOD_MASS.clear()\n", - " MOD_MASS.update(MOD_DF['mass'].to_dict())\n", - " MOD_LOSS_MASS.clear()\n", - " MOD_LOSS_MASS.update(MOD_DF['modloss'].to_dict())\n", - " MOD_LOSS_IMPORTANCE.clear()\n", - " MOD_LOSS_IMPORTANCE.update(MOD_DF['modloss_importance'].to_dict())\n", - "\n", - " MOD_formula.clear()\n", - " for mod, chem in MOD_CHEM.items():\n", - " MOD_formula[mod] = dict(parse_formula(chem))\n", - "\n", - "def add_modifications_for_lower_case_AA():\n", - " \"\"\" Add modifications for lower-case AAs for advanced usages \"\"\"\n", - " global MOD_DF\n", - " lower_case_df = MOD_DF.copy()\n", - " \n", - " def _mod_lower_case(modname):\n", - " modname, site = modname.split('@')\n", - " if len(site) == 1:\n", - " return modname+'@'+site.lower()\n", - " elif '^' in site:\n", - " site = site[0].lower()+site[1:]\n", - " return modname+'@'+site\n", - " else:\n", - " return ''\n", - " lower_case_df['mod_name'] = lower_case_df['mod_name'].apply(_mod_lower_case)\n", - " lower_case_df = lower_case_df[lower_case_df['mod_name']!='']\n", - " lower_case_df.set_index('mod_name', drop=False, inplace=True)\n", - " lower_case_df['lower_case_AA'] = True\n", - " MOD_DF['lower_case_AA'] = False\n", - " MOD_DF = pd.concat([MOD_DF, lower_case_df])\n", - " update_all_by_MOD_DF()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def keep_modloss_by_importance(modloss_importance_level:float=1.0):\n", - " MOD_DF['modloss'] = MOD_DF['modloss_original']\n", - " MOD_DF.loc[MOD_DF.modloss_importancemass\n", " modloss_original\n", " modloss\n", + " lower_case_AA\n", " \n", " \n", " mod_name\n", @@ -204,6 +95,7 @@ " \n", " \n", " \n", + " \n", " \n", " \n", " \n", @@ -222,6 +114,7 @@ " 114.042927\n", " 114.042927\n", " 114.042927\n", + " False\n", " \n", " \n", " 15N-oxobutanoic@C^Any N-term\n", @@ -238,6 +131,7 @@ " -18.023584\n", " 0.000000\n", " 0.000000\n", + " False\n", " \n", " \n", " 15N-oxobutanoic@S^Protein N-term\n", @@ -254,6 +148,7 @@ " -18.023584\n", " 0.000000\n", " 0.000000\n", + " False\n", " \n", " \n", " 15N-oxobutanoic@T^Protein N-term\n", @@ -270,6 +165,7 @@ " -18.023584\n", " 0.000000\n", " 0.000000\n", + " False\n", " \n", " \n", " 2-dimethylsuccinyl@C\n", @@ -286,6 +182,7 @@ " 144.042259\n", " 0.000000\n", " 0.000000\n", + " False\n", " \n", " \n", " ...\n", @@ -302,10 +199,11 @@ " ...\n", " ...\n", " ...\n", + " ...\n", " \n", " \n", - " spermidine@Q\n", - " spermidine@Q\n", + " spermidine@q\n", + " spermidine@q\n", " 128.215300\n", " Chemical derivative\n", " H(16)C(7)N(2)\n", @@ -318,10 +216,11 @@ " 128.131349\n", " 0.000000\n", " 0.000000\n", + " True\n", " \n", " \n", - " spermine@Q\n", - " spermine@Q\n", + " spermine@q\n", + " spermine@q\n", " 185.309700\n", " Chemical derivative\n", " H(23)C(10)N(3)\n", @@ -334,10 +233,11 @@ " 185.189198\n", " 0.000000\n", " 0.000000\n", + " True\n", " \n", " \n", - " sulfo+amino@Y\n", - " sulfo+amino@Y\n", + " sulfo+amino@y\n", + " sulfo+amino@y\n", " 95.077800\n", " Chemical derivative\n", " H(1)N(1)O(3)S(1)\n", @@ -350,10 +250,11 @@ " 94.967714\n", " 0.000000\n", " 0.000000\n", + " True\n", " \n", " \n", - " thioacylPA@K\n", - " thioacylPA@K\n", + " thioacylPA@k\n", + " thioacylPA@k\n", " 159.206200\n", " Chemical derivative\n", " H(9)C(6)N(1)O(2)S(1)\n", @@ -366,10 +267,11 @@ " 159.035400\n", " 0.000000\n", " 0.000000\n", + " True\n", " \n", " \n", - " trifluoro@L\n", - " trifluoro@L\n", + " trifluoro@l\n", + " trifluoro@l\n", " 53.971400\n", " Non-standard residue\n", " H(-3)F(3)\n", @@ -382,10 +284,11 @@ " 53.971734\n", " 0.000000\n", " 0.000000\n", + " True\n", " \n", " \n", "\n", - "

2685 rows × 13 columns

\n", + "

9939 rows × 14 columns

\n", "" ], "text/plain": [ @@ -397,11 +300,11 @@ "15N-oxobutanoic@T^Protein N-term 15N-oxobutanoic@T^Protein N-term \n", "2-dimethylsuccinyl@C 2-dimethylsuccinyl@C \n", "... ... \n", - "spermidine@Q spermidine@Q \n", - "spermine@Q spermine@Q \n", - "sulfo+amino@Y sulfo+amino@Y \n", - "thioacylPA@K thioacylPA@K \n", - "trifluoro@L trifluoro@L \n", + "spermidine@q spermidine@q \n", + "spermine@q spermine@q \n", + "sulfo+amino@y sulfo+amino@y \n", + "thioacylPA@k thioacylPA@k \n", + "trifluoro@l trifluoro@l \n", "\n", " avge_mass classification \\\n", "mod_name \n", @@ -411,11 +314,11 @@ "15N-oxobutanoic@T^Protein N-term -18.023900 Post-translational \n", "2-dimethylsuccinyl@C 144.125300 Chemical derivative \n", "... ... ... \n", - "spermidine@Q 128.215300 Chemical derivative \n", - "spermine@Q 185.309700 Chemical derivative \n", - "sulfo+amino@Y 95.077800 Chemical derivative \n", - "thioacylPA@K 159.206200 Chemical derivative \n", - "trifluoro@L 53.971400 Non-standard residue \n", + "spermidine@q 128.215300 Chemical derivative \n", + "spermine@q 185.309700 Chemical derivative \n", + "sulfo+amino@y 95.077800 Chemical derivative \n", + "thioacylPA@k 159.206200 Chemical derivative \n", + "trifluoro@l 53.971400 Non-standard residue \n", "\n", " composition modloss_composition \\\n", "mod_name \n", @@ -425,11 +328,11 @@ "15N-oxobutanoic@T^Protein N-term H(-3)15N(-1) \n", "2-dimethylsuccinyl@C H(8)C(6)O(4) \n", "... ... ... \n", - "spermidine@Q H(16)C(7)N(2) \n", - "spermine@Q H(23)C(10)N(3) \n", - "sulfo+amino@Y H(1)N(1)O(3)S(1) \n", - "thioacylPA@K H(9)C(6)N(1)O(2)S(1) \n", - "trifluoro@L H(-3)F(3) \n", + "spermidine@q H(16)C(7)N(2) \n", + "spermine@q H(23)C(10)N(3) \n", + "sulfo+amino@y H(1)N(1)O(3)S(1) \n", + "thioacylPA@k H(9)C(6)N(1)O(2)S(1) \n", + "trifluoro@l H(-3)F(3) \n", "\n", " mono_mass unimod_id unimod_mass \\\n", "mod_name \n", @@ -439,11 +342,11 @@ "15N-oxobutanoic@T^Protein N-term -18.023584 1419 -18.023584 \n", "2-dimethylsuccinyl@C 144.042259 1262 144.042259 \n", "... ... ... ... \n", - "spermidine@Q 128.131349 1421 128.131349 \n", - "spermine@Q 185.189198 1420 185.189198 \n", - "sulfo+amino@Y 94.967714 997 94.967714 \n", - "thioacylPA@K 159.035399 967 159.035399 \n", - "trifluoro@L 53.971735 750 53.971735 \n", + "spermidine@q 128.131349 1421 128.131349 \n", + "spermine@q 185.189198 1420 185.189198 \n", + "sulfo+amino@y 94.967714 997 94.967714 \n", + "thioacylPA@k 159.035399 967 159.035399 \n", + "trifluoro@l 53.971735 750 53.971735 \n", "\n", " unimod_modloss modloss_importance \\\n", "mod_name \n", @@ -453,27 +356,41 @@ "15N-oxobutanoic@T^Protein N-term 0.000000 0.0 \n", "2-dimethylsuccinyl@C 0.000000 0.0 \n", "... ... ... \n", - "spermidine@Q 0.000000 0.0 \n", - "spermine@Q 0.000000 0.0 \n", - "sulfo+amino@Y 0.000000 0.0 \n", - "thioacylPA@K 0.000000 0.0 \n", - "trifluoro@L 0.000000 0.0 \n", + "spermidine@q 0.000000 0.0 \n", + "spermine@q 0.000000 0.0 \n", + "sulfo+amino@y 0.000000 0.0 \n", + "thioacylPA@k 0.000000 0.0 \n", + "trifluoro@l 0.000000 0.0 \n", "\n", - " mass modloss_original modloss \n", - "mod_name \n", - "GlyGly@K 114.042927 114.042927 114.042927 \n", - "15N-oxobutanoic@C^Any N-term -18.023584 0.000000 0.000000 \n", - "15N-oxobutanoic@S^Protein N-term -18.023584 0.000000 0.000000 \n", - "15N-oxobutanoic@T^Protein N-term -18.023584 0.000000 0.000000 \n", - "2-dimethylsuccinyl@C 144.042259 0.000000 0.000000 \n", - "... ... ... ... \n", - "spermidine@Q 128.131349 0.000000 0.000000 \n", - "spermine@Q 185.189198 0.000000 0.000000 \n", - "sulfo+amino@Y 94.967714 0.000000 0.000000 \n", - "thioacylPA@K 159.035400 0.000000 0.000000 \n", - "trifluoro@L 53.971734 0.000000 0.000000 \n", + " mass modloss_original modloss \\\n", + "mod_name \n", + "GlyGly@K 114.042927 114.042927 114.042927 \n", + "15N-oxobutanoic@C^Any N-term -18.023584 0.000000 0.000000 \n", + "15N-oxobutanoic@S^Protein N-term -18.023584 0.000000 0.000000 \n", + "15N-oxobutanoic@T^Protein N-term -18.023584 0.000000 0.000000 \n", + "2-dimethylsuccinyl@C 144.042259 0.000000 0.000000 \n", + "... ... ... ... \n", + "spermidine@q 128.131349 0.000000 0.000000 \n", + "spermine@q 185.189198 0.000000 0.000000 \n", + "sulfo+amino@y 94.967714 0.000000 0.000000 \n", + "thioacylPA@k 159.035400 0.000000 0.000000 \n", + "trifluoro@l 53.971734 0.000000 0.000000 \n", + "\n", + " lower_case_AA \n", + "mod_name \n", + "GlyGly@K False \n", + "15N-oxobutanoic@C^Any N-term False \n", + "15N-oxobutanoic@S^Protein N-term False \n", + "15N-oxobutanoic@T^Protein N-term False \n", + "2-dimethylsuccinyl@C False \n", + "... ... \n", + "spermidine@q True \n", + "spermine@q True \n", + "sulfo+amino@y True \n", + "thioacylPA@k True \n", + "trifluoro@l True \n", "\n", - "[2685 rows x 13 columns]" + "[9939 rows x 14 columns]" ] }, "execution_count": null, @@ -482,7 +399,7 @@ } ], "source": [ - "MOD_DF" + "modification.MOD_DF" ] }, { @@ -501,7 +418,10 @@ "name": "stdout", "output_type": "stream", "text": [ - "Delta:Hg(1)@C: unimod mod=201.970617, formula mass=201.9706434\n" + "Delta:Hg(1)@C: unimod mod=201.970617, formula mass=201.9706434\n", + "Delta:Hg(1)@c: unimod mod=201.970617, formula mass=201.9706434\n", + "Delta:Hg(1)@c: unimod mod=201.970617, formula mass=201.9706434\n", + "Delta:Hg(1)@c: unimod mod=201.970617, formula mass=201.9706434\n" ] } ], @@ -531,119 +451,6 @@ "`calc_modification_mass` and `calc_modification_mass_sum` are base functions to calculate masses. But for large sets of peptides, we recommend to use `calc_mod_masses_for_same_len_seqs` instead of `calc_modification_mass`." ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def calc_modification_mass(\n", - " nAA:int, \n", - " mod_names:List[str], \n", - " mod_sites:List[int]\n", - ")->np.ndarray:\n", - " '''\n", - " Calculate modification masses for the given peptide length (`nAA`), \n", - " and modified site list.\n", - " \n", - " Parameters\n", - " ----------\n", - " nAA : int\n", - " Peptide length\n", - "\n", - " mod_names : list\n", - " List[str]. Modification name list\n", - "\n", - " mod_sites : list\n", - " List[int]. Modification site list corresponding to `mod_names`.\n", - " * `site=0` refers to an N-term modification\n", - " * `site=-1` refers to a C-term modification\n", - " * `1<=site<=peplen` refers to a normal modification\n", - " \n", - " Returns\n", - " -------\n", - " np.ndarray\n", - " 1-D array with length=`nAA`. \n", - " Masses of modifications through the peptide, \n", - " `0` if sites has no modifications\n", - " '''\n", - " masses = np.zeros(nAA)\n", - " for site, mod in zip(mod_sites, mod_names):\n", - " if site == 0:\n", - " masses[site] += MOD_MASS[mod]\n", - " elif site == -1:\n", - " masses[site] += MOD_MASS[mod]\n", - " else:\n", - " masses[site-1] += MOD_MASS[mod]\n", - " return masses\n", - "\n", - "def calc_mod_masses_for_same_len_seqs(\n", - " nAA:int, \n", - " mod_names_list:List[List[str]], \n", - " mod_sites_list:List[List[int]]\n", - ")->np.ndarray:\n", - " '''\n", - " Calculate modification masses for the given peptides with same peptide length (`nAA`).\n", - " \n", - " Parameters\n", - " ----------\n", - " nAA : int\n", - " \n", - " Peptide length\n", - "\n", - " mod_names_list : List[List[str]]\n", - " List (pep_count) of modification list (n_mod on each peptide)\n", - "\n", - " mod_sites_list : List[List[int]]\n", - " List of modification site list corresponding to `mod_names_list`.\n", - " * `site=0` refers to an N-term modification\n", - " * `site=-1` refers to a C-term modification\n", - " * `1<=site<=peplen` refers to a normal modification\n", - " \n", - " Returns\n", - " -------\n", - " np.ndarray\n", - " 2-D array with shape=`(nAA, pep_count or len(mod_names_list)))`. \n", - " Masses of modifications through all the peptides, \n", - " `0` if sites without modifications.\n", - " '''\n", - " masses = np.zeros((len(mod_names_list),nAA))\n", - " for i, (mod_names, mod_sites) in enumerate(\n", - " zip(mod_names_list, mod_sites_list)\n", - " ):\n", - " for mod, site in zip(mod_names, mod_sites): \n", - " if site == 0:\n", - " masses[i,site] += MOD_MASS[mod]\n", - " elif site == -1:\n", - " masses[i,site] += MOD_MASS[mod]\n", - " else:\n", - " masses[i,site-1] += MOD_MASS[mod]\n", - " return masses\n", - "\n", - "def calc_modification_mass_sum(\n", - " mod_names:List[str]\n", - ")->float:\n", - " \"\"\"\n", - " Calculate summed mass of the given modification \n", - " without knowing the sites and peptide length.\n", - " It is useful to calculate peptide mass.\n", - " \n", - " Parameters\n", - " ----------\n", - " mod_names : List[str]\n", - " Modification name list\n", - "\n", - " Returns\n", - " -------\n", - " float\n", - " Total mass\n", - " \"\"\"\n", - " return np.sum([\n", - " MOD_MASS[mod] for mod in mod_names\n", - " ])\n" - ] - }, { "cell_type": "code", "execution_count": null, @@ -661,169 +468,6 @@ ")" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "@numba.jit(nopython=True, nogil=True)\n", - "def _calc_modloss_with_importance(\n", - " mod_losses: np.ndarray, \n", - " _loss_importance: np.ndarray\n", - ")->np.ndarray:\n", - " '''\n", - " Calculate modification loss masses (e.g. -98 Da for Phospho@S/T). \n", - " Modification with higher `_loss_importance` has higher priorities. \n", - " For example, `AM(Oxidation@M)S(Phospho@S)...`,\n", - " importance of Phospho@S > importance of Oxidation@M, so the modloss of \n", - " b3 ion will be -98 Da, not -64 Da.\n", - " \n", - " Parameters\n", - " ----------\n", - " mod_losses : np.ndarray\n", - " Mod loss masses of each AA position\n", - "\n", - " _loss_importance : np.ndarray\n", - " Mod loss importance of each AA position\n", - " \n", - " Returns\n", - " -------\n", - " np.ndarray\n", - " New mod_loss masses selected by `_loss_importance`\n", - " '''\n", - " prev_importance = _loss_importance[0]\n", - " prev_most = 0\n", - " for i, _curr_imp in enumerate(_loss_importance[1:],1):\n", - " if _curr_imp > prev_importance:\n", - " prev_most = i\n", - " prev_importance = _curr_imp\n", - " else:\n", - " mod_losses[i] = mod_losses[prev_most]\n", - " return mod_losses\n", - "\n", - "def calc_modloss_mass_with_importance(\n", - " nAA: int, \n", - " mod_names: List, \n", - " mod_sites: List,\n", - " for_nterm_frag: bool,\n", - ")->np.ndarray:\n", - " '''\n", - " Calculate modification loss masses (e.g. -98 Da for Phospho@S/T, \n", - " -64 Da for Oxidation@M). Modifications with higher `MOD_LOSS_IMPORTANCE` \n", - " have higher priorities. For example, `AS(Phospho@S)M(Oxidation@M)...`,\n", - " importance of Phospho@S > importance of Oxidation@M, so the modloss of \n", - " b3 ion will be -98 Da, not -64 Da.\n", - " \n", - " Parameters\n", - " ----------\n", - " nAA : int\n", - " Peptide length\n", - "\n", - " mod_names : List[str]\n", - " Modification name list\n", - "\n", - " mod_sites : List[int]\n", - " Modification site list \n", - "\n", - " for_nterm_frag : bool\n", - " If `True`, the loss will be on the \n", - " N-term fragments (mainly `b` ions); \n", - " If `False`, the loss will be on the \n", - " C-term fragments (mainly `y` ions)\n", - " \n", - " Returns\n", - " -------\n", - " np.ndarray\n", - " mod_loss masses\n", - " '''\n", - " if not mod_names: return np.zeros(nAA-1)\n", - " mod_losses = np.zeros(nAA+2)\n", - " mod_losses[mod_sites] = [MOD_LOSS_MASS[mod] for mod in mod_names]\n", - " _loss_importance = np.zeros(nAA+2)\n", - " _loss_importance[mod_sites] = [\n", - " MOD_LOSS_IMPORTANCE[mod] if mod in MOD_LOSS_IMPORTANCE else 0 \n", - " for mod in mod_names\n", - " ]\n", - " \n", - " # Will not consider the modloss if the corresponding modloss_importance is 0\n", - " mod_losses[_loss_importance==0] = 0\n", - "\n", - " if for_nterm_frag:\n", - " return _calc_modloss_with_importance(mod_losses, _loss_importance)[1:-2]\n", - " else:\n", - " return _calc_modloss_with_importance(mod_losses[::-1], _loss_importance[::-1])[-3:0:-1]\n", - "\n", - "@numba.njit\n", - "def _calc_modloss(\n", - " mod_losses: np.ndarray\n", - ")->np.ndarray:\n", - " '''\n", - " Calculate modification loss masses (e.g. -98 Da for Phospho@S/T). \n", - " \n", - " Parameters\n", - " ----------\n", - " mod_losses : np.ndarray\n", - " Mod loss masses of each AA position\n", - " \n", - " Returns\n", - " -------\n", - " np.ndarray\n", - " New mod_loss masses \n", - " '''\n", - " for i, _curr_loss in enumerate(mod_losses[1:],1):\n", - " if _curr_loss == 0:\n", - " mod_losses[i] = mod_losses[i-1]\n", - " else:\n", - " mod_losses[i] = _curr_loss\n", - " return mod_losses\n", - " \n", - "def calc_modloss_mass(\n", - " nAA: int, \n", - " mod_names: List, \n", - " mod_sites: List,\n", - " for_nterm_frag: bool,\n", - ")->np.ndarray:\n", - " '''\n", - " Calculate modification loss masses (e.g. -98 Da for Phospho@S/T, \n", - " -64 Da for Oxidation@M). The mod loss mass is calculated by the\n", - " modification closer to the fragment sites. For example, \n", - " the modloss of the b3 ion for `AS(Phospho@S)M(Oxidation@M)...`\n", - " will be -64 Da.\n", - " \n", - " Parameters\n", - " ----------\n", - " nAA : int\n", - " Peptide length\n", - "\n", - " mod_names : List[str]\n", - " Modification name list\n", - "\n", - " mod_sites : List[int]\n", - " Modification site list corresponding \n", - "\n", - " for_nterm_frag : bool\n", - " If `True`, the loss will be on the \n", - " N-term fragments (mainly `b` ions); \n", - " If `False`, the loss will be on the \n", - " C-term fragments (mainly `y` ions)\n", - " \n", - " Returns\n", - " -------\n", - " np.ndarray\n", - " mod_loss masses\n", - " '''\n", - " if len(mod_names) == 0: return np.zeros(nAA-1)\n", - " mod_losses = np.zeros(nAA+2)\n", - " mod_losses[mod_sites] = [MOD_LOSS_MASS[mod] for mod in mod_names]\n", - "\n", - " if for_nterm_frag:\n", - " return _calc_modloss(mod_losses)[1:-2]\n", - " else:\n", - " return _calc_modloss(mod_losses[::-1])[-3:0:-1]" - ] - }, { "cell_type": "code", "execution_count": null, @@ -904,6 +548,7 @@ " mass\n", " modloss_original\n", " modloss\n", + " lower_case_AA\n", " \n", " \n", " mod_name\n", @@ -920,6 +565,7 @@ " \n", " \n", " \n", + " \n", " \n", " \n", " \n", @@ -938,6 +584,7 @@ " 114.042927\n", " 114.042927\n", " 114.042927\n", + " False\n", " \n", " \n", " 15N-oxobutanoic@C^Any N-term\n", @@ -954,6 +601,7 @@ " -18.023584\n", " 0.000000\n", " 0.000000\n", + " False\n", " \n", " \n", " 2-dimethylsuccinyl@C\n", @@ -970,6 +618,7 @@ " 144.042259\n", " 0.000000\n", " 0.000000\n", + " False\n", " \n", " \n", " 3-deoxyglucosone@R\n", @@ -986,6 +635,7 @@ " 144.042259\n", " 0.000000\n", " 0.000000\n", + " False\n", " \n", " \n", " ADP-Ribosyl@C\n", @@ -1002,6 +652,7 @@ " 541.061110\n", " 0.000000\n", " 0.000000\n", + " False\n", " \n", " \n", " ADP-Ribosyl@N\n", @@ -1018,6 +669,7 @@ " 541.061110\n", " 541.061110\n", " 0.000000\n", + " False\n", " \n", " \n", " ADP-Ribosyl@S\n", @@ -1034,6 +686,7 @@ " 541.061110\n", " 541.061110\n", " 0.000000\n", + " False\n", " \n", " \n", " AEC-MAEC:2H(4)@S\n", @@ -1050,6 +703,7 @@ " 63.044463\n", " 0.000000\n", " 0.000000\n", + " False\n", " \n", " \n", " Ahx2+Hsl@Any C-term\n", @@ -1066,6 +720,7 @@ " 309.205242\n", " 0.000000\n", " 0.000000\n", + " False\n", " \n", " \n", " Ala->Arg@A\n", @@ -1082,6 +737,7 @@ " 85.063997\n", " 0.000000\n", " 0.000000\n", + " False\n", " \n", " \n", " Arg-loss@R^Any C-term\n", @@ -1098,6 +754,7 @@ " -156.101111\n", " 0.000000\n", " 0.000000\n", + " False\n", " \n", " \n", " FormylMet@Protein N-term\n", @@ -1114,6 +771,7 @@ " 159.035400\n", " 0.000000\n", " 0.000000\n", + " False\n", " \n", " \n", " HexN@K\n", @@ -1130,6 +788,7 @@ " 161.068808\n", " 0.000000\n", " 0.000000\n", + " False\n", " \n", " \n", " Met-loss+Acetyl@M^Protein N-term\n", @@ -1146,6 +805,7 @@ " -89.029920\n", " 0.000000\n", " 0.000000\n", + " False\n", " \n", " \n", "\n", @@ -1254,22 +914,22 @@ "HexN@K 0.0 161.068808 \n", "Met-loss+Acetyl@M^Protein N-term 0.0 -89.029920 \n", "\n", - " modloss_original modloss \n", - "mod_name \n", - "GlyGly@K 114.042927 114.042927 \n", - "15N-oxobutanoic@C^Any N-term 0.000000 0.000000 \n", - "2-dimethylsuccinyl@C 0.000000 0.000000 \n", - "3-deoxyglucosone@R 0.000000 0.000000 \n", - "ADP-Ribosyl@C 0.000000 0.000000 \n", - "ADP-Ribosyl@N 541.061110 0.000000 \n", - "ADP-Ribosyl@S 541.061110 0.000000 \n", - "AEC-MAEC:2H(4)@S 0.000000 0.000000 \n", - "Ahx2+Hsl@Any C-term 0.000000 0.000000 \n", - "Ala->Arg@A 0.000000 0.000000 \n", - "Arg-loss@R^Any C-term 0.000000 0.000000 \n", - "FormylMet@Protein N-term 0.000000 0.000000 \n", - "HexN@K 0.000000 0.000000 \n", - "Met-loss+Acetyl@M^Protein N-term 0.000000 0.000000 " + " modloss_original modloss lower_case_AA \n", + "mod_name \n", + "GlyGly@K 114.042927 114.042927 False \n", + "15N-oxobutanoic@C^Any N-term 0.000000 0.000000 False \n", + "2-dimethylsuccinyl@C 0.000000 0.000000 False \n", + "3-deoxyglucosone@R 0.000000 0.000000 False \n", + "ADP-Ribosyl@C 0.000000 0.000000 False \n", + "ADP-Ribosyl@N 541.061110 0.000000 False \n", + "ADP-Ribosyl@S 541.061110 0.000000 False \n", + "AEC-MAEC:2H(4)@S 0.000000 0.000000 False \n", + "Ahx2+Hsl@Any C-term 0.000000 0.000000 False \n", + "Ala->Arg@A 0.000000 0.000000 False \n", + "Arg-loss@R^Any C-term 0.000000 0.000000 False \n", + "FormylMet@Protein N-term 0.000000 0.000000 False \n", + "HexN@K 0.000000 0.000000 False \n", + "Met-loss+Acetyl@M^Protein N-term 0.000000 0.000000 False " ] }, "execution_count": null, @@ -1288,6 +948,370 @@ "## We can update modification list for differet requirements, for example:" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
mod_nameavge_massclassificationcompositionmodloss_compositionmono_massunimod_idunimod_massunimod_modlossmodloss_importancemassmodloss_originalmodlosslower_case_AA
mod_name
GlyGly@KGlyGly@K114.042927Post-translationalH(6)C(4)N(2)O(2)H(6)C(4)N(2)O(2)114.042927121114.042927114.0429271000000.0114.042927114.042927114.042927False
15N-oxobutanoic@C^Any N-term15N-oxobutanoic@C^Any N-term-18.023900ArtefactH(-3)15N(-1)-18.0235841419-18.0235840.0000000.0-18.0235840.0000000.000000False
15N-oxobutanoic@S^Protein N-term15N-oxobutanoic@S^Protein N-term-18.023900Post-translationalH(-3)15N(-1)-18.0235841419-18.0235840.0000000.0-18.0235840.0000000.000000False
15N-oxobutanoic@T^Protein N-term15N-oxobutanoic@T^Protein N-term-18.023900Post-translationalH(-3)15N(-1)-18.0235841419-18.0235840.0000000.0-18.0235840.0000000.000000False
2-dimethylsuccinyl@C2-dimethylsuccinyl@C144.125300Chemical derivativeH(8)C(6)O(4)144.0422591262144.0422590.0000000.0144.0422590.0000000.000000False
.............................................
spermidine@qspermidine@q128.215300Chemical derivativeH(16)C(7)N(2)128.1313491421128.1313490.0000000.0128.1313490.0000000.000000True
spermine@qspermine@q185.309700Chemical derivativeH(23)C(10)N(3)185.1891981420185.1891980.0000000.0185.1891980.0000000.000000True
sulfo+amino@ysulfo+amino@y95.077800Chemical derivativeH(1)N(1)O(3)S(1)94.96771499794.9677140.0000000.094.9677140.0000000.000000True
thioacylPA@kthioacylPA@k159.206200Chemical derivativeH(9)C(6)N(1)O(2)S(1)159.035399967159.0353990.0000000.0159.0354000.0000000.000000True
trifluoro@ltrifluoro@l53.971400Non-standard residueH(-3)F(3)53.97173575053.9717350.0000000.053.9717340.0000000.000000True
\n", + "

5103 rows × 14 columns

\n", + "
" + ], + "text/plain": [ + " mod_name \\\n", + "mod_name \n", + "GlyGly@K GlyGly@K \n", + "15N-oxobutanoic@C^Any N-term 15N-oxobutanoic@C^Any N-term \n", + "15N-oxobutanoic@S^Protein N-term 15N-oxobutanoic@S^Protein N-term \n", + "15N-oxobutanoic@T^Protein N-term 15N-oxobutanoic@T^Protein N-term \n", + "2-dimethylsuccinyl@C 2-dimethylsuccinyl@C \n", + "... ... \n", + "spermidine@q spermidine@q \n", + "spermine@q spermine@q \n", + "sulfo+amino@y sulfo+amino@y \n", + "thioacylPA@k thioacylPA@k \n", + "trifluoro@l trifluoro@l \n", + "\n", + " avge_mass classification \\\n", + "mod_name \n", + "GlyGly@K 114.042927 Post-translational \n", + "15N-oxobutanoic@C^Any N-term -18.023900 Artefact \n", + "15N-oxobutanoic@S^Protein N-term -18.023900 Post-translational \n", + "15N-oxobutanoic@T^Protein N-term -18.023900 Post-translational \n", + "2-dimethylsuccinyl@C 144.125300 Chemical derivative \n", + "... ... ... \n", + "spermidine@q 128.215300 Chemical derivative \n", + "spermine@q 185.309700 Chemical derivative \n", + "sulfo+amino@y 95.077800 Chemical derivative \n", + "thioacylPA@k 159.206200 Chemical derivative \n", + "trifluoro@l 53.971400 Non-standard residue \n", + "\n", + " composition modloss_composition \\\n", + "mod_name \n", + "GlyGly@K H(6)C(4)N(2)O(2) H(6)C(4)N(2)O(2) \n", + "15N-oxobutanoic@C^Any N-term H(-3)15N(-1) \n", + "15N-oxobutanoic@S^Protein N-term H(-3)15N(-1) \n", + "15N-oxobutanoic@T^Protein N-term H(-3)15N(-1) \n", + "2-dimethylsuccinyl@C H(8)C(6)O(4) \n", + "... ... ... \n", + "spermidine@q H(16)C(7)N(2) \n", + "spermine@q H(23)C(10)N(3) \n", + "sulfo+amino@y H(1)N(1)O(3)S(1) \n", + "thioacylPA@k H(9)C(6)N(1)O(2)S(1) \n", + "trifluoro@l H(-3)F(3) \n", + "\n", + " mono_mass unimod_id unimod_mass \\\n", + "mod_name \n", + "GlyGly@K 114.042927 121 114.042927 \n", + "15N-oxobutanoic@C^Any N-term -18.023584 1419 -18.023584 \n", + "15N-oxobutanoic@S^Protein N-term -18.023584 1419 -18.023584 \n", + "15N-oxobutanoic@T^Protein N-term -18.023584 1419 -18.023584 \n", + "2-dimethylsuccinyl@C 144.042259 1262 144.042259 \n", + "... ... ... ... \n", + "spermidine@q 128.131349 1421 128.131349 \n", + "spermine@q 185.189198 1420 185.189198 \n", + "sulfo+amino@y 94.967714 997 94.967714 \n", + "thioacylPA@k 159.035399 967 159.035399 \n", + "trifluoro@l 53.971735 750 53.971735 \n", + "\n", + " unimod_modloss modloss_importance \\\n", + "mod_name \n", + "GlyGly@K 114.042927 1000000.0 \n", + "15N-oxobutanoic@C^Any N-term 0.000000 0.0 \n", + "15N-oxobutanoic@S^Protein N-term 0.000000 0.0 \n", + "15N-oxobutanoic@T^Protein N-term 0.000000 0.0 \n", + "2-dimethylsuccinyl@C 0.000000 0.0 \n", + "... ... ... \n", + "spermidine@q 0.000000 0.0 \n", + "spermine@q 0.000000 0.0 \n", + "sulfo+amino@y 0.000000 0.0 \n", + "thioacylPA@k 0.000000 0.0 \n", + "trifluoro@l 0.000000 0.0 \n", + "\n", + " mass modloss_original modloss \\\n", + "mod_name \n", + "GlyGly@K 114.042927 114.042927 114.042927 \n", + "15N-oxobutanoic@C^Any N-term -18.023584 0.000000 0.000000 \n", + "15N-oxobutanoic@S^Protein N-term -18.023584 0.000000 0.000000 \n", + "15N-oxobutanoic@T^Protein N-term -18.023584 0.000000 0.000000 \n", + "2-dimethylsuccinyl@C 144.042259 0.000000 0.000000 \n", + "... ... ... ... \n", + "spermidine@q 128.131349 0.000000 0.000000 \n", + "spermine@q 185.189198 0.000000 0.000000 \n", + "sulfo+amino@y 94.967714 0.000000 0.000000 \n", + "thioacylPA@k 159.035400 0.000000 0.000000 \n", + "trifluoro@l 53.971734 0.000000 0.000000 \n", + "\n", + " lower_case_AA \n", + "mod_name \n", + "GlyGly@K False \n", + "15N-oxobutanoic@C^Any N-term False \n", + "15N-oxobutanoic@S^Protein N-term False \n", + "15N-oxobutanoic@T^Protein N-term False \n", + "2-dimethylsuccinyl@C False \n", + "... ... \n", + "spermidine@q True \n", + "spermine@q True \n", + "sulfo+amino@y True \n", + "thioacylPA@k True \n", + "trifluoro@l True \n", + "\n", + "[5103 rows x 14 columns]" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "add_modifications_for_lower_case_AA()\n", + "modification.MOD_DF" + ] + }, { "cell_type": "code", "execution_count": null, @@ -1624,10 +1648,10 @@ } ], "source": [ - "add_modifications_for_lower_case_AA()\n", - "MOD_DF = MOD_DF[\n", - " (MOD_DF['classification'].isin(['Post-translational','O-linked glycosylation','AA substitution','Multiple','Non-standard residue','Pre-translational']))\n", - " & MOD_DF['lower_case_AA']\n", + "\n", + "modification.MOD_DF = modification.MOD_DF[\n", + " (modification.MOD_DF['classification'].isin(['Post-translational','O-linked glycosylation','AA substitution','Multiple','Non-standard residue','Pre-translational']))\n", + " & modification.MOD_DF['lower_case_AA']\n", "] # we only need PTMs\n", "update_all_by_MOD_DF()\n", "# MOD_INFO_DICT is also updated\n", @@ -1643,56 +1667,13 @@ "#| hide\n", "load_mod_df()\n", "add_modifications_for_lower_case_AA()\n", + "MOD_DF = modification.MOD_DF\n", "MOD_DF = MOD_DF[\n", " MOD_DF['lower_case_AA']\n", "] # we only need PTMs\n", "assert MOD_DF['mod_name'].apply(lambda x: x[x.find('@')+1].islower()).all()" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def add_new_modifications(new_mods:list):\n", - " \"\"\"Add new modifications into MOD_DF\n", - "\n", - " Parameters\n", - " ----------\n", - " new_mods : list \n", - " \n", - " list of tuples. Tuple example:\n", - " (\n", - " modname@site:str (e.g. Mod@S), \n", - " chemical compositions:str (e.g. \"H(4)O(2)\"),\n", - " [optional] modloss compositions:str (e.g. \"H(2)O(1)\"),\n", - " )\n", - " \"\"\"\n", - " for items in new_mods:\n", - " if len(items) == 2:\n", - " mod, comp = items\n", - " modloss_comp = ''\n", - " else:\n", - " mod, comp, modloss_comp = items\n", - " MOD_DF.loc[mod,[\n", - " 'mod_name','composition','modloss_composition',\n", - " 'classification','unimod_id'\n", - " ]] = [\n", - " mod, comp, modloss_comp,\n", - " 'User-added', 0\n", - " ]\n", - " MOD_DF.loc[mod,['mass','modloss']] = (\n", - " calc_mass_from_formula(comp),\n", - " calc_mass_from_formula(modloss_comp)\n", - " )\n", - " if MOD_DF.loc[mod, 'modloss'] > 0:\n", - " MOD_DF.loc[mod, 'modloss_importance'] = 1e6\n", - " MOD_DF.fillna(0, inplace=True)\n", - " update_all_by_MOD_DF()" - ] - }, { "cell_type": "code", "execution_count": null, @@ -1704,11 +1685,11 @@ " (\"Hello@S\",\"H(2)\"),\n", " (\"World@S\",\"O(10)\",\"O(3)\")\n", "])\n", - "assert (MOD_DF.classification=='User-added').sum()==2\n", - "assert 'Hello@S' in MOD_DF.mod_name\n", - "assert 'World@S' in MOD_DF.mod_name\n", - "assert MOD_DF.loc['World@S','modloss'] > 0\n", - "assert MOD_DF.loc['World@S','modloss_importance'] > 0\n", + "assert (modification.MOD_DF.classification=='User-added').sum()==2\n", + "assert 'Hello@S' in modification.MOD_DF.mod_name\n", + "assert 'World@S' in modification.MOD_DF.mod_name\n", + "assert modification.MOD_DF.loc['World@S','modloss'] > 0\n", + "assert modification.MOD_DF.loc['World@S','modloss_importance'] > 0\n", "assert 'Hello@S' in MOD_formula\n", "assert 'World@S' in MOD_MASS" ] diff --git a/nbdev_nbs/index.ipynb b/nbdev_nbs/index.ipynb deleted file mode 100644 index 7de59db1..00000000 --- a/nbdev_nbs/index.ipynb +++ /dev/null @@ -1,219 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# AlphaBase" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "AlphaBase provides all basic python functionalities for AlphaPept ecosystem from the [Mann Labs at the Max Planck Institute of Biochemistry](https://www.biochem.mpg.de/mann) and the [University of Copenhagen](https://www.cpr.ku.dk/research/proteomics/mann/). To enable all hyperlinks in this document, please view it at [GitHub](https://github.com/MannLabs/alphabase). For documentation, please see [GitHub Pages](https://mannlabs.github.io/alphabase/)\n", - "\n", - "* [**About**](#about)\n", - "* [**License**](#license)\n", - "* [**Installation**](#installation)\n", - " * [**Pip installer**](#pip)\n", - " * [**Developer installer**](#developer)\n", - "* [**Usage**](#usage)\n", - "* [**Troubleshooting**](#troubleshooting)\n", - "* [**Citations**](#citations)\n", - "* [**How to contribute**](#how-to-contribute)\n", - "* [**Changelog**](#changelog)\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## About\n", - "\n", - "An open-source Python package of the AlphaPept ecosystem from the [Mann Labs at the Max Planck Institute of Biochemistry](https://www.biochem.mpg.de/mann) and the [University of Copenhagen](https://www.cpr.ku.dk/research/proteomics/mann/). It provides basic functionalities for AlphaPept ecosystem.\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## License\n", - "\n", - "AlphaBase was developed by the [Mann Labs at the Max Planck Institute of Biochemistry](https://www.biochem.mpg.de/mann) and the [University of Copenhagen](https://www.cpr.ku.dk/research/proteomics/mann/) and is freely available with an [Apache License](LICENSE.txt). External Python packages (available in the [requirements](requirements) folder) have their own licenses, which can be consulted on their respective websites.\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Installation\n", - "\n", - "AlphaBase can be installed and used on all major operating systems (Windows, macOS and Linux).\n", - "There are two different types of installation possible:\n", - "\n", - "* [**Pip installer:**](#pip) Choose this installation if you want to use AlphaBase as a Python package in an existing Python 3.8 environment (e.g. a Jupyter notebook). \n", - "* [**Developer installer:**](#developer) Choose this installation if you are familiar with [conda](https://docs.conda.io/en/latest/) and Python. This installation allows access to all available features of AlphaBase and even allows to modify its source code directly. Generally, the developer version of AlphaBase outperforms the precompiled versions which makes this the installation of choice for high-throughput experiments.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Pip\n", - "\n", - "AlphaBase can be installed in an existing Python 3.8 environment with a single `bash` command. *This `bash` command can also be run directly from within a Jupyter notebook by prepending it with a `!`*:\n", - "\n", - "```bash\n", - "pip install alphabase\n", - "```\n", - "\n", - "Installing AlphaBase like this avoids conflicts when integrating it in other tools, as this does not enforce strict versioning of dependancies. However, if new versions of dependancies are released, they are not guaranteed to be fully compatible with AlphaBase. While this should only occur in rare cases where dependencies are not backwards compatible, you can always force AlphaBase to use dependancy versions which are known to be compatible with:\n", - "\n", - "```bash\n", - "pip install \"alphabase[stable]\"\n", - "```\n", - "\n", - "NOTE: You might need to run `pip install -U pip` before installing AlphaBase like this. Also note the double quotes `\"`.\n", - "\n", - "For those who are really adventurous, it is also possible to directly install any branch (e.g. `@development`) with any extras (e.g. `#egg=alphabase[stable,development-stable]`) from GitHub with e.g.\n", - "\n", - "```bash\n", - "pip install \"git+https://github.com/MannLabs/alphabase.git@development#egg=alphabase[stable,development-stable]\"\n", - "```\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Developer\n", - "\n", - "AlphaBase can also be installed in editable (i.e. developer) mode with a few `bash` commands. This allows to fully customize the software and even modify the source code to your specific needs. When an editable Python package is installed, its source code is stored in a transparent location of your choice. While optional, it is advised to first (create and) navigate to e.g. a general software folder:\n", - "\n", - "```bash\n", - "mkdir ~/folder/where/to/install/software\n", - "cd ~/folder/where/to/install/software\n", - "```\n", - "\n", - "***The following commands assume you do not perform any additional `cd` commands anymore***.\n", - "\n", - "Next, download the AlphaBase repository from GitHub either directly or with a `git` command. This creates a new AlphaBase subfolder in your current directory.\n", - "\n", - "```bash\n", - "git clone https://github.com/MannLabs/alphabase.git\n", - "```\n", - "\n", - "For any Python package, it is highly recommended to use a separate [conda virtual environment](https://docs.conda.io/en/latest/), as otherwise *dependancy conflicts can occur with already existing packages*.\n", - "\n", - "```bash\n", - "conda create --name alphabase python=3.8 -y\n", - "conda activate alphabase\n", - "```\n", - "\n", - "Finally, AlphaBase and all its [dependancies](requirements) need to be installed. To take advantage of all features and allow development (with the `-e` flag), this is best done by also installing the [development dependencies](requirements/requirements_development.txt) instead of only the [core dependencies](requirements/requirements.txt):\n", - "\n", - "```bash\n", - "pip install -e \"./alphabase[development]\"\n", - "```\n", - "\n", - "By default this installs loose dependancies (no explicit versioning), although it is also possible to use stable dependencies (e.g. `pip install -e \"./alphabase[stable,development-stable]\"`).\n", - "\n", - "***By using the editable flag `-e`, all modifications to the [AlphaBase source code folder](alphabase) are directly reflected when running AlphaBase. Note that the AlphaBase folder cannot be moved and/or renamed if an editable version is installed. In case of confusion, you can always retrieve the location of any Python module with e.g. the command `import module` followed by `module.__file__`.***\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Usage\n", - "\n", - "TODO\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Troubleshooting\n", - "\n", - "In case of issues, check out the following:\n", - "\n", - "* [Issues](https://github.com/MannLabs/alphabase/issues): Try a few different search terms to find out if a similar problem has been encountered before\n", - "* [Discussions](https://github.com/MannLabs/alphabase/discussions): Check if your problem or feature requests has been discussed before.\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Citations\n", - "\n", - "There are currently no plans to draft a manuscript.\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## How to contribute\n", - "\n", - "If you like this software, you can give us a [star](https://github.com/MannLabs/alphabase/stargazers) to boost our visibility! All direct contributions are also welcome. Feel free to post a new [issue](https://github.com/MannLabs/alphabase/issues) or clone the repository and create a [pull request](https://github.com/MannLabs/alphabase/pulls) with a new branch. For an even more interactive participation, check out the [discussions](https://github.com/MannLabs/alphabase/discussions) and the [the Contributors License Agreement](misc/CLA.md).\n", - "\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Changelog\n", - "\n", - "See the [HISTORY.md](HISTORY.md) for a full overview of the changes made in each version." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3.8.3 ('base')", - "language": "python", - "name": "python3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/nbdev_nbs/peptide/fragment.ipynb b/nbdev_nbs/peptide/fragment.ipynb index cdbb750a..9754c641 100644 --- a/nbdev_nbs/peptide/fragment.ipynb +++ b/nbdev_nbs/peptide/fragment.ipynb @@ -6,7 +6,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| default_exp peptide.fragment" + "#---#| default_exp peptide.fragment" ] }, { @@ -20,6 +20,15 @@ "%autoreload 2" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from alphabase.peptide.fragment import *" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -39,97 +48,6 @@ "Just in case that we have two modifications, one is on the peptide N-term, and the other is on the N-term AA site chain. Similar for C-term sites." ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "import numpy as np\n", - "import pandas as pd\n", - "from typing import List, Union, Tuple, Dict\n", - "import warnings\n", - "\n", - "from alphabase.peptide.mass_calc import *\n", - "from alphabase.constants.modification import (\n", - " calc_modloss_mass\n", - ")\n", - "from alphabase.constants.element import (\n", - " MASS_H2O, MASS_PROTON, \n", - " MASS_NH3, CHEM_MONO_MASS\n", - ")\n", - "\n", - "from alphabase.peptide.precursor import (\n", - " refine_precursor_df,\n", - " update_precursor_mz,\n", - " is_precursor_sorted\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def get_charged_frag_types(\n", - " frag_types:List[str], \n", - " max_frag_charge:int = 2\n", - ")->List[str]:\n", - " '''\n", - " Combine fragment types and charge states.\n", - "\n", - " Parameters\n", - " ----------\n", - " frag_types : List[str]\n", - " e.g. ['b','y','b_modloss','y_modloss']\n", - "\n", - " max_frag_charge : int\n", - " max fragment charge. (default: 2)\n", - " \n", - " Returns\n", - " -------\n", - " List[str]\n", - " charged fragment types\n", - " \n", - " Examples\n", - " --------\n", - " >>> frag_types=['b','y','b_modloss','y_modloss']\n", - " >>> get_charged_frag_types(frag_types, 2)\n", - " ['b_z1','b_z2','y_z1','y_z2','b_modloss_z1','b_modloss_z2','y_modloss_z1','y_modloss_z2']\n", - " '''\n", - " charged_frag_types = []\n", - " for _type in frag_types:\n", - " for _ch in range(1, max_frag_charge+1):\n", - " charged_frag_types.append(f\"{_type}_z{_ch}\")\n", - " return charged_frag_types\n", - "\n", - "def parse_charged_frag_type(\n", - " charged_frag_type: str\n", - ")->Tuple[str,int]:\n", - " '''\n", - " Oppsite to `get_charged_frag_types`.\n", - " \n", - " Parameters\n", - " ----------\n", - " charged_frag_type : str\n", - " e.g. 'y_z1', 'b_modloss_z1'\n", - "\n", - " Returns\n", - " -------\n", - " tuple\n", - " str. Fragment type, e.g. 'b','y'\n", - "\n", - " int. Charge state\n", - " '''\n", - " items = charged_frag_type.split('_')\n", - " _ch = items[-1]\n", - " _type = '_'.join(items[:-1])\n", - " return _type, int(_ch[1:])" - ] - }, { "cell_type": "code", "execution_count": null, @@ -165,151 +83,6 @@ "We provide different ways to initialize fragment dataframes, see below:" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def init_zero_fragment_dataframe(\n", - " peplen_array:np.ndarray,\n", - " charged_frag_types:List[str], \n", - " dtype=np.float64\n", - ")->Tuple[pd.DataFrame, np.ndarray, np.ndarray]: \n", - " '''Initialize a zero dataframe based on peptide length \n", - " (nAA) array (peplen_array) and charge_frag_types (column number).\n", - " The row number of returned dataframe is np.sum(peplen_array-1).\n", - "\n", - " Parameters\n", - " ----------\n", - " peplen_array : np.ndarray\n", - " peptide lengths for the fragment dataframe\n", - " \n", - " charged_frag_types : List[str]\n", - " `['b_z1','b_z2','y_z1','y_z2','b_modloss_z1','y_H2O_z1'...]`\n", - " \n", - " Returns\n", - " -------\n", - " tuple\n", - " pd.DataFrame, `fragment_df` with zero values\n", - "\n", - " np.ndarray (int64), the start indices point to the `fragment_df` for each peptide\n", - "\n", - " np.ndarray (int64), the end indices point to the `fragment_df` for each peptide\n", - " '''\n", - " indices = np.zeros(len(peplen_array)+1, dtype=np.int64)\n", - " indices[1:] = peplen_array-1\n", - " indices = np.cumsum(indices)\n", - " fragment_df = pd.DataFrame(\n", - " np.zeros((indices[-1],len(charged_frag_types)), dtype=dtype),\n", - " columns = charged_frag_types\n", - " )\n", - " return fragment_df, indices[:-1], indices[1:]\n", - "\n", - "def init_fragment_dataframe_from_other(\n", - " reference_fragment_df: pd.DataFrame,\n", - " dtype=np.float64\n", - "):\n", - " '''\n", - " Init zero fragment dataframe from the `reference_fragment_df` (same rows and same columns)\n", - " '''\n", - " return pd.DataFrame(\n", - " np.zeros_like(reference_fragment_df.values, dtype=dtype),\n", - " columns = reference_fragment_df.columns\n", - " )\n", - "\n", - "def init_fragment_by_precursor_dataframe(\n", - " precursor_df,\n", - " charged_frag_types: List[str],\n", - " *,\n", - " reference_fragment_df: pd.DataFrame = None,\n", - " dtype:np.dtype=np.float64,\n", - " inplace_in_reference:bool=False,\n", - "):\n", - " '''\n", - " Init zero fragment dataframe for the `precursor_df`. If \n", - " the `reference_fragment_df` is provided, the result dataframe's \n", - " length will be the same as reference_fragment_df. Otherwise it \n", - " generates the dataframe from scratch.\n", - " \n", - " Parameters\n", - " ----------\n", - " precursor_df : pd.DataFrame\n", - " precursors to generate fragment masses,\n", - " if `precursor_df` contains the 'frag_start_idx' column, \n", - " it is better to provide `reference_fragment_df` as \n", - " `precursor_df.frag_start_idx` and `precursor.frag_end_idx` \n", - " point to the indices in `reference_fragment_df`\n", - "\n", - " charged_frag_types : List\n", - " `['b_z1','b_z2','y_z1','y_z2','b_modloss_z1','y_H2O_z1'...]`\n", - "\n", - " reference_fragment_df : pd.DataFrame\n", - " init zero fragment_mz_df based\n", - " on this reference. If None, fragment_mz_df will be \n", - " initialized by :func:`alphabase.peptide.fragment.init_zero_fragment_dataframe`.\n", - " Defaults to None.\n", - "\n", - " inplace_in_reference : bool, optional\n", - " if calculate the fragment mz \n", - " inplace in the reference_fragment_df (default: False)\n", - "\n", - " Returns\n", - " -------\n", - " pd.DataFrame\n", - " zero `fragment_df` with given `charged_frag_types` columns\n", - " \n", - " # Raises\n", - " # ------\n", - " # ValueError\n", - " # If `reference_fragment_df` is None but there are 'frag_start_idx'\n", - " # in the `precursor_df`, meaning that there are some other fragment \n", - " # dataframes linked to the `precursor_df`, these fragment dataframes must \n", - " # be provided as `reference_fragment_df`. \n", - " # If we are sure that other fragment dataframes are not needed any more, \n", - " # we can just `del precursor_df['frag_start_idx']` before call this function.\n", - " '''\n", - " if 'frag_start_idx' not in precursor_df.columns:\n", - " (\n", - " fragment_df, start_indices, end_indices\n", - " ) = init_zero_fragment_dataframe(\n", - " precursor_df.nAA.values,\n", - " charged_frag_types,\n", - " dtype=dtype\n", - " )\n", - " precursor_df['frag_start_idx'] = start_indices\n", - " precursor_df['frag_end_idx'] = end_indices\n", - " else:\n", - " if reference_fragment_df is None:\n", - " # raise ValueError(\n", - " # \"`precursor_df` contains 'frag_start_idx' column, \"\\\n", - " # \"please provide `reference_fragment_df` argument\"\n", - " # )\n", - " fragment_df = pd.DataFrame(\n", - " np.zeros((\n", - " precursor_df.frag_end_idx.max(), \n", - " len(charged_frag_types)\n", - " )),\n", - " columns = charged_frag_types\n", - " )\n", - " else:\n", - " if inplace_in_reference: \n", - " fragment_df = reference_fragment_df[[\n", - " _fr for _fr in charged_frag_types \n", - " if _fr in reference_fragment_df.columns\n", - " ]]\n", - " else:\n", - " fragment_df = pd.DataFrame(\n", - " np.zeros((\n", - " len(reference_fragment_df), \n", - " len(charged_frag_types)\n", - " )),\n", - " columns = charged_frag_types\n", - " )\n", - " return fragment_df" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -317,91 +90,6 @@ "For a subset of the precursor dataframe, we need to set or get fragment values for the slicing (by `frag_start_idx` and `frag_end_idx`in `precursor_df`) of the fragment dataframe. We use `update_sliced_fragment_dataframe` to set the values, and `get_sliced_fragment_dataframe` to get values." ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def update_sliced_fragment_dataframe(\n", - " fragment_df: pd.DataFrame,\n", - " values: np.ndarray,\n", - " frag_start_end_list: List[Tuple[int,int]],\n", - " charged_frag_types: List[str]=None,\n", - ")->pd.DataFrame:\n", - " '''\n", - " Set the values of the slices `frag_start_end_list=[(start,end),(start,end),...]` \n", - " of fragment_df.\n", - "\n", - " Parameters\n", - " ----------\n", - " fragment_df : pd.DataFrame\n", - " fragment dataframe to set the values\n", - "\n", - " values : np.ndarray\n", - " values to set\n", - "\n", - " frag_start_end_list : List[Tuple[int,int]]\n", - " e.g. `[(start,end),(start,end),...]`\n", - "\n", - " charged_frag_types : List[str], optional\n", - " e.g. `['b_z1','b_z2','y_z1','y_z2']`.\n", - " If None, the columns of values should be the same as fragment_df's columns.\n", - " It is much faster if charged_frag_types is None as we use numpy slicing, \n", - " otherwise we use pd.loc (much slower).\n", - " Defaults to None.\n", - " \n", - " Returns\n", - " -------\n", - " pd.DataFrame\n", - " fragment_df after the values are set into slices\n", - " '''\n", - " frag_slice_list = [slice(start,end) for start,end in frag_start_end_list]\n", - " frag_slices = np.r_[tuple(frag_slice_list)]\n", - " if charged_frag_types is None or len(charged_frag_types)==0:\n", - " fragment_df.values[frag_slices, :] = values\n", - " else:\n", - " charged_frag_idxes = [fragment_df.columns.get_loc(c) for c in charged_frag_types]\n", - " fragment_df.iloc[frag_slices, charged_frag_idxes] = values\n", - " return fragment_df\n", - "\n", - "def get_sliced_fragment_dataframe(\n", - " fragment_df: pd.DataFrame,\n", - " frag_start_end_list:Union[List,np.ndarray],\n", - " charged_frag_types:List = None,\n", - ")->pd.DataFrame:\n", - " '''\n", - " Get the sliced fragment_df from `frag_start_end_list=[(start,end),(start,end),...]`.\n", - " \n", - " Parameters\n", - " ----------\n", - " fragment_df : pd.DataFrame\n", - " fragment dataframe to get values\n", - "\n", - " frag_start_end_list : Union\n", - " List[Tuple[int,int]], e.g. `[(start,end),(start,end),...]` or np.ndarray\n", - "\n", - " charged_frag_types : List[str]\n", - " e.g. `['b_z1','b_z2','y_z1','y_z2']`.\n", - " if None, all columns will be considered\n", - " \n", - " Returns\n", - " -------\n", - " pd.DataFrame\n", - " \n", - " sliced fragment_df. If `charged_frag_types` is None, \n", - " return fragment_df with all columns\n", - " '''\n", - " frag_slice_list = [slice(start,end) for start,end in frag_start_end_list]\n", - " frag_slices = np.r_[tuple(frag_slice_list)]\n", - " if charged_frag_types is None or len(charged_frag_types)==0:\n", - " charged_frag_idxes = slice(None)\n", - " else:\n", - " charged_frag_idxes = [fragment_df.columns.get_loc(c) for c in charged_frag_types]\n", - " return fragment_df.iloc[frag_slices, charged_frag_idxes]" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -409,187 +97,6 @@ "For some search engines, it reports different result files for different raw files. After load them separately, we concatenate `precursor_df_list` and `fragment_df_list` into single dataframes respectively. The main processing here is to cumulate `frag_start_idx` and `frag_end_idx` for different `precursor_df`s." ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def concat_precursor_fragment_dataframes(\n", - " precursor_df_list: List[pd.DataFrame],\n", - " fragment_df_list: List[pd.DataFrame],\n", - " *other_fragment_df_lists\n", - ")->Tuple[pd.DataFrame,...]:\n", - " '''\n", - " Since fragment_df is indexed by precursor_df, when we concatenate multiple \n", - " fragment_df, the indexed positions will change for in precursor_dfs, \n", - " this function keeps the correct indexed positions of precursor_df when \n", - " concatenating multiple fragment_df dataframes.\n", - " \n", - " Parameters\n", - " ----------\n", - " precursor_df_list : List[pd.DataFrame]\n", - " precursor dataframe list to concatenate\n", - "\n", - " fragment_df_list : List[pd.DataFrame]\n", - " fragment dataframe list to concatenate\n", - "\n", - " *other_fragment_df_lists\n", - " arbitray other fragment dataframe list to concatenate, \n", - " e.g. fragment_mass_df, fragment_inten_df, ...\n", - " \n", - " Returns\n", - " -------\n", - " Tuple[pd.DataFrame,...]\n", - " concatenated precursor_df, fragment_df, *other_fragment_df ...\n", - " '''\n", - " fragment_df_lens = [len(fragment_df) for fragment_df in fragment_df_list]\n", - " precursor_df_list = [precursor_df.copy() for precursor_df in precursor_df_list]\n", - " cum_frag_df_lens = np.cumsum(fragment_df_lens)\n", - " for i,precursor_df in enumerate(precursor_df_list[1:]):\n", - " precursor_df[['frag_start_idx','frag_end_idx']] += cum_frag_df_lens[i]\n", - " return (\n", - " pd.concat(precursor_df_list, ignore_index=True),\n", - " pd.concat(fragment_df_list, ignore_index=True),\n", - " *[pd.concat(other_list, ignore_index=True)\n", - " for other_list in other_fragment_df_lists\n", - " ]\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def calc_fragment_mz_values_for_same_nAA(\n", - " df_group:pd.DataFrame, \n", - " nAA:int, \n", - " charged_frag_types:list\n", - "):\n", - " mod_list = df_group.mods.str.split(';').apply(\n", - " lambda x: [m for m in x if len(m)>0]\n", - " ).values\n", - " site_list = df_group.mod_sites.str.split(';').apply(\n", - " lambda x: [int(s) for s in x if len(s)>0]\n", - " ).values\n", - "\n", - " if 'mod_deltas' in df_group.columns:\n", - " mod_delta_list = df_group.mod_deltas.str.split(';').apply(\n", - " lambda x: [float(m) for m in x if len(m)>0]\n", - " ).values\n", - " mod_delta_site_list = df_group.mod_delta_sites.str.split(';').apply(\n", - " lambda x: [int(s) for s in x if len(s)>0]\n", - " ).values\n", - " else:\n", - " mod_delta_list = None\n", - " mod_delta_site_list = None\n", - " (\n", - " b_mass, y_mass, pepmass\n", - " ) = calc_b_y_and_peptide_masses_for_same_len_seqs(\n", - " df_group.sequence.values.astype('U'), \n", - " mod_list, site_list,\n", - " mod_delta_list,\n", - " mod_delta_site_list\n", - " )\n", - " b_mass = b_mass.reshape(-1)\n", - " y_mass = y_mass.reshape(-1)\n", - "\n", - " for charged_frag_type in charged_frag_types:\n", - " if charged_frag_type.startswith('b_modloss'):\n", - " b_modloss = np.concatenate([\n", - " calc_modloss_mass(nAA, mods, sites, True)\n", - " for mods, sites in zip(mod_list, site_list)\n", - " ])\n", - " break\n", - " for charged_frag_type in charged_frag_types:\n", - " if charged_frag_type.startswith('y_modloss'):\n", - " y_modloss = np.concatenate([\n", - " calc_modloss_mass(nAA, mods, sites, False)\n", - " for mods, sites in zip(mod_list, site_list)\n", - " ])\n", - " break\n", - "\n", - " mz_values = []\n", - " # neutral masses also considered for future uses\n", - " for frag_type in charged_frag_types:\n", - " if frag_type == 'b':\n", - " mz_values.append(b_mass)\n", - " elif frag_type == 'y':\n", - " mz_values.append(y_mass)\n", - " add_proton = MASS_PROTON\n", - " for charged_frag_type in charged_frag_types:\n", - " frag_type, charge = parse_charged_frag_type(charged_frag_type)\n", - " if frag_type =='b':\n", - " mz_values.append(b_mass/charge + add_proton)\n", - " elif frag_type == 'y':\n", - " mz_values.append(y_mass/charge + add_proton)\n", - " elif frag_type == 'b_modloss':\n", - " _mass = (b_mass-b_modloss)/charge + add_proton\n", - " _mass[b_modloss == 0] = 0\n", - " mz_values.append(_mass)\n", - " elif frag_type == 'y_modloss':\n", - " _mass = (y_mass-y_modloss)/charge + add_proton\n", - " _mass[y_modloss == 0] = 0\n", - " mz_values.append(_mass)\n", - " elif frag_type == 'b_H2O':\n", - " _mass = (b_mass-MASS_H2O)/charge + add_proton\n", - " mz_values.append(_mass)\n", - " elif frag_type == 'y_H2O':\n", - " _mass = (y_mass-MASS_H2O)/charge + add_proton\n", - " mz_values.append(_mass)\n", - " elif frag_type == 'b_NH3':\n", - " _mass = (b_mass-MASS_NH3)/charge + add_proton\n", - " mz_values.append(_mass)\n", - " elif frag_type == 'y_NH3':\n", - " _mass = (y_mass-MASS_NH3)/charge + add_proton\n", - " mz_values.append(_mass)\n", - " elif frag_type == 'c':\n", - " _mass = (b_mass+MASS_NH3)/charge + add_proton\n", - " mz_values.append(_mass)\n", - " elif frag_type == 'z':\n", - " _mass = (\n", - " y_mass-(MASS_NH3-CHEM_MONO_MASS['H'])\n", - " )/charge + add_proton\n", - " mz_values.append(_mass)\n", - " else:\n", - " raise NotImplementedError(\n", - " f'Fragment type \"{frag_type}\" is not in fragment_mz_df.'\n", - " )\n", - " return np.array(mz_values).T" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def mask_fragments_for_charge_greater_than_precursor_charge(\n", - " fragment_df:pd.DataFrame, \n", - " precursor_charge_array:np.ndarray,\n", - " nAA_array:np.ndarray,\n", - " *,\n", - " candidate_fragment_charges:list = [2,3,4],\n", - "):\n", - " \"\"\"Mask the fragment dataframe when \n", - " the fragment charge is larger than the precursor charge\"\"\"\n", - " precursor_charge_array = np.repeat(\n", - " precursor_charge_array, nAA_array-1\n", - " )\n", - " for col in fragment_df.columns:\n", - " for charge in candidate_fragment_charges:\n", - " if col.endswith(f'z{charge}'):\n", - " fragment_df.loc[\n", - " precursor_charge_arraypd.DataFrame:\n", - " \"\"\"Sort nAA in precursor_df for faster fragment mz dataframe creation.\n", - "\n", - " Because the fragment mz values are continous in memory, so it is faster\n", - " when setting values in pandas.\n", - "\n", - " Note that this function will change the order and index of precursor_df\n", - "\n", - " Parameters\n", - " ----------\n", - " precursor_df : pd.DataFrame\n", - " precursor dataframe\n", - "\n", - " charged_frag_types : List\n", - " fragment types list\n", - "\n", - " batch_size : int, optional\n", - " Calculate fragment mz values in batch. \n", - " Defaults to 500000.\n", - " \"\"\"\n", - " if 'frag_start_idx' in precursor_df.columns:\n", - " precursor_df.drop(columns=[\n", - " 'frag_start_idx','frag_end_idx'\n", - " ], inplace=True)\n", - "\n", - " refine_precursor_df(precursor_df)\n", - "\n", - " fragment_mz_df = init_fragment_by_precursor_dataframe(\n", - " precursor_df, charged_frag_types\n", - " )\n", - "\n", - " _grouped = precursor_df.groupby('nAA')\n", - " for nAA, big_df_group in _grouped:\n", - " for i in range(0, len(big_df_group), batch_size):\n", - " batch_end = i+batch_size\n", - " \n", - " df_group = big_df_group.iloc[i:batch_end,:]\n", - "\n", - " mz_values = calc_fragment_mz_values_for_same_nAA(\n", - " df_group, nAA, charged_frag_types\n", - " )\n", - "\n", - " fragment_mz_df.iloc[\n", - " df_group.frag_start_idx.values[0]:\n", - " df_group.frag_end_idx.values[-1], :\n", - " ] = mz_values\n", - " return mask_fragments_for_charge_greater_than_precursor_charge(\n", - " fragment_mz_df,\n", - " precursor_df.charge.values,\n", - " precursor_df.nAA.values,\n", - " )\n", - "\n", - "def create_fragment_mz_dataframe(\n", - " precursor_df: pd.DataFrame,\n", - " charged_frag_types:List,\n", - " *,\n", - " reference_fragment_df: pd.DataFrame = None,\n", - " inplace_in_reference:bool = False,\n", - " batch_size:int=500000,\n", - ")->pd.DataFrame:\n", - " '''\n", - " Generate fragment mass dataframe for the precursor_df. If \n", - " the `reference_fragment_df` is provided and precursor_df contains `frag_start_idx`, \n", - " it will generate the mz dataframe based on the reference. Otherwise it \n", - " generates the mz dataframe from scratch.\n", - " \n", - " Parameters\n", - " ----------\n", - " precursor_df : pd.DataFrame\n", - " precursors to generate fragment masses,\n", - " if `precursor_df` contains the 'frag_start_idx' column, \n", - " `reference_fragment_df` must be provided\n", - " charged_frag_types : List\n", - " `['b_z1','b_z2','y_z1','y_z2','b_modloss_1','y_H2O_z1'...]`\n", - "\n", - " reference_fragment_df : pd.DataFrame\n", - " kwargs only. Generate fragment_mz_df based on this reference, \n", - " as `precursor_df.frag_start_idx` and \n", - " `precursor.frag_end_idx` point to the indices in \n", - " `reference_fragment_df`.\n", - " Defaults to None\n", - "\n", - " inplace_in_reference : bool\n", - " kwargs only. Change values in place in the `reference_fragment_df`.\n", - " Defaults to False\n", - "\n", - " batch_size: int\n", - " Number of peptides for each batch, to save RAM.\n", - "\n", - " Returns\n", - " -------\n", - " pd.DataFrame\n", - " `fragment_mz_df` with given `charged_frag_types`\n", - " \n", - " # Raises\n", - " # ------\n", - " # ValueError\n", - " # when `precursor_df` contains 'frag_start_idx' but \n", - " # `reference_fragment_df` is not None\n", - " '''\n", - " if reference_fragment_df is None:\n", - " if 'frag_start_idx' in precursor_df.columns:\n", - " # raise ValueError(\n", - " # \"`precursor_df` contains 'frag_start_idx' column, \"\\\n", - " # \"please provide `reference_fragment_df` argument\"\n", - " # )\n", - " fragment_mz_df = init_fragment_by_precursor_dataframe(\n", - " precursor_df, charged_frag_types,\n", - " )\n", - " return create_fragment_mz_dataframe(\n", - " precursor_df=precursor_df, \n", - " charged_frag_types=charged_frag_types,\n", - " reference_fragment_df=fragment_mz_df,\n", - " inplace_in_reference=True,\n", - " batch_size=batch_size,\n", - " )\n", - " if 'nAA' not in precursor_df.columns:\n", - " # fast\n", - " return create_fragment_mz_dataframe_by_sort_precursor(\n", - " precursor_df, charged_frag_types, batch_size\n", - " )\n", - "\n", - " if (is_precursor_sorted(precursor_df) and \n", - " reference_fragment_df is None\n", - " ):\n", - " # fast\n", - " return create_fragment_mz_dataframe_by_sort_precursor(\n", - " precursor_df, charged_frag_types, batch_size\n", - " )\n", - "\n", - " else:\n", - " # slow\n", - " if reference_fragment_df is not None:\n", - " if inplace_in_reference:\n", - " fragment_mz_df = reference_fragment_df.loc[:,[\n", - " _fr for _fr in charged_frag_types \n", - " if _fr in reference_fragment_df.columns\n", - " ]]\n", - " else:\n", - " fragment_mz_df = pd.DataFrame(\n", - " np.zeros((\n", - " len(reference_fragment_df), \n", - " len(charged_frag_types)\n", - " )),\n", - " columns = charged_frag_types\n", - " )\n", - " else:\n", - " fragment_mz_df = init_fragment_by_precursor_dataframe(\n", - " precursor_df, charged_frag_types,\n", - " )\n", - "\n", - " _grouped = precursor_df.groupby('nAA')\n", - " for nAA, big_df_group in _grouped:\n", - " for i in range(0, len(big_df_group), batch_size):\n", - " batch_end = i+batch_size\n", - " \n", - " df_group = big_df_group.iloc[i:batch_end,:]\n", - "\n", - " mz_values = calc_fragment_mz_values_for_same_nAA(\n", - " df_group, nAA, fragment_mz_df.columns\n", - " )\n", - " \n", - " update_sliced_fragment_dataframe(\n", - " fragment_mz_df, mz_values, \n", - " df_group[['frag_start_idx','frag_end_idx']].values, \n", - " )\n", - "\n", - " return mask_fragments_for_charge_greater_than_precursor_charge(\n", - " fragment_mz_df,\n", - " precursor_df.charge.values,\n", - " precursor_df.nAA.values,\n", - " )\n" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -815,6 +136,14 @@ "execution_count": null, "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/lc/9594t94d5b5_gn0y04w1jh980000gn/T/ipykernel_87333/3544571044.py:22: FutureWarning: is_monotonic is deprecated and will be removed in a future version. Use is_monotonic_increasing instead.\n", + " assert precursor_df.nAA.is_monotonic\n" + ] + }, { "data": { "text/html": [ @@ -1317,13 +646,880 @@ "cell_type": "code", "execution_count": null, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
mzintensitytypeposition
098.0600400.4980
149.5336580.7980
2769.2651570.61210
3385.1362170.81210
4671.2882620.11210
...............
193152.5844110.012111
1941572.6205890.69812
195786.8139330.99812
196175.1189520.312112
19788.0631140.312112
\n", + "

198 rows × 4 columns

\n", + "
" + ], + "text/plain": [ + " mz intensity type position\n", + "0 98.060040 0.4 98 0\n", + "1 49.533658 0.7 98 0\n", + "2 769.265157 0.6 121 0\n", + "3 385.136217 0.8 121 0\n", + "4 671.288262 0.1 121 0\n", + ".. ... ... ... ...\n", + "193 152.584411 0.0 121 11\n", + "194 1572.620589 0.6 98 12\n", + "195 786.813933 0.9 98 12\n", + "196 175.118952 0.3 121 12\n", + "197 88.063114 0.3 121 12\n", + "\n", + "[198 rows x 4 columns]" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| hide\n", + "repeat = 2\n", + "peptides = ['AGHCEWQMKAADER']*repeat\n", + "mods = ['Acetyl@Protein N-term;Carbamidomethyl@C;Oxidation@M']*repeat\n", + "sites = ['0;4;8']*repeat\n", + "peptides += ['AGHCEWQMK']*repeat\n", + "mods += ['']*repeat\n", + "sites += ['']*repeat\n", + "peptides += ['PEPSIDE']*repeat\n", + "mods += ['Phospho@S']*repeat\n", + "sites += ['4']*repeat\n", + "\n", + "precursor_df = pd.DataFrame({\n", + " 'sequence': peptides,\n", + " 'mods': mods,\n", + " 'mod_sites': sites\n", + "})\n", + "np.random.seed(0)\n", + "precursor_df['nAA'] = precursor_df['sequence'].str.len()\n", + "precursor_df['charge'] = np.random.randint(1,4, size=len(mods))\n", + "precursor_df = update_precursor_mz(precursor_df)\n", + "\n", + "fragment_mz_df = create_fragment_mz_dataframe_by_sort_precursor(\n", + " precursor_df,\n", + " get_charged_frag_types(['b','y','b_modloss','y_modloss'],2)\n", + ")\n", + "fragment_intensity_df = fragment_mz_df.copy()\n", + "fragment_intensity_df[fragment_intensity_df.columns] = np.random.randint(0,11, size=(fragment_mz_df.shape))/10.0\n", + "\n", + "precursor_new_df, fragment_df = flatten_fragments(\n", + " precursor_df, fragment_mz_df, fragment_intensity_df, \n", + " min_fragment_intensity=-1,keep_top_k_fragments=1000,\n", + " custom_columns=['type','position']\n", + ")\n", + "assert(isinstance(precursor_new_df, pd.DataFrame))\n", + "assert(isinstance(fragment_df, pd.DataFrame))\n", + "assert 'type' in fragment_df.columns\n", + "assert 'position' in fragment_df.columns\n", + "assert 'number' not in fragment_df.columns\n", + "assert 'charge' not in fragment_df.columns\n", + "assert 'loss_type' not in fragment_df.columns\n", + "\n", + "fragment_count = np.sum(fragment_mz_df.values>0)\n", + "\n", + "assert(len(fragment_df) == fragment_count)\n", + "assert(precursor_new_df['frag_end_idx'].iloc[-1] == fragment_count)\n", + "fragment_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sequencemodsmod_sitesnAAchargeprecursor_mzfrag_start_idxfrag_end_idx
0PEPSIDEPhospho@S472433.662599036
1PEPSIDEPhospho@S473289.4441583672
2AGHCEWQMK911089.4604477288
3AGHCEWQMK92545.23386288120
4AGHCEWQMKAADERAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;81411746.732265120146
5AGHCEWQMKAADERAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;8142873.869771146198
\n", + "
" + ], + "text/plain": [ + " sequence mods \\\n", + "0 PEPSIDE Phospho@S \n", + "1 PEPSIDE Phospho@S \n", + "2 AGHCEWQMK \n", + "3 AGHCEWQMK \n", + "4 AGHCEWQMKAADER Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat... \n", + "5 AGHCEWQMKAADER Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat... \n", + "\n", + " mod_sites nAA charge precursor_mz frag_start_idx frag_end_idx \n", + "0 4 7 2 433.662599 0 36 \n", + "1 4 7 3 289.444158 36 72 \n", + "2 9 1 1089.460447 72 88 \n", + "3 9 2 545.233862 88 120 \n", + "4 0;4;8 14 1 1746.732265 120 146 \n", + "5 0;4;8 14 2 873.869771 146 198 " + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| hide\n", + "precursor_new_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
mzintensitytypeposition
0385.1362170.81210
1542.2456690.81211
2271.6264730.91211
3604.2378210.9984
4302.6225480.9984
5132.0473271.01214
698.0600400.8980
7671.2882621.01210
8336.1477690.81210
9320.6149200.91211
10302.6225481.0984
11719.2647640.9985
12129.0658540.9981
13961.4018701.01211
14369.1339510.9983
15406.2118670.81215
16812.3144340.8986
17147.1128040.41217
181018.4233330.91210
19824.3429580.91212
20361.1705250.81213
21684.2558571.0985
22943.3549190.9987
23472.1810980.9987
24114.0549551.0980
251576.6631230.81211
26689.3576790.91217
271257.5139390.8989
281443.5779961.09811
29175.1189520.812112
3057.5311161.0980
311633.6845861.01210
32720.3057441.01212
33234.5866281.0983
34640.2904191.01213
35345.1824780.91217
\n", + "
" + ], + "text/plain": [ + " mz intensity type position\n", + "0 385.136217 0.8 121 0\n", + "1 542.245669 0.8 121 1\n", + "2 271.626473 0.9 121 1\n", + "3 604.237821 0.9 98 4\n", + "4 302.622548 0.9 98 4\n", + "5 132.047327 1.0 121 4\n", + "6 98.060040 0.8 98 0\n", + "7 671.288262 1.0 121 0\n", + "8 336.147769 0.8 121 0\n", + "9 320.614920 0.9 121 1\n", + "10 302.622548 1.0 98 4\n", + "11 719.264764 0.9 98 5\n", + "12 129.065854 0.9 98 1\n", + "13 961.401870 1.0 121 1\n", + "14 369.133951 0.9 98 3\n", + "15 406.211867 0.8 121 5\n", + "16 812.314434 0.8 98 6\n", + "17 147.112804 0.4 121 7\n", + "18 1018.423333 0.9 121 0\n", + "19 824.342958 0.9 121 2\n", + "20 361.170525 0.8 121 3\n", + "21 684.255857 1.0 98 5\n", + "22 943.354919 0.9 98 7\n", + "23 472.181098 0.9 98 7\n", + "24 114.054955 1.0 98 0\n", + "25 1576.663123 0.8 121 1\n", + "26 689.357679 0.9 121 7\n", + "27 1257.513939 0.8 98 9\n", + "28 1443.577996 1.0 98 11\n", + "29 175.118952 0.8 121 12\n", + "30 57.531116 1.0 98 0\n", + "31 1633.684586 1.0 121 0\n", + "32 720.305744 1.0 121 2\n", + "33 234.586628 1.0 98 3\n", + "34 640.290419 1.0 121 3\n", + "35 345.182478 0.9 121 7" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| hide\n", + "precursor_new_df, fragment_df = flatten_fragments(\n", + " precursor_df, fragment_mz_df, fragment_intensity_df, \n", + " min_fragment_intensity=-1,keep_top_k_fragments=6,\n", + " custom_columns=['type','position']\n", + ")\n", + "assert (precursor_new_df.frag_end_idx.values - precursor_new_df.frag_start_idx.values).max() <= 6\n", + "fragment_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sequencemodsmod_sitesnAAchargeprecursor_mzfrag_start_idxfrag_end_idx
0PEPSIDEPhospho@S472433.66259906
1PEPSIDEPhospho@S473289.444158612
2AGHCEWQMK911089.4604471218
3AGHCEWQMK92545.2338621824
4AGHCEWQMKAADERAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;81411746.7322652430
5AGHCEWQMKAADERAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;8142873.8697713036
\n", + "
" + ], + "text/plain": [ + " sequence mods \\\n", + "0 PEPSIDE Phospho@S \n", + "1 PEPSIDE Phospho@S \n", + "2 AGHCEWQMK \n", + "3 AGHCEWQMK \n", + "4 AGHCEWQMKAADER Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat... \n", + "5 AGHCEWQMKAADER Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat... \n", + "\n", + " mod_sites nAA charge precursor_mz frag_start_idx frag_end_idx \n", + "0 4 7 2 433.662599 0 6 \n", + "1 4 7 3 289.444158 6 12 \n", + "2 9 1 1089.460447 12 18 \n", + "3 9 2 545.233862 18 24 \n", + "4 0;4;8 14 1 1746.732265 24 30 \n", + "5 0;4;8 14 2 873.869771 30 36 " + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| hide\n", + "precursor_new_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| hide\n", + "\n", + "repeat = 2\n", + "peptides = ['AGHCEWQMKAADER']*repeat\n", + "peptides += ['AGHCEWQMK']*repeat\n", + "peptides += ['PEPTIDE']*repeat\n", + "mods = ['']*repeat*3\n", + "sites = ['']*repeat*3\n", + "charge = [2, 3]*3\n", + "\n", + "precursor_df = pd.DataFrame({\n", + " 'sequence': peptides,\n", + " 'mods': mods,\n", + " 'mod_sites': sites,\n", + " 'charge': charge\n", + "})\n", + "precursor_df['nAA'] = precursor_df['sequence'].str.len()\n", + "precursor_df = update_precursor_mz(precursor_df)\n", + "\n", + "fragment_mz_df = create_fragment_mz_dataframe_by_sort_precursor(\n", + " precursor_df,\n", + " get_charged_frag_types(['b','y'],2)\n", + ")\n", + "\n", + "fragment_intensity_df = fragment_mz_df.copy()\n", + "fragment_intensity_df[fragment_intensity_df.columns] = np.random.random_sample(size=(fragment_mz_df.shape))\n", + "\n", + "small_precursor_df = precursor_df[precursor_df['charge'] == 2].sample(frac=1)\n", + "small_precursor_df.reset_index(drop=True, inplace=True)\n", + "new_small_precursor_df, (new_fragment_mz_df, new_fragment_intensity_df) = remove_unused_fragments(small_precursor_df, (fragment_mz_df, fragment_intensity_df))\n", + "\n", + "# iterate all precursors and make sure that the precursor order and fragments match\n", + "for i in range(len(small_precursor_df)):\n", + " old_frag_idx = small_precursor_df[['frag_start_idx','frag_end_idx']].values[i]\n", + " new_frag_idx = new_small_precursor_df[['frag_start_idx','frag_end_idx']].values[i]\n", + "\n", + " # check fragment intensities\n", + " old_slice = fragment_intensity_df.values[old_frag_idx[0]:old_frag_idx[1]]\n", + " new_slice = new_fragment_intensity_df.values[new_frag_idx[0]:new_frag_idx[1]]\n", + " assert np.allclose(old_slice,new_slice)\n", + "\n", + " # check fragment mzs\n", + " old_slice = fragment_mz_df.values[old_frag_idx[0]:old_frag_idx[1]]\n", + " new_slice = new_fragment_mz_df.values[new_frag_idx[0]:new_frag_idx[1]]\n", + "\n", + " assert np.allclose(old_slice,new_slice)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| hide\n", + "def test_join_left():\n", + "\n", + " left = np.random.randint(0,10,20)\n", + " right = np.arange(0,10)\n", + " joined = join_left(left, right)\n", + "\n", + " assert all(left==joined)\n", + "\n", + "test_join_left()" + ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3.8.3 ('base')", + "display_name": "alpha", "language": "python", "name": "python3" } diff --git a/nbdev_nbs/peptide/mass_calc.ipynb b/nbdev_nbs/peptide/mass_calc.ipynb index a3322aa4..aecb05ec 100644 --- a/nbdev_nbs/peptide/mass_calc.ipynb +++ b/nbdev_nbs/peptide/mass_calc.ipynb @@ -6,7 +6,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| default_exp peptide.mass_calc" + "#---#| default_exp peptide.mass_calc" ] }, { @@ -40,145 +40,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| export\n", - "\n", - "import numpy as np\n", - "from typing import List, Tuple\n", - "\n", - "from alphabase.constants.aa import (\n", - " calc_sequence_mass, \n", - " calc_AA_masses_for_same_len_seqs,\n", - " calc_sequence_masses_for_same_len_seqs\n", - ")\n", - "from alphabase.constants.modification import (\n", - " calc_modification_mass,\n", - " calc_modification_mass_sum,\n", - " calc_mod_masses_for_same_len_seqs\n", - ")\n", - "from alphabase.constants.element import MASS_H2O" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def calc_delta_modification_mass(\n", - " pep_len:int,\n", - " mass_deltas:List[float],\n", - " mass_delta_sites:List[int]\n", - ")->np.ndarray:\n", - " '''\n", - " For open-search, we may also get modification \n", - " mass deltas other than mod names. This function calculate\n", - " modification masses from these delta masses.\n", - " \n", - " Parameters\n", - " ----------\n", - " pep_len : int\n", - " nAA\n", - " \n", - " mass_deltas : List[float]\n", - " mass deltas on the peptide\n", - "\n", - " mass_delta_sites : List[int]\n", - " localized sites of corresponding mass deltas\n", - "\n", - " Returns\n", - " -------\n", - " np.ndarray\n", - " 1-D array with length=`peplen`.\n", - " Masses of modifications (mass deltas) through the peptide,\n", - " `0` if sites has no modifications\n", - " '''\n", - " masses = np.zeros(pep_len)\n", - " for site, mass in zip(mass_delta_sites, mass_deltas):\n", - " if site == 0:\n", - " masses[site] += mass\n", - " elif site == -1:\n", - " masses[site] += mass\n", - " else:\n", - " masses[site-1] += mass\n", - " return masses\n", - "\n", - "def calc_mod_delta_masses_for_same_len_seqs(\n", - " nAA:int, \n", - " mod_deltas_list:List[List[float]], \n", - " mod_sites_list:List[List[int]]\n", - ")->np.ndarray:\n", - " '''\n", - " Calculate delta modification masses for the given peptide length (`nAA`), \n", - " For open-search, we may also get modification \n", - " mass deltas other than mod names. This function calculate\n", - " modification masses from these delta masses.\n", - " \n", - " Parameters\n", - " ----------\n", - " nAA : int\n", - " peptide length\n", - "\n", - " mod_names_list : List[List[str]]\n", - " list of modification list\n", - "\n", - " mod_sites_list : List[List[int]]\n", - " list of modification site list corresponding \n", - " to `mod_names_list`.\n", - " * `site=0` refers to an N-term modification\n", - " * `site=-1` refers to a C-term modification\n", - " * `1<=site<=peplen` refers to a normal modification\n", - " \n", - " Returns\n", - " -------\n", - " np.ndarray\n", - " 2-D array with shape=`(nAA, pep_count or len(mod_names_list)))`. \n", - " Masses of modifications through all the peptides, \n", - " `0` if sites has no modifications\n", - " '''\n", - " masses = np.zeros((len(mod_deltas_list),nAA))\n", - " for i, (mod_deltas, mod_sites) in enumerate(\n", - " zip(mod_deltas_list, mod_sites_list)\n", - " ):\n", - " for mod_delta, site in zip(mod_deltas, mod_sites): \n", - " if site == 0:\n", - " masses[i,site] += mod_delta\n", - " elif site == -1:\n", - " masses[i,site] += mod_delta\n", - " else:\n", - " masses[i,site-1] += mod_delta\n", - " return masses\n", - "\n", - "def calc_b_y_and_peptide_mass(\n", - " sequence: str,\n", - " mod_names: List[str],\n", - " mod_sites: List[int],\n", - " mod_deltas: List[float] = None,\n", - " mod_delta_sites: List[int] = None,\n", - ")->Tuple[np.ndarray,np.ndarray,float]:\n", - " '''\n", - " It is highly recommend to use \n", - " `calc_b_y_and_peptide_masses_for_same_len_seqs`\n", - " as it is much faster\n", - " '''\n", - " residue_masses = calc_sequence_mass(sequence)\n", - " mod_masses = calc_modification_mass(\n", - " len(sequence), mod_names, mod_sites\n", - " )\n", - " residue_masses += mod_masses\n", - " if mod_deltas is not None:\n", - " mod_masses = calc_delta_modification_mass(\n", - " len(sequence), mod_deltas, mod_delta_sites\n", - " )\n", - " residue_masses += mod_masses\n", - " #residue_masses = residue_masses[np.newaxis, ...]\n", - " b_masses = np.cumsum(residue_masses)\n", - " b_masses, pepmass = b_masses[:-1], b_masses[-1]\n", - " \n", - " pepmass += MASS_H2O\n", - " y_masses = pepmass - b_masses\n", - " return b_masses, y_masses, pepmass" + "from alphabase.peptide.mass_calc import *" ] }, { @@ -192,141 +54,6 @@ "`calc_b_y_and_peptide_masses_for_same_len_seqs` calculates b/y neutral masses and peptide masses for the given sequence array and modification lists. Note that all a/b/c neutral masses can be calculated from b fragment masses, and x/y/z from y masses. So the key are b/y masses." ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def calc_peptide_masses_for_same_len_seqs(\n", - " sequences: np.ndarray,\n", - " mod_list: List[str],\n", - " mod_delta_list: List[str]=None\n", - ")->np.ndarray:\n", - " '''\n", - " Calculate peptide masses for peptide sequences with same lengths.\n", - " We need 'same_len' here because numpy can process AA sequences \n", - " with same length very fast. \n", - " See `alphabase.aa.calc_sequence_masses_for_same_len_seqs`\n", - "\n", - " Parameters\n", - " ----------\n", - " mod_list : List[str]\n", - "\n", - " list of modifications, \n", - " e.g. `['Oxidation@M;Phospho@S','Phospho@S;Deamidated@N']`\n", - "\n", - " mass_delta_list : List[str]\n", - " \n", - " List of modifications as mass deltas,\n", - " e.g. `['15.9xx;79.9xxx','79.9xx;0.98xx']`\n", - " \n", - " Returns\n", - " -------\n", - " np.ndarray\n", - " \n", - " peptide masses (1-D array, H2O already added)\n", - " '''\n", - " seq_masses = calc_sequence_masses_for_same_len_seqs(\n", - " sequences\n", - " )\n", - " mod_masses = np.zeros_like(seq_masses)\n", - " for i, mods in enumerate(mod_list):\n", - " if len(mods) > 0:\n", - " mod_masses[i] = calc_modification_mass_sum(\n", - " mods.split(';')\n", - " )\n", - " if mod_delta_list is not None:\n", - " for i, mass_deltas in enumerate(mod_delta_list):\n", - " if len(mass_deltas) > 0:\n", - " mod_masses[i] += np.sum([\n", - " float(mass) for mass in mass_deltas.split(';')\n", - " ])\n", - " return seq_masses+mod_masses\n", - " \n", - "\n", - "def calc_b_y_and_peptide_masses_for_same_len_seqs(\n", - " sequences: np.ndarray,\n", - " mod_list: List[List[str]],\n", - " site_list: List[List[int]],\n", - " mod_delta_list: List[List[float]]=None,\n", - " mod_delta_site_list: List[List[int]]=None,\n", - ")->Tuple[np.ndarray,np.ndarray,np.ndarray]:\n", - " '''\n", - " Calculate b/y fragment masses and peptide masses \n", - " for peptide sequences with same lengths.\n", - " We need 'same_len' here because numpy can process AA sequences \n", - " with same length very fast.\n", - "\n", - " Parameters\n", - " ----------\n", - " sequence : np.ndarray of str\n", - " np.ndarray of peptie sequences with same length.\n", - "\n", - " mod_list : List[List[str]]\n", - " list of modifications , \n", - " e.g. `[['Oxidation@M','Phospho@S'],['Phospho@S','Deamidated@N']]` \n", - "\n", - " site_list : List[List[int]]\n", - " list of modification sites\n", - " corresponding to `mod_list`, e.g. `[[3,6],[4,17]]`\n", - "\n", - " mod_delta_list : List[List[float]]\n", - " list of modifications, \n", - " e.g. `[[15.994915,79.966331],[79.966331,0.984016]]` \n", - "\n", - " mod_delta_site_list : List[List[int]]\n", - " list of modification mass delta sites\n", - " corresponding to `mod_list`, e.g. `[[3,6],[4,17]]`\n", - " \n", - " Returns\n", - " -------\n", - " np.ndarray\n", - " neutral b fragment masses (2-D array)\n", - "\n", - " np.ndarray\n", - " neutral y fragmnet masses (2-D array)\n", - "\n", - " np.ndarray\n", - " neutral peptide masses (1-D array)\n", - " '''\n", - " aa_masses = calc_AA_masses_for_same_len_seqs(sequences)\n", - " nAA = len(sequences[0])\n", - "\n", - " # mod_masses = np.zeros_like(aa_masses)\n", - " # for i, (mods, sites) in enumerate(zip(mod_list, site_list)):\n", - " # if len(mods) != 0:\n", - " # mod_masses[i,:] = calc_modification_mass(\n", - " # seq_len, \n", - " # mods, \n", - " # sites,\n", - " # )\n", - " mod_masses = calc_mod_masses_for_same_len_seqs(nAA, mod_list, site_list)\n", - " if mod_delta_list is not None:\n", - " mod_masses += calc_mod_delta_masses_for_same_len_seqs(\n", - " nAA, mod_delta_list, mod_delta_site_list\n", - " )\n", - " # for i, (mass_deltas, sites) in enumerate(zip(\n", - " # mass_delta_list, mass_delta_site_list\n", - " # )):\n", - " # if len(mass_deltas) != 0:\n", - " # mod_masses[i,:] += calc_delta_modification_mass(\n", - " # seq_len, \n", - " # mass_deltas, \n", - " # sites,\n", - " # )\n", - " aa_masses += mod_masses\n", - "\n", - " b_masses = np.cumsum(aa_masses, axis=1)\n", - " b_masses, pepmass = b_masses[:,:-1], b_masses[:,-1:]\n", - " \n", - " pepmass += MASS_H2O\n", - " y_masses = pepmass - b_masses\n", - " return b_masses, y_masses, pepmass.flatten()" - ] - }, { "cell_type": "markdown", "metadata": {}, diff --git a/nbdev_nbs/peptide/mobility.ipynb b/nbdev_nbs/peptide/mobility.ipynb index 2aea00fd..3df0c613 100644 --- a/nbdev_nbs/peptide/mobility.ipynb +++ b/nbdev_nbs/peptide/mobility.ipynb @@ -6,7 +6,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| default_exp peptide.mobility" + "#---#| default_exp peptide.mobility" ] }, { @@ -16,127 +16,6 @@ "# CCS/Mobility Functionalities" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "import numpy as np\n", - "import pandas as pd\n", - "\n", - "from alphabase.peptide.fragment import update_precursor_mz\n", - "from alphabase.constants.element import common_const_dict" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "CCS_IM_COEF = common_const_dict['MOBILITY']['CCS_IM_COEF']\n", - "IM_GAS_MASS = common_const_dict['MOBILITY']['IM_GAS_MASS']\n", - "\n", - "def get_reduced_mass(\n", - " precursor_mzs: np.ndarray, \n", - " charges: np.ndarray\n", - ")->np.ndarray:\n", - " \"\"\" Reduced mass for CCS and mobility calculation \"\"\"\n", - " reduced_masses = precursor_mzs*charges\n", - " return reduced_masses*IM_GAS_MASS/(reduced_masses+IM_GAS_MASS)\n", - "\n", - "def ccs_to_mobility_bruker(\n", - " ccs_values: np.ndarray, \n", - " charges: np.ndarray, \n", - " precursor_mzs: np.ndarray\n", - ")->np.ndarray:\n", - " \"\"\" Convert CCS to mobility for Bruker (timsTOF) \"\"\"\n", - " reduced_masses = get_reduced_mass(precursor_mzs, charges)\n", - " return ccs_values*np.sqrt(reduced_masses)/charges/CCS_IM_COEF\n", - "\n", - "def mobility_to_ccs_bruker(\n", - " im_values: np.ndarray, \n", - " charges: np.ndarray, \n", - " precursor_mzs: np.ndarray\n", - ")->np.ndarray:\n", - " \"\"\" Convert mobility to CCS for Bruker (timsTOF) \"\"\"\n", - " reduced_masses = get_reduced_mass(precursor_mzs, charges)\n", - " return im_values*charges*CCS_IM_COEF/np.sqrt(reduced_masses)\n", - "\n", - "def ccs_to_mobility_for_df(\n", - " precursor_df:pd.DataFrame,\n", - " ccs_column:str,\n", - " *,\n", - " vendor=\"bruker\"\n", - ")->np.ndarray:\n", - " \"\"\"\n", - "\n", - " Parameters\n", - " ----------\n", - " precursor_df : pd.DataFrame\n", - " precursor_df\n", - "\n", - " ccs_column : str\n", - " CCS column name in precursor_df\n", - "\n", - " vendor : str, optional\n", - " Different vender may have different IM calculation. \n", - " Defaults to \"bruker\".\n", - " Note that other vendors are not implemented currently.\n", - "\n", - " Returns\n", - " -------\n", - " np.ndarray\n", - " mobility values\n", - " \"\"\"\n", - " if 'precursor_mz' not in precursor_df.columns:\n", - " precursor_df = update_precursor_mz(precursor_df)\n", - " return ccs_to_mobility_bruker(\n", - " precursor_df[ccs_column].values, \n", - " precursor_df.charge.values,\n", - " precursor_df.precursor_mz.values\n", - " )\n", - "\n", - "def mobility_to_ccs_for_df(\n", - " precursor_df:pd.DataFrame,\n", - " mobility_column:str,\n", - " *,\n", - " vendor=\"bruker\"\n", - ")->np.ndarray:\n", - " \"\"\"\n", - "\n", - " Parameters\n", - " ----------\n", - " precursor_df : pd.DataFrame\n", - " precursor_df\n", - "\n", - " mobility_column : str\n", - " mobility column name in precursor_df\n", - "\n", - " vendor : str, optional\n", - " Different vender may have different IM calculation. \n", - " Defaults to \"bruker\".\n", - " Note that other vendors are not implemented currently.\n", - "\n", - " Returns\n", - " -------\n", - " np.ndarray\n", - " CCS values\n", - " \"\"\"\n", - " \n", - " if 'precursor_mz' not in precursor_df.columns:\n", - " precursor_df = update_precursor_mz(precursor_df)\n", - " return mobility_to_ccs_bruker(\n", - " precursor_df[mobility_column].values,\n", - " precursor_df.charge.values,\n", - " precursor_df.precursor_mz.values\n", - " )" - ] - }, { "cell_type": "code", "execution_count": null, diff --git a/nbdev_nbs/peptide/precursor.ipynb b/nbdev_nbs/peptide/precursor.ipynb index 961a0106..c0ebdab2 100644 --- a/nbdev_nbs/peptide/precursor.ipynb +++ b/nbdev_nbs/peptide/precursor.ipynb @@ -6,7 +6,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| default_exp peptide.precursor" + "#---#| default_exp peptide.precursor" ] }, { @@ -22,568 +22,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| export\n", - "import pandas as pd\n", - "import numpy as np\n", - "import numba\n", - "import multiprocessing as mp\n", - "\n", - "from mmh3 import hash64\n", - "from functools import partial\n", - "\n", - "from alphabase.constants.element import (\n", - " MASS_PROTON, MASS_ISOTOPE\n", - ")\n", - "from alphabase.constants.aa import AA_formula\n", - "from alphabase.constants.modification import MOD_formula\n", - "from alphabase.constants.isotope import (\n", - " IsotopeDistribution\n", - ")\n", - "from alphabase.peptide.mass_calc import (\n", - " calc_peptide_masses_for_same_len_seqs\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def refine_precursor_df(\n", - " df:pd.DataFrame, \n", - " drop_frag_idx = True,\n", - " ensure_data_validity = False,\n", - ")->pd.DataFrame:\n", - " \"\"\" \n", - " Refine df inplace for faster precursor/fragment calculation.\n", - " \"\"\"\n", - " if ensure_data_validity:\n", - " df.fillna('', inplace=True)\n", - " if 'charge' in df.columns:\n", - " if df.charge.dtype not in [\n", - " 'int','int8','int64','int32',\n", - " # np.int64, np.int32, np.int8,\n", - " ]:\n", - " df['charge'] = df['charge'].astype(np.int8)\n", - " if 'mod_sites' in df.columns:\n", - " if df.mod_sites.dtype not in ['O','U']:\n", - " df['mod_sites'] = df.mod_sites.astype('U')\n", - "\n", - " if 'nAA' not in df.columns:\n", - " df['nAA']= df.sequence.str.len().astype(np.int32)\n", - "\n", - " if drop_frag_idx and 'frag_start_idx' in df.columns:\n", - " df.drop(columns=[\n", - " 'frag_start_idx','frag_end_idx'\n", - " ], inplace=True)\n", - "\n", - " if not is_precursor_refined(df):\n", - " df.sort_values('nAA', inplace=True)\n", - " df.reset_index(drop=True, inplace=True)\n", - "\n", - " return df\n", - "\n", - "reset_precursor_df = refine_precursor_df\n", - "\n", - "def is_precursor_refined(precursor_df: pd.DataFrame):\n", - " return (\n", - " (len(precursor_df) == 0) or (\n", - " (precursor_df.index.values[0] == 0) and\n", - " precursor_df.nAA.is_monotonic and\n", - " np.all(\n", - " np.diff(precursor_df.index.values)==1\n", - " )\n", - " )\n", - " )\n", - "\n", - "is_precursor_sorted = is_precursor_refined\n", - "\n", - "def update_precursor_mz(\n", - " precursor_df: pd.DataFrame,\n", - " batch_size = 500000,\n", - ")->pd.DataFrame:\n", - " \"\"\"\n", - " Calculate precursor_mz inplace in the precursor_df\n", - " \n", - " Parameters\n", - " ----------\n", - " precursor_df : pd.DataFrame\n", - "\n", - " precursor_df with the 'charge' column\n", - "\n", - " Returns\n", - " -------\n", - " pd.DataFrame\n", - " \n", - " precursor_df with 'precursor_mz'\n", - " \"\"\"\n", - "\n", - " if 'nAA' not in precursor_df:\n", - " reset_precursor_df(precursor_df)\n", - " _calc_in_order = True\n", - " elif is_precursor_sorted(precursor_df):\n", - " _calc_in_order = True\n", - " else:\n", - " _calc_in_order = False\n", - " precursor_df['precursor_mz'] = 0.\n", - " _grouped = precursor_df.groupby('nAA')\n", - " precursor_mz_idx = precursor_df.columns.get_loc(\n", - " 'precursor_mz'\n", - " )\n", - " for nAA, big_df_group in _grouped:\n", - " for i in range(0, len(big_df_group), batch_size):\n", - " batch_end = i+batch_size\n", - " \n", - " df_group = big_df_group.iloc[i:batch_end,:]\n", - "\n", - " pep_mzs = calc_peptide_masses_for_same_len_seqs(\n", - " df_group.sequence.values.astype('U'),\n", - " df_group.mods.values,\n", - " df_group.mod_deltas.values if \n", - " 'mod_deltas' in df_group.columns else None\n", - " )/df_group.charge + MASS_PROTON\n", - " if _calc_in_order:\n", - " precursor_df.iloc[:,precursor_mz_idx].values[\n", - " df_group.index.values[0]:\n", - " df_group.index.values[-1]+1\n", - " ] = pep_mzs\n", - " else:\n", - " precursor_df.loc[\n", - " df_group.index, 'precursor_mz'\n", - " ] = pep_mzs\n", - " return precursor_df\n", - "\n", - "calc_precursor_mz = update_precursor_mz" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def get_mod_seq_hash(\n", - " sequence:str, mods:str, \n", - " mod_sites:str,\n", - " *, seed:int=0\n", - ")->np.int64:\n", - " \"\"\"Get hash code value for a peptide:\n", - " (sequence, mods, mod_sites)\n", - "\n", - " Parameters\n", - " ----------\n", - " sequence : str\n", - " \n", - " Amino acid sequence\n", - "\n", - " mods : str\n", - " \n", - " Modification names in AlphaBase format\n", - "\n", - " mod_sites : str\n", - " \n", - " Modification sites in AlphaBase format\n", - "\n", - " seed : int\n", - " \n", - " Seed for hashing.\n", - " Optional, by default 0\n", - "\n", - " Returns\n", - " -------\n", - " np.int64\n", - "\n", - " 64-bit hash code value\n", - " \"\"\"\n", - " return np.sum([\n", - " hash64(sequence, seed=seed)[0],\n", - " hash64(mods, seed=seed)[0],\n", - " hash64(mod_sites, seed=seed)[0],\n", - " ],dtype=np.int64) # use np.sum to prevent overflow\n", - "\n", - "def get_mod_seq_charge_hash(\n", - " sequence:str, mods:str, \n", - " mod_sites:str, charge:int,\n", - " *, seed=0\n", - "):\n", - " \"\"\"Get hash code value for a precursor:\n", - " (sequence, mods, mod_sites, charge)\n", - "\n", - " Parameters\n", - " ----------\n", - " sequence : str\n", - "\n", - " Amino acid sequence\n", - "\n", - " mods : str\n", - " \n", - " Modification names in AlphaBase format\n", - "\n", - " mod_sites : str\n", - " \n", - " Modification sites in AlphaBase format\n", - "\n", - " charge : int\n", - " \n", - " Precursor charge state\n", - "\n", - " seed : int\n", - " \n", - " Seed for hashing.\n", - " Optional, by default 0\n", - "\n", - " Returns\n", - " -------\n", - " np.int64\n", - " \n", - " 64-bit hash code value\n", - " \"\"\"\n", - " return np.sum([\n", - " get_mod_seq_hash(\n", - " sequence, mods, mod_sites, \n", - " seed=seed\n", - " ),\n", - " charge,\n", - " ],dtype=np.int64) # use np.sum to prevent overflow \n", - "\n", - "def hash_mod_seq_df(\n", - " precursor_df:pd.DataFrame,\n", - " *, seed=0\n", - "):\n", - " \"\"\" Internal function \"\"\"\n", - " hash_vals = precursor_df.sequence.apply(\n", - " lambda x: hash64(x, seed=seed)[0]\n", - " ).astype(np.int64).values\n", - " hash_vals += precursor_df.mods.apply(\n", - " lambda x: hash64(x, seed=seed)[0]\n", - " ).values\n", - " hash_vals += precursor_df.mod_sites.apply(\n", - " lambda x: hash64(x, seed=seed)[0]\n", - " ).values\n", - "\n", - " precursor_df[\n", - " \"mod_seq_hash\"\n", - " ] = hash_vals\n", - " return precursor_df\n", - "\n", - "def hash_mod_seq_charge_df(\n", - " precursor_df:pd.DataFrame,\n", - " *, seed=0\n", - "):\n", - " \"\"\" Internal function \"\"\"\n", - " if \"mod_seq_hash\" not in precursor_df.columns:\n", - " hash_mod_seq_df(precursor_df, seed=seed)\n", - " if \"charge\" not in precursor_df.columns:\n", - " raise ValueError(\n", - " \"DataFrame must contain 'charge' column\"\n", - " )\n", - " \n", - " precursor_df[\"mod_seq_charge_hash\"] = (\n", - " precursor_df[\"mod_seq_hash\"].values\n", - " + precursor_df[\"charge\"].values\n", - " )\n", - " return precursor_df\n", - "\n", - "def hash_precursor_df(\n", - " precursor_df:pd.DataFrame,\n", - " *, seed:int=0\n", - ")->pd.DataFrame:\n", - " \"\"\"Add columns 'mod_seq_hash' and 'mod_seq_charge_hash'\n", - " into precursor_df (inplace). \n", - " The 64-bit hash function is from mmh3 (mmh3.hash64).\n", - "\n", - " Parameters\n", - " ----------\n", - " precursor_df : pd.DataFrame\n", - " \n", - " precursor_df\n", - " \n", - " Seed : int\n", - " \n", - " Seed for mmh3.hash64.\n", - " Optional, by default 0\n", - "\n", - " Returns\n", - " -------\n", - " pd.DataFrame\n", - "\n", - " DataFrame with columns 'mod_seq_hash' and 'mod_seq_charge_hash'\n", - " \"\"\"\n", - " hash_mod_seq_df(precursor_df, seed=seed)\n", - "\n", - " if 'charge' in precursor_df.columns:\n", - " hash_mod_seq_charge_df(precursor_df, seed=seed)\n", - " return precursor_df" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def get_mod_seq_formula(seq:str, mods:str)->list:\n", - " \"\"\" \n", - " 'PEPTIDE','Acetyl@Any N-term' --> [('C',n), ('H',m), ...] \n", - " \"\"\"\n", - " formula = {}\n", - " for aa in seq:\n", - " for chem,n in AA_formula[aa].items():\n", - " if chem in formula:\n", - " formula[chem]+=n\n", - " else:\n", - " formula[chem]=n\n", - " if len(mods) > 0:\n", - " for mod in mods.split(';'):\n", - " for chem,n in MOD_formula[mod].items():\n", - " if chem in formula:\n", - " formula[chem]+=n\n", - " else:\n", - " formula[chem]=n\n", - " return list(formula.items())\n", - "\n", - "@numba.njit\n", - "def get_right_most_isotope_index(\n", - " intensities:np.ndarray, \n", - " apex_idx:int,\n", - " min_right_most_intensity:float,\n", - ")->int:\n", - " \"\"\"Get right-most isotope index\n", - "\n", - " Parameters\n", - " ----------\n", - " intensities : np.ndarray\n", - "\n", - " Isotope intensities\n", - "\n", - " apex_idx : int\n", - "\n", - " The index or position of apex peak\n", - "\n", - " min_right_most_intensity : float\n", - "\n", - " Minimal intensity to consider for right-most peak relative to apex\n", - "\n", - " Returns\n", - " -------\n", - " int\n", - "\n", - " Index or position of the right-most peak\n", - " \"\"\"\n", - "\n", - " apex_inten = intensities[apex_idx]\n", - " for i in range(len(intensities)-1,-1,-1):\n", - " if intensities[i] >= apex_inten*min_right_most_intensity:\n", - " return i\n", - " return apex_idx\n", - "\n", - "def get_mod_seq_isotope_distribution(\n", - " seq_mods:tuple, \n", - " isotope_dist:IsotopeDistribution,\n", - " min_right_most_intensity:float=0.2,\n", - ")->tuple:\n", - " \"\"\"Get isotope abundance distribution by IsotopeDistribution.\n", - " This function is designed for multiprocessing.\n", - "\n", - " Parameters\n", - " ----------\n", - " seq_mods : tuple\n", - " (sequence, mods)\n", - " \n", - " isotope_dist : IsotopeDistribution\n", - " See `IsotopeDistribution` in `alphabase.constants.isotope`\n", - "\n", - " min_right_most_intensity : float\n", - " The minimal intensity value of the right-most peak relative to apex peak. \n", - " Optional, by default 0.2\n", - "\n", - " Returns\n", - " -------\n", - " tuple\n", - " float - Abundance of mono+1 / mono\n", - " float - Abundance of apex / mono\n", - " int - Apex isotope position relative to mono, \n", - " i.e. apex index - mono index and\n", - " 0 refers to the position of mono itself\n", - " float - Abundance of right-most peak which has at least `min_right_most_intensity`\n", - " intensity relative to the apex peak\n", - " int - Right-most position relative to mono,\n", - " i.e. right-most index - mono index\n", - " \"\"\"\n", - " dist, mono = isotope_dist.calc_formula_distribution(\n", - " get_mod_seq_formula(*seq_mods)\n", - " )\n", - "\n", - " apex_idx = np.argmax(dist)\n", - "\n", - " # find right-most peak\n", - " right_most_idx = get_right_most_isotope_index(\n", - " dist, apex_idx, min_right_most_intensity\n", - " )\n", - "\n", - " return (\n", - " dist[mono+1]/dist[mono], \n", - " dist[apex_idx]/dist[mono], \n", - " apex_idx-mono,\n", - " dist[right_most_idx]/dist[mono],\n", - " right_most_idx-mono,\n", - " )\n", - "\n", - "def calc_precursor_isotope(\n", - " precursor_df:pd.DataFrame,\n", - " min_right_most_intensity:float=0.2,\n", - "):\n", - " \"\"\"Calculate isotope mz values and relative (to M0) intensity values for precursor_df inplace.\n", - "\n", - " Parameters\n", - " ----------\n", - " precursor_df : pd.DataFrame\n", - " precursor_df to calculate\n", - "\n", - " min_right_most_intensity : float\n", - " The minimal intensity value of the right-most peak relative to apex peak. \n", - " Optional, by default 0.2\n", - "\n", - " Returns\n", - " -------\n", - " pd.DataFrame\n", - " precursor_df with additional columns:\n", - " - isotope_m1_intensity\n", - " - isotope_m1_mz\n", - " - isotope_apex_intensity\n", - " - isotope_apex_mz\n", - " - isotope_apex_index\n", - " - isotope_right_most_intensity\n", - " - isotope_right_most_mz\n", - " - isotope_right_most_index\n", - " \"\"\"\n", - "\n", - " if \"precursor_mz\" not in precursor_df.columns:\n", - " update_precursor_mz(precursor_df)\n", - "\n", - " isotope_dist = IsotopeDistribution()\n", - "\n", - " (\n", - " precursor_df['isotope_m1_intensity'], \n", - " precursor_df['isotope_apex_intensity'],\n", - " precursor_df['isotope_apex_index'],\n", - " precursor_df['isotope_right_most_intensity'],\n", - " precursor_df['isotope_right_most_index'],\n", - " ) = zip(\n", - " *precursor_df[['sequence','mods']].apply(\n", - " get_mod_seq_isotope_distribution, \n", - " axis=1, isotope_dist=isotope_dist,\n", - " min_right_most_intensity=min_right_most_intensity,\n", - " )\n", - " )\n", - "\n", - " precursor_df['isotope_m1_mz'] = (\n", - " precursor_df.precursor_mz + \n", - " MASS_ISOTOPE/precursor_df.charge\n", - " )\n", - "\n", - " precursor_df['isotope_apex_mz'] = (\n", - " precursor_df.precursor_mz + \n", - " (\n", - " MASS_ISOTOPE\n", - " *precursor_df.isotope_apex_index\n", - " /precursor_df.charge\n", - " )\n", - " )\n", - " precursor_df['isotope_right_most_mz'] = (\n", - " precursor_df.precursor_mz + \n", - " (\n", - " MASS_ISOTOPE\n", - " *precursor_df.isotope_right_most_index\n", - " /precursor_df.charge\n", - " )\n", - " )\n", - "\n", - " return precursor_df\n", - "\n", - "def _batchify_df(df_group, mp_batch_size):\n", - " \"\"\"Internal funciton for multiprocessing\"\"\"\n", - " for _, df in df_group:\n", - " for i in range(0, len(df), mp_batch_size):\n", - " yield df.iloc[i:i+mp_batch_size,:]\n", - "\n", - "def _count_batchify_df(df_group, mp_batch_size):\n", - " \"\"\"Internal funciton for multiprocessing\"\"\"\n", - " count = 0\n", - " for _, df in df_group:\n", - " for _ in range(0, len(df), mp_batch_size):\n", - " count += 1\n", - " return count\n", - "\n", - "# `process_bar` should be replaced by more advanced tqdm wrappers created by Sander\n", - "# I will leave it to alphabase.utils\n", - "def calc_precursor_isotope_mp(\n", - " precursor_df:pd.DataFrame, \n", - " processes:int=8,\n", - " mp_batch_size:int=100000,\n", - " process_bar=None,\n", - " min_right_most_intensity:float=0.2,\n", - ")->pd.DataFrame:\n", - " \"\"\"`calc_precursor_isotope` is not that fast for large dataframes, \n", - " so here we use multiprocessing for faster isotope pattern calculation. \n", - " The speed is acceptable with multiprocessing (3.8 min for 21M precursors, 8 processes).\n", - "\n", - " Parameters\n", - " ----------\n", - " precursor_df : pd.DataFrame\n", - " Precursor_df to calculate\n", - " \n", - " processes : int\n", - " Process number. Optional, by default 8\n", - " \n", - " mp_batch_size : int\n", - " Multiprocessing batch size. Optional, by default 100000.\n", - " \n", - " process_bar : Callable\n", - " The tqdm-based callback function \n", - " to check multiprocessing. Defaults to None.\n", - "\n", - " min_right_most_intensity : float\n", - " The minimal intensity value of the right-most peak relative to apex peak. \n", - " Optional, by default 0.2\n", - "\n", - " Returns\n", - " -------\n", - " pd.DataFrame\n", - " precursor_df with additional columns:\n", - " - isotope_m1_intensity\n", - " - isotope_m1_mz\n", - " - isotope_apex_intensity\n", - " - isotope_apex_mz\n", - " - isotope_apex_index\n", - " - isotope_right_most_intensity\n", - " - isotope_right_most_mz\n", - " - isotope_right_most_index\n", - " \"\"\"\n", - " df_list = []\n", - " df_group = precursor_df.groupby('nAA')\n", - " with mp.Pool(processes) as p:\n", - " processing = p.imap(\n", - " partial(\n", - " calc_precursor_isotope,\n", - " min_right_most_intensity=min_right_most_intensity\n", - " ), _batchify_df(df_group, mp_batch_size)\n", - " )\n", - " if process_bar:\n", - " processing = process_bar(\n", - " processing, _count_batchify_df(\n", - " df_group, mp_batch_size\n", - " )\n", - " )\n", - " for df in processing:\n", - " df_list.append(df)\n", - " return pd.concat(df_list)" + "from alphabase.peptide.precursor import *" ] }, { @@ -648,11 +87,11 @@ " nAA\n", " charge\n", " precursor_mz\n", - " isotope_intensity_m1\n", + " isotope_m1_intensity\n", " isotope_apex_intensity\n", - " isotope_apex_index\n", + " isotope_apex_offset\n", " isotope_right_most_intensity\n", - " isotope_right_most_index\n", + " isotope_right_most_offset\n", " isotope_m1_mz\n", " isotope_apex_mz\n", " isotope_right_most_mz\n", @@ -738,23 +177,23 @@ "2 AGHCEWQMK \n", "3 AGHCEWQMK \n", "\n", - " mod_sites nAA charge precursor_mz isotope_intensity_m1 \\\n", + " mod_sites nAA charge precursor_mz isotope_m1_intensity \\\n", "0 0;4;8 14 2 873.869771 0.888952 \n", "1 0;4;8 14 2 873.869771 0.888952 \n", "2 9 2 545.233862 0.576623 \n", "3 9 2 545.233862 0.576623 \n", "\n", - " isotope_apex_intensity isotope_apex_index isotope_right_most_intensity \\\n", - "0 1.0 0 0.235889 \n", - "1 1.0 0 0.235889 \n", - "2 1.0 0 0.277542 \n", - "3 1.0 0 0.277542 \n", + " isotope_apex_intensity isotope_apex_offset isotope_right_most_intensity \\\n", + "0 1.0 0 0.235889 \n", + "1 1.0 0 0.235889 \n", + "2 1.0 0 0.277542 \n", + "3 1.0 0 0.277542 \n", "\n", - " isotope_right_most_index isotope_m1_mz isotope_apex_mz \\\n", - "0 3 874.371421 873.869771 \n", - "1 3 874.371421 873.869771 \n", - "2 2 545.735512 545.233862 \n", - "3 2 545.735512 545.233862 \n", + " isotope_right_most_offset isotope_m1_mz isotope_apex_mz \\\n", + "0 3 874.371421 873.869771 \n", + "1 3 874.371421 873.869771 \n", + "2 2 545.735512 545.233862 \n", + "3 2 545.735512 545.233862 \n", "\n", " isotope_right_most_mz \n", "0 875.374721 \n", @@ -780,8 +219,8 @@ ")<=1e-5\n", "assert abs(\n", " precursor_df.loc[1,'isotope_apex_mz']-precursor_df.loc[1,'precursor_mz']\n", - " -MASS_ISOTOPE/precursor_df.loc[1,'isotope_apex_index'] \n", - " if precursor_df.loc[1,'isotope_apex_index'] > 0 else 0\n", + " -MASS_ISOTOPE/precursor_df.loc[1,'isotope_apex_offset'] \n", + " if precursor_df.loc[1,'isotope_apex_offset'] > 0 else 0\n", ")<=1e-5\n", "precursor_df" ] diff --git a/nbdev_nbs/protein/fasta.ipynb b/nbdev_nbs/protein/fasta.ipynb index 418ba921..d513c1fe 100644 --- a/nbdev_nbs/protein/fasta.ipynb +++ b/nbdev_nbs/protein/fasta.ipynb @@ -6,7 +6,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| default_exp protein.fasta" + "#---#| default_exp protein.fasta" ] }, { @@ -22,109 +22,8 @@ "metadata": {}, "outputs": [], "source": [ - "#| export\n", - "\n", - "import regex as re\n", - "import numpy as np\n", - "import pandas as pd\n", - "import numba\n", - "import os\n", - "import itertools\n", - "import copy\n", - "\n", - "from Bio import SeqIO\n", - "from typing import Union\n", - "\n", - "from alphabase.yaml_utils import load_yaml\n", - "from alphabase.io.hdf import HDF_File\n", - "from alphabase.utils import explode_multiple_columns\n", - "\n", - "from alphabase.constants._const import CONST_FILE_FOLDER\n", - "\n", - "from alphabase.spectral_library.library_base import SpecLibBase" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def get_uniprot_gene_name(description:str):\n", - " idx = description.find(' GN=')\n", - " if idx == -1: return ''\n", - " else: idx += 4\n", - " return description[idx:description.find(' ', idx)]\n", - "\n", - "def read_fasta_file(fasta_filename:str=\"\"):\n", - " \"\"\"\n", - " Read a FASTA file line by line\n", - "\n", - " Parameters\n", - " ----------\n", - " fasta_filename : str\n", - " fasta.\n", - " \n", - " Yields\n", - " ------\n", - " dict \n", - " protein information, \n", - " {protein_id:str, full_name:str, gene_name:str, description:str, sequence:str}\n", - " \"\"\"\n", - " with open(fasta_filename, \"rt\") as handle:\n", - " iterator = SeqIO.parse(handle, \"fasta\")\n", - " while iterator:\n", - " try:\n", - " record = next(iterator)\n", - " parts = record.id.split(\"|\") # pipe char\n", - " if len(parts) > 1:\n", - " id = parts[1]\n", - " else:\n", - " id = record.name\n", - " sequence = str(record.seq)\n", - " entry = {\n", - " \"protein_id\": id,\n", - " \"full_name\": record.name,\n", - " \"gene_name\": get_uniprot_gene_name(record.description),\n", - " \"description\": record.description,\n", - " \"sequence\": sequence,\n", - " }\n", - "\n", - " yield entry\n", - " except StopIteration:\n", - " break\n", - "\n", - "def load_all_proteins(fasta_file_list:list):\n", - " protein_dict = {}\n", - " for fasta in fasta_file_list:\n", - " for protein in read_fasta_file(fasta):\n", - " protein_dict[protein['protein_id']] = protein\n", - " return protein_dict\n", - "\n", - "def concat_proteins(protein_dict:dict, sep='$')->str:\n", - " \"\"\"Concatenate all protein sequences into a single sequence, \n", - " seperated by `sep ($ by default)`.\n", - "\n", - " Parameters\n", - " ----------\n", - " protein_dict : dict\n", - " protein_dict by read_fasta_file()\n", - "\n", - " Returns\n", - " -------\n", - " str\n", - " concatenated sequence seperated by `sep`.\n", - " \"\"\"\n", - " seq_list = ['']\n", - " seq_count = 1\n", - " for key in protein_dict:\n", - " protein_dict[key]['offset'] = seq_count\n", - " seq_list.append(protein_dict[key]['sequence'])\n", - " seq_count += protein_dict[key]['sequence']+1\n", - " seq_list.append('')\n", - " return '$'.join(seq_list)" + "from alphabase.protein.fasta import *\n", + "import alphabase.protein.fasta as fasta" ] }, { @@ -143,168 +42,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| export\n", - "\n", - "protease_dict = load_yaml(\n", - " os.path.join(\n", - " CONST_FILE_FOLDER, \n", - " 'protease.yaml'\n", - " )\n", - ")\n", - "\n", - "@numba.njit\n", - "def cleave_sequence_with_cut_pos(\n", - " sequence:str,\n", - " cut_pos:np.ndarray,\n", - " n_missed_cleavages:int=2,\n", - " pep_length_min:int=6,\n", - " pep_length_max:int=45,\n", - ")->tuple:\n", - " \"\"\"\n", - " Cleave a sequence with cut postions (cut_pos). \n", - " Filters to have a minimum and maximum length.\n", - "\n", - " Parameters\n", - " ----------\n", - " sequence : str\n", - " protein sequence\n", - "\n", - " cut_pos : np.ndarray\n", - " cut postions determined by a given protease.\n", - "\n", - " n_missed_cleavages : int\n", - " the number of max missed cleavages.\n", - "\n", - " pep_length_min : int\n", - " min peptide length.\n", - "\n", - " pep_length_max :int\n", - " max peptide length.\n", - "\n", - " Returns\n", - " -------\n", - " tuple:\n", - " List[str]. Cleaved peptide sequences with missed cleavages.\n", - "\n", - " List[int]. Number of miss cleavage of each peptide.\n", - "\n", - " List[bool]. If N-term peptide\n", - "\n", - " List[bool]. If C-term pepetide\n", - " \"\"\"\n", - " seq_list = []\n", - " miss_list = []\n", - " nterm_list = []\n", - " cterm_list = []\n", - " for i,start_pos in enumerate(cut_pos):\n", - " for n_miss,end_pos in enumerate(\n", - " cut_pos[i+1:i+2+n_missed_cleavages]\n", - " ):\n", - " if end_pos > start_pos + pep_length_max:\n", - " break\n", - " elif end_pos < start_pos + pep_length_min:\n", - " continue\n", - " else:\n", - " seq_list.append(sequence[start_pos:end_pos])\n", - " miss_list.append(n_miss)\n", - " if start_pos == 0:\n", - " nterm_list.append(True)\n", - " else:\n", - " nterm_list.append(False)\n", - " if end_pos == len(sequence):\n", - " cterm_list.append(True)\n", - " else:\n", - " cterm_list.append(False)\n", - " return seq_list, miss_list, nterm_list, cterm_list\n", - "\n", - "class Digest(object):\n", - " def __init__(self,\n", - " protease:str='trypsin/P',\n", - " max_missed_cleavages:int=2,\n", - " peptide_length_min:int=6,\n", - " peptide_length_max:int=45,\n", - " ):\n", - " \"\"\"Digest a protein sequence\n", - "\n", - " Parameters\n", - " ----------\n", - " protease : str, optional\n", - " protease name, could be pre-defined name defined in `protease_dict`\n", - " or a regular expression. By default 'trypsin/P'\n", - "\n", - " max_missed_cleavages : int, optional\n", - " Max number of misses cleavage sites.\n", - " By default 2\n", - "\n", - " peptide_length_min : int, optional\n", - " Minimal cleaved peptide length, by default 6\n", - " \n", - " peptide_length_max : int, optional\n", - " Maximal cleaved peptide length, by default 45\n", - " \"\"\"\n", - "\n", - " self.n_miss_cleave = max_missed_cleavages\n", - " self.peptide_length_min = peptide_length_min\n", - " self.peptide_length_max = peptide_length_max\n", - " if protease.lower() in protease_dict:\n", - " self.regex_pattern = re.compile(\n", - " protease_dict[protease.lower()]\n", - " )\n", - " else:\n", - " self.regex_pattern = re.compile(\n", - " protease\n", - " )\n", - "\n", - " def cleave_sequence(self,\n", - " sequence:str,\n", - " )->tuple:\n", - " \"\"\"\n", - " Cleave a sequence.\n", - "\n", - " Parameters\n", - " ----------\n", - " sequence : str\n", - " the given (protein) sequence.\n", - "\n", - " Returns\n", - " -------\n", - " tuple[list]\n", - " list[str]: cleaved peptide sequences with missed cleavages\n", - " list[int]: miss cleavage list\n", - " list[bool]: is protein N-term\n", - " list[bool]: is protein C-term\n", - " \"\"\"\n", - "\n", - " cut_pos = [0]\n", - " cut_pos.extend([\n", - " m.start()+1 for m in \n", - " self.regex_pattern.finditer(sequence)\n", - " ])\n", - " cut_pos.append(len(sequence))\n", - " cut_pos = np.array(cut_pos, dtype=np.int64)\n", - "\n", - " (\n", - " seq_list, miss_list, nterm_list, cterm_list\n", - " ) = cleave_sequence_with_cut_pos(\n", - " sequence, cut_pos, \n", - " self.n_miss_cleave,\n", - " self.peptide_length_min,\n", - " self.peptide_length_max,\n", - " )\n", - " # Consider M loss at protein N-term\n", - " if sequence.startswith('M'):\n", - " for seq,miss,cterm in zip(\n", - " seq_list,miss_list,cterm_list\n", - " ):\n", - " if (\n", - " sequence.startswith(seq) \n", - " and len(seq)>self.peptide_length_min\n", - " ):\n", - " seq_list.append(seq[1:])\n", - " miss_list.append(miss)\n", - " nterm_list.append(True)\n", - " cterm_list.append(cterm)\n", - " return seq_list, miss_list, nterm_list, cterm_list" + "assert 'trypsin_not_p' in protease_dict, 'trypsin_not_p not in protease_dict, why?'" ] }, { @@ -314,7 +52,7 @@ "outputs": [], "source": [ "#| hide\n", - "p = re.compile(protease_dict['trypsin'])\n", + "p = re.compile(protease_dict['trypsin_not_p'])\n", "\n", "idx = '0123456789012345678901234567890123456789012345'\n", "seq = 'ABDNGKENGLANGIXHGRKTNGLANGKVHNAKHNARKANGKPFAAT'\n", @@ -322,65 +60,6 @@ "assert np.all(cut_pos==np.array([6, 18, 19, 27, 32, 36, 37]))" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| hide\n", - "from nbdev.showdoc import show_doc" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L216){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### Digest.cleave_sequence\n", - "\n", - "> Digest.cleave_sequence (sequence:str)\n", - "\n", - "Cleave a sequence.\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| sequence | str | the given (protein) sequence. |\n", - "| **Returns** | **tuple** | **list[str]: cleaved peptide sequences with missed cleavages
list[int]: miss cleavage list
list[bool]: is protein N-term
list[bool]: is protein C-term** |" - ], - "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L216){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### Digest.cleave_sequence\n", - "\n", - "> Digest.cleave_sequence (sequence:str)\n", - "\n", - "Cleave a sequence.\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| sequence | str | the given (protein) sequence. |\n", - "| **Returns** | **tuple** | **list[str]: cleaved peptide sequences with missed cleavages
list[int]: miss cleavage list
list[bool]: is protein N-term
list[bool]: is protein C-term** |" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "show_doc(Digest.cleave_sequence)" - ] - }, { "cell_type": "code", "execution_count": null, @@ -399,30 +78,6 @@ "assert len(T_end_seqs) == len([_ for _ in cterm_list if _])" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def get_fix_mods(\n", - " sequence:str,\n", - " fix_mod_aas:str,\n", - " fix_mod_dict:dict\n", - ")->tuple:\n", - " \"\"\"\n", - " Generate fix modifications for the sequence\n", - " \"\"\"\n", - " mods = []\n", - " mod_sites = []\n", - " for i,aa in enumerate(sequence):\n", - " if aa in fix_mod_aas:\n", - " mod_sites.append(i+1)\n", - " mods.append(fix_mod_dict[aa])\n", - " return ';'.join(mods), ';'.join(str(i) for i in mod_sites)" - ] - }, { "cell_type": "code", "execution_count": null, @@ -449,81 +104,6 @@ "get_fix_mods(seq, 'C', _fix_mod_dict)" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def get_candidate_sites(\n", - " sequence:str, target_mod_aas:str\n", - ")->list:\n", - " \"\"\"get candidate modification sites\n", - "\n", - " Parameters\n", - " ----------\n", - " sequence : str\n", - " peptide sequence\n", - "\n", - " target_mod_aas : str\n", - " AAs that may have modifications\n", - "\n", - " Returns\n", - " -------\n", - " list\n", - " candiadte mod sites in alphabase format (0: N-term, -1: C-term, 1-n:others)\n", - " \"\"\"\n", - " candidate_sites = []\n", - " for i,aa in enumerate(sequence):\n", - " if aa in target_mod_aas:\n", - " candidate_sites.append(i+1) #alphabase mod sites\n", - " return candidate_sites\n", - "\n", - "def get_var_mod_sites(\n", - " sequence:str,\n", - " target_mod_aas:str,\n", - " max_var_mod: int,\n", - " max_combs: int,\n", - ")->list:\n", - " \"\"\"get all combinations of variable modification sites\n", - "\n", - " Parameters\n", - " ----------\n", - " sequence : str\n", - " peptide sequence\n", - "\n", - " target_mod_aas : str\n", - " AAs that may have modifications\n", - "\n", - " max_var_mod : int\n", - " max number of mods in a sequence\n", - "\n", - " max_combs : int\n", - " max number of combinations for a sequence\n", - "\n", - " Returns\n", - " -------\n", - " list\n", - " list of combinations (tuple) of modification sites \n", - " \"\"\"\n", - " candidate_sites = get_candidate_sites(\n", - " sequence, target_mod_aas\n", - " )\n", - " mod_sites = [(s,) for s in candidate_sites]\n", - " for n_var_mod in range(2, max_var_mod+1):\n", - " if len(mod_sites)>=max_combs: break\n", - " mod_sites.extend(\n", - " itertools.islice(\n", - " itertools.combinations(\n", - " candidate_sites, n_var_mod\n", - " ),\n", - " max_combs-len(mod_sites)\n", - " )\n", - " )\n", - " return mod_sites" - ] - }, { "cell_type": "code", "execution_count": null, @@ -548,1529 +128,10 @@ " (5, 7),\n", " (6, 7),\n", " (2, 4, 5),\n", - " (2, 4, 6),\n", - " (2, 4, 7),\n", - " (2, 5, 6),\n", - " (2, 5, 7)]" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "seq = 'AMCMSTYK'\n", - "candidate_sites = get_candidate_sites(seq, 'MSTY')\n", - "assert np.all(np.array(candidate_sites)==np.array([2,4,5,6,7]))\n", - "get_var_mod_sites(seq, 'MSTY', 3, 20)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def get_var_mods_per_sites_multi_mods_on_aa(\n", - " sequence:str,\n", - " mod_sites:tuple,\n", - " var_mod_dict:dict\n", - ")->list:\n", - " \"\"\"\n", - " Used only when the var mod list contains \n", - " more than one mods on the same AA, for example:\n", - " Mod1@A, Mod2@A ...\n", - " \"\"\"\n", - " mods_str_list = ['']\n", - " for i,site in enumerate(mod_sites):\n", - " if len(var_mod_dict[sequence[site-1]]) == 1:\n", - " for i in range(len(mods_str_list)):\n", - " mods_str_list[i] += var_mod_dict[sequence[site-1]][0]+';'\n", - " else:\n", - " _new_list = []\n", - " for mod in var_mod_dict[sequence[site-1]]:\n", - " _lst = copy.deepcopy(mods_str_list)\n", - " for i in range(len(_lst)):\n", - " _lst[i] += mod+';'\n", - " _new_list.extend(_lst)\n", - " mods_str_list = _new_list\n", - " return [mod[:-1] for mod in mods_str_list]\n", - "\n", - "def get_var_mods_per_sites_single_mod_on_aa(\n", - " sequence:str,\n", - " mod_sites:tuple,\n", - " var_mod_dict:dict\n", - ")->list:\n", - " \"\"\"\n", - " Used when the var mod list contains \n", - " only one mods on the each AA, for example:\n", - " Mod1@A, Mod2@D ...\n", - " \"\"\"\n", - " mod_str = ''\n", - " for site in mod_sites:\n", - " mod_str += var_mod_dict[sequence[site-1]]+';'\n", - " return [mod_str[:-1]]\n", - "\n", - "get_var_mods_per_sites = get_var_mods_per_sites_single_mod_on_aa\n", - "\n", - "def get_var_mods(\n", - " sequence:str,\n", - " var_mod_aas:str,\n", - " mod_dict:dict,\n", - " max_var_mod:int,\n", - " max_combs:int,\n", - " keep_unmodified:bool=False,\n", - ")->tuple:\n", - " \"\"\"\n", - " Generate all modification combinations and associated sites\n", - " for the sequence.\n", - " \"\"\"\n", - " mod_sites_list = get_var_mod_sites(\n", - " sequence, var_mod_aas, \n", - " max_var_mod, max_combs\n", - " )\n", - " ret_mods = []\n", - " ret_sites_list = []\n", - " for mod_sites in mod_sites_list:\n", - " _mods = get_var_mods_per_sites(\n", - " sequence,mod_sites,mod_dict\n", - " )\n", - " mod_sites_str = ';'.join([str(i) for i in mod_sites])\n", - " ret_mods.extend(_mods)\n", - " ret_sites_list.extend([mod_sites_str]*len(_mods))\n", - " if keep_unmodified:\n", - " ret_mods.append('')\n", - " ret_sites_list.append('')\n", - " return ret_mods, ret_sites_list" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(['mod@M',\n", - " 'mod@M',\n", - " 'mod@S',\n", - " 'modX@S',\n", - " 'mod@T',\n", - " 'mod@Y',\n", - " 'mod@M;mod@M',\n", - " 'mod@M;mod@S',\n", - " 'mod@M;modX@S',\n", - " 'mod@M;mod@T',\n", - " 'mod@M;mod@Y',\n", - " 'mod@M;mod@S',\n", - " 'mod@M;modX@S',\n", - " 'mod@M;mod@T',\n", - " 'mod@M;mod@Y',\n", - " 'mod@S;mod@T',\n", - " 'modX@S;mod@T',\n", - " 'mod@S;mod@Y',\n", - " 'modX@S;mod@Y',\n", - " 'mod@T;mod@Y',\n", - " 'mod@M;mod@M;mod@S',\n", - " 'mod@M;mod@M;modX@S'],\n", - " ['2',\n", - " '4',\n", - " '5',\n", - " '5',\n", - " '6',\n", - " '7',\n", - " '2;4',\n", - " '2;5',\n", - " '2;5',\n", - " '2;6',\n", - " '2;7',\n", - " '4;5',\n", - " '4;5',\n", - " '4;6',\n", - " '4;7',\n", - " '5;6',\n", - " '5;6',\n", - " '5;7',\n", - " '5;7',\n", - " '6;7',\n", - " '2;4;5',\n", - " '2;4;5'])" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "#| hide\n", - "get_var_mods_per_sites = get_var_mods_per_sites_multi_mods_on_aa\n", - "seq = 'AMCMSTYK'\n", - "candidate_sites = get_candidate_sites(seq, 'MSTY')\n", - "mod_sites_list = get_var_mod_sites(seq, 'MSTY', 3, 20)\n", - "_mod_dict = {\n", - " 'M':['mod@M'],\n", - " 'S':['mod@S','modX@S'],\n", - " 'T':['mod@T'],\n", - " 'Y':['mod@Y'],\n", - "}\n", - "_mods, _sites = get_var_mods(seq, 'MSTY', _mod_dict, 3, 16)\n", - "\n", - "assert 'mod@M;mod@M;mod@S' in _mods\n", - "assert _sites[_mods.index('mod@M;mod@M;mod@S')] == '2;4;5'\n", - "assert 'mod@M;mod@M;modX@S' in _mods\n", - "assert _sites[_mods.index('mod@M;mod@M;modX@S')] == '2;4;5'\n", - "assert 'mod@M;mod@S' in _mods\n", - "assert 'mod@M;modX@S' in _mods\n", - "get_var_mods(seq, 'MSTY', _mod_dict, 3, 16)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(['mod@M',\n", - " 'mod@M',\n", - " 'mod@S',\n", - " 'mod@T',\n", - " 'mod@Y',\n", - " 'mod@M;mod@M',\n", - " 'mod@M;mod@S',\n", - " 'mod@M;mod@T',\n", - " 'mod@M;mod@Y',\n", - " 'mod@M;mod@S',\n", - " 'mod@M;mod@T',\n", - " 'mod@M;mod@Y',\n", - " 'mod@S;mod@T',\n", - " 'mod@S;mod@Y',\n", - " 'mod@T;mod@Y',\n", - " 'mod@M;mod@M;mod@S'],\n", - " ['2',\n", - " '4',\n", - " '5',\n", - " '6',\n", - " '7',\n", - " '2;4',\n", - " '2;5',\n", - " '2;6',\n", - " '2;7',\n", - " '4;5',\n", - " '4;6',\n", - " '4;7',\n", - " '5;6',\n", - " '5;7',\n", - " '6;7',\n", - " '2;4;5'])" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "#| hide\n", - "get_var_mods_per_sites = get_var_mods_per_sites_single_mod_on_aa\n", - "seq = 'AMCMSTYK'\n", - "candidate_sites = get_candidate_sites(seq, 'MSTY')\n", - "mod_sites_list = get_var_mod_sites(seq, 'MSTY', 3, 20)\n", - "_mod_dict = {\n", - " 'M':'mod@M',\n", - " 'S':'mod@S',\n", - " 'T':'mod@T',\n", - " 'Y':'mod@Y',\n", - "}\n", - "_mods, _sites = get_var_mods(seq, 'MSTY', _mod_dict, 3, 16)\n", - "assert len(_mods) == len(_sites) == 16\n", - "assert _sites[_mods.index('mod@M;mod@M;mod@S')] == '2;4;5'\n", - "get_var_mods(seq, 'MSTY', _mod_dict, 3, 16)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def parse_term_mod(term_mod_name:str):\n", - " _mod, term = term_mod_name.split('@')\n", - " if '^' in term:\n", - " return tuple(term.split('^'))\n", - " else:\n", - " return '', term" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| hide\n", - "assert parse_term_mod('Acetyl@Protein N-term') == ('', 'Protein N-term')\n", - "assert parse_term_mod('Gln->pyro-Glu@Q^Any N-term') == ('Q', 'Any N-term')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def add_single_peptide_labeling(\n", - " seq:str,\n", - " mods:str,\n", - " mod_sites:str, \n", - " label_aas:str, \n", - " label_mod_dict:dict, \n", - " nterm_label_mod:str, \n", - " cterm_label_mod:str\n", - "):\n", - " add_nterm_label = True if nterm_label_mod else False\n", - " add_cterm_label = True if cterm_label_mod else False\n", - " if mod_sites:\n", - " _sites = mod_sites.split(';')\n", - " if '0' in _sites: add_nterm_label = False\n", - " if '-1' in _sites: add_cterm_label = False\n", - " mod_list = [mods]\n", - " mod_site_list = [mod_sites]\n", - " else:\n", - " mod_list = []\n", - " mod_site_list = []\n", - " if add_nterm_label:\n", - " mod_list.append(nterm_label_mod)\n", - " mod_site_list.append('0')\n", - " if add_cterm_label:\n", - " mod_list.append(cterm_label_mod)\n", - " mod_site_list.append('-1')\n", - " aa_labels, aa_label_sites = get_fix_mods(seq, label_aas, label_mod_dict)\n", - " if aa_labels:\n", - " mod_list.append(aa_labels)\n", - " mod_site_list.append(aa_label_sites)\n", - " return ';'.join(mod_list), ';'.join(mod_site_list)\n", - "\n", - "def parse_labels(labels:list):\n", - " label_aas = ''\n", - " label_mod_dict = {}\n", - " nterm_label_mod = ''\n", - " cterm_label_mod = ''\n", - " for label in labels:\n", - " _, aa = label.split('@')\n", - " if len(aa) == 1:\n", - " label_aas += aa\n", - " label_mod_dict[aa] = label\n", - " elif aa == 'Any N-term':\n", - " nterm_label_mod = label\n", - " elif aa == 'Any C-term':\n", - " cterm_label_mod = label\n", - " return label_aas, label_mod_dict, nterm_label_mod, cterm_label_mod\n", - " \n", - "def create_labeling_peptide_df(peptide_df:pd.DataFrame, labels:list):\n", - " df = peptide_df.copy()\n", - " (\n", - " label_aas, label_mod_dict, \n", - " nterm_label_mod, cterm_label_mod\n", - " ) = parse_labels(labels)\n", - "\n", - " (\n", - " df['mods'],\n", - " df['mod_sites']\n", - " ) = zip(*df[\n", - " ['sequence','mods','mod_sites']\n", - " ].apply(lambda x:\n", - " add_single_peptide_labeling(\n", - " *x, label_aas, label_mod_dict, \n", - " nterm_label_mod, cterm_label_mod\n", - " ), axis=1,\n", - " ))\n", - "\n", - " return df" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| hide\n", - "labels = ['label@Any N-term','label@K']\n", - "(\n", - " label_aas, label_mod_dict, \n", - " nterm_label_mod, cterm_label_mod\n", - ") = parse_labels(labels)\n", - "assert add_single_peptide_labeling(\n", - " 'ABCK','','', label_aas, label_mod_dict, \n", - " nterm_label_mod, cterm_label_mod\n", - ") == ('label@Any N-term;label@K', '0;4')\n", - "assert add_single_peptide_labeling(\n", - " 'ABCK','Mod@Any N-term','0', label_aas, label_mod_dict, \n", - " nterm_label_mod, cterm_label_mod\n", - ") == ('Mod@Any N-term;label@K', '0;4')\n", - "assert add_single_peptide_labeling(\n", - " 'KBCK','','', label_aas, label_mod_dict, \n", - " nterm_label_mod, cterm_label_mod\n", - ") == ('label@Any N-term;label@K;label@K', '0;1;4')\n", - "assert add_single_peptide_labeling(\n", - " 'KBCK','Mod@Any N-term','0', label_aas, label_mod_dict, \n", - " nterm_label_mod, cterm_label_mod\n", - ") == ('Mod@Any N-term;label@K;label@K', '0;1;4')\n", - "pep_df = pd.DataFrame({\n", - " 'sequence': ['ABCD','ABCK','KABK','EFGK'],\n", - " 'mods': ['']*3+['Mod@Any N-term'],\n", - " 'mod_sites': ['']*3+['0']\n", - "})\n", - "df = create_labeling_peptide_df(pep_df, labels)\n", - "assert np.all(df.mods.values!=pep_df.mods.values)\n", - "assert df[df.sequence=='ABCD'].mods.values[0] == 'label@Any N-term'\n", - "assert df[df.sequence=='ABCD'].mod_sites.values[0] == '0'\n", - "assert df[df.sequence=='ABCK'].mods.values[0] == 'label@Any N-term;label@K'\n", - "assert df[df.sequence=='ABCK'].mod_sites.values[0] == '0;4'\n", - "assert df[df.sequence=='KABK'].mods.values[0] == 'label@Any N-term;label@K;label@K'\n", - "assert df[df.sequence=='KABK'].mod_sites.values[0] == '0;1;4'\n", - "assert df[df.sequence=='EFGK'].mods.values[0] == 'Mod@Any N-term;label@K'\n", - "assert df[df.sequence=='EFGK'].mod_sites.values[0] == '0;4'\n", - "df = create_labeling_peptide_df(pep_df, [])\n", - "assert np.all(df.mods.values==pep_df.mods.values)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def protein_idxes_to_names(protein_idxes:str, protein_names:list):\n", - " if len(protein_idxes) == 0: return ''\n", - " proteins = [protein_names[int(i)] for i in protein_idxes.split(';')]\n", - " proteins = [protein for protein in proteins if protein]\n", - " return ';'.join(proteins)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| hide\n", - "assert protein_idxes_to_names('0;1', ['A','','B'])=='A'\n", - "assert protein_idxes_to_names('0;1', ['A','C','B'])=='A;C'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def append_regular_modifications(df:pd.DataFrame, \n", - " var_mods = ['Phospho@S','Phospho@T','Phospho@Y'], \n", - " max_mod_num=1, max_combs=100,\n", - " keep_unmodified=True,\n", - " cannot_modify_pep_nterm_aa:bool=False,\n", - " cannot_modify_pep_cterm_aa:bool=False,\n", - ")->pd.DataFrame:\n", - " \"\"\"\n", - " Append regular (not N/C-term) variable modifications to the \n", - " exsiting modifications of each sequence in `df`.\n", - "\n", - " Parameters\n", - " ----------\n", - " df : pd.DataFrame\n", - " Precursor dataframe\n", - " \n", - " var_mods : list, optional\n", - " Considered varialbe modification list. \n", - " Defaults to ['Phospho@S','Phospho@T','Phospho@Y'].\n", - "\n", - " max_mod_num : int, optional\n", - " Maximal modification number for \n", - " each sequence of the `var_mods`. Defaults to 1.\n", - "\n", - " max_combs : int, optional\n", - " One sequence is only allowed to explode \n", - " to `max_combs` number of modified peptides. Defaults to 100.\n", - "\n", - " keep_unmodified : bool, optional\n", - " If unmodified (only refered to `var_mods`)\n", - " peptides are also remained in the returned dataframe. Defaults to True.\n", - "\n", - " cannot_modify_pep_nterm_aa : bool, optional\n", - " Similar to `cannot_modify_pep_cterm_aa`, by default False\n", - "\n", - " cannot_modify_pep_cterm_aa : bool, optional\n", - " If the modified AA is at C-term, then the modification cannot modified it.\n", - " For example GlyGly@K, for a peptide `ACDKEFGK`, if GlyGly is at the C-term, \n", - " trypsin cannot cleave the C-term K, hence there will be no such a modified peptide ACDKEFGK(GlyGly).\n", - " by default False\n", - "\n", - " Returns\n", - " -------\n", - " pd.DataFrame\n", - " The precursor_df with new modification added.\n", - " \"\"\"\n", - "\n", - " if cannot_modify_pep_nterm_aa:\n", - " df['sequence'] = df['sequence'].apply(\n", - " lambda seq: seq[0].lower()+seq[1:]\n", - " )\n", - " \n", - " if cannot_modify_pep_cterm_aa:\n", - " df['sequence'] = df['sequence'].apply(\n", - " lambda seq: seq[:-1]+seq[-1].lower()\n", - " )\n", - "\n", - " mod_dict = dict([(mod[-1],mod) for mod in var_mods])\n", - " var_mod_aas = ''.join(mod_dict.keys())\n", - " \n", - " (\n", - " df['mods_app'],\n", - " df['mod_sites_app']\n", - " ) = zip(*df.sequence.apply(get_var_mods, \n", - " var_mod_aas=var_mod_aas, mod_dict=mod_dict, \n", - " max_var_mod=max_mod_num, max_combs=max_combs,\n", - " keep_unmodified=keep_unmodified\n", - " )\n", - " )\n", - "\n", - " if cannot_modify_pep_nterm_aa:\n", - " df['sequence'] = df['sequence'].apply(\n", - " lambda seq: seq[0].upper()+seq[1:]\n", - " )\n", - " \n", - " if cannot_modify_pep_cterm_aa:\n", - " df['sequence'] = df['sequence'].apply(\n", - " lambda seq: seq[:-1]+seq[-1].upper()\n", - " )\n", - " \n", - " if keep_unmodified:\n", - " df = df.explode(['mods_app','mod_sites_app'])\n", - " df.fillna('', inplace=True)\n", - " else:\n", - " df.drop(df[df.mods_app.apply(lambda x: len(x)==0)].index, inplace=True)\n", - " df = df.explode(['mods_app','mod_sites_app'])\n", - " df['mods'] = df[['mods','mods_app']].apply(\n", - " lambda x: ';'.join(i for i in x if i), axis=1\n", - " )\n", - " df['mod_sites'] = df[['mod_sites','mod_sites_app']].apply(\n", - " lambda x: ';'.join(i for i in x if i), axis=1\n", - " )\n", - " df.drop(columns=['mods_app', 'mod_sites_app'], inplace=True)\n", - " df.reset_index(drop=True, inplace=True)\n", - " return df" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "class FastaLib(SpecLibBase):\n", - " def __init__(self,\n", - " charged_frag_types:list = [\n", - " 'b_z1','b_z2','y_z1', 'y_z2'\n", - " ],\n", - " protease:str = 'trypsin/P',\n", - " max_missed_cleavages:int = 2,\n", - " peptide_length_min:int = 7,\n", - " peptide_length_max:int = 35,\n", - " precursor_charge_min:int = 2,\n", - " precursor_charge_max:int = 4,\n", - " precursor_mz_min:float = 200.0, \n", - " precursor_mz_max:float = 2000.0,\n", - " var_mods:list = ['Acetyl@Protein N-term','Oxidation@M'],\n", - " max_var_mod_num:int = 2,\n", - " fix_mods:list = ['Carbamidomethyl@C'],\n", - " decoy: str = None, # or pseudo_reverse or diann\n", - " I_to_L=False,\n", - " ):\n", - " \"\"\"Class to process fasta files and generate libraries, including:\n", - " - Digest protein sequences\n", - " - Add fixed, variable or labeling modifications to the peptide sequences\n", - " - Add charge states\n", - " - Append decoy peptides\n", - " - Save libraries into hdf file\n", - "\n", - " Parameters\n", - " ----------\n", - " charged_frag_types : list, optional\n", - " Fragment types with charge, \n", - " by default [ 'b_z1','b_z2','y_z1', 'y_z2' ]\n", - "\n", - " protease : str, optional\n", - " Could be pre-defined protease name defined in `protease_dict`,\n", - " or a regular expression. \n", - " By default 'trypsin/P'\n", - "\n", - " max_missed_cleavages : int, optional\n", - " Maximal missed cleavages, by default 2\n", - " \n", - " peptide_length_min : int, optional\n", - " Minimal cleaved peptide length, by default 7\n", - "\n", - " peptide_length_max : int, optional\n", - " Maximal cleaved peptide length, by default 35\n", - "\n", - " precursor_charge_min : int, optional\n", - " Minimal precursor charge, by default 2\n", - "\n", - " precursor_charge_max : int, optional\n", - " Maximal precursor charge, by default 4\n", - "\n", - " precursor_mz_min : float, optional\n", - " Minimal precursor mz, by default 200.0\n", - "\n", - " precursor_mz_max : float, optional\n", - " Maximal precursor mz, by default 2000.0\n", - "\n", - " var_mods : list, optional\n", - " list of variable modifications, \n", - " by default ['Acetyl@Protein N-term','Oxidation@M']\n", - "\n", - " max_var_mod_num : int, optional\n", - " Maximal number of variable modifications on a peptide sequence, \n", - " by default 2\n", - "\n", - " fix_mods : list, optional\n", - " list of fixed modifications, by default ['Carbamidomethyl@C']\n", - "\n", - " decoy : str, optional\n", - " Decoy type, see `alphabase.spectral_library.decoy_library`,\n", - " by default None\n", - "\n", - " Attributes\n", - " ----------\n", - " precursor_df : pd.DataFrame\n", - " The main peptide/precursor DataFrame containing peptide sequences, modifications, ...\n", - " \n", - " protein_df : pd.DataFrame\n", - " It contains protein sequences, gene names, protein ids ...\n", - "\n", - " fragment_mz_df : pd.DataFrame\n", - " Fragment mz DataFrame\n", - "\n", - " fragment_intensity_df : pd.DataFrame\n", - " Fragment intensity DataFrame\n", - " \"\"\"\n", - " super().__init__(\n", - " charged_frag_types=charged_frag_types,\n", - " precursor_mz_min=precursor_mz_min,\n", - " precursor_mz_max=precursor_mz_max,\n", - " decoy=decoy\n", - " )\n", - " self.protein_df:pd.DataFrame() = pd.DataFrame()\n", - " self.I_to_L = I_to_L\n", - " self.max_mod_combinations = 100\n", - " self._digest = Digest(\n", - " protease, max_missed_cleavages,\n", - " peptide_length_min, peptide_length_max\n", - " )\n", - " self.min_precursor_charge = precursor_charge_min\n", - " self.max_precursor_charge = precursor_charge_max\n", - "\n", - " self.var_mods = var_mods\n", - " self.fix_mods = fix_mods\n", - " self.max_var_mod_num = max_var_mod_num\n", - "\n", - " self.fix_mod_aas = ''\n", - " self.fix_mod_prot_nterm_dict = {}\n", - " self.fix_mod_prot_cterm_dict = {}\n", - " self.fix_mod_pep_nterm_dict = {}\n", - " self.fix_mod_pep_cterm_dict = {}\n", - " self.fix_mod_dict = {}\n", - "\n", - " def _set_term_mod(term_mod,\n", - " prot_nterm, prot_cterm, pep_nterm, pep_cterm,\n", - " allow_conflicts\n", - " ):\n", - " def _set_dict(term_dict,site,mod,\n", - " allow_conflicts\n", - " ):\n", - " if allow_conflicts:\n", - " if site in term_dict:\n", - " term_dict[site].append(term_mod)\n", - " else:\n", - " term_dict[site] = [term_mod]\n", - " else:\n", - " term_dict[site] = term_mod\n", - " site, term = parse_term_mod(term_mod)\n", - " if term == \"Any N-term\":\n", - " _set_dict(pep_nterm, site, term_mod, \n", - " allow_conflicts\n", - " )\n", - " elif term == 'Protein N-term':\n", - " _set_dict(prot_nterm, site, term_mod, \n", - " allow_conflicts\n", - " )\n", - " elif term == 'Any C-term':\n", - " _set_dict(pep_cterm, site, term_mod, \n", - " allow_conflicts\n", - " )\n", - " elif term == 'Protein C-term':\n", - " _set_dict(prot_cterm, site, term_mod, \n", - " allow_conflicts\n", - " )\n", - " \n", - " for mod in fix_mods:\n", - " if mod.find('@')+2 == len(mod):\n", - " self.fix_mod_aas += mod[-1]\n", - " self.fix_mod_dict[mod[-1]] = mod\n", - " else:\n", - " _set_term_mod(\n", - " mod, \n", - " self.fix_mod_prot_nterm_dict,\n", - " self.fix_mod_prot_cterm_dict,\n", - " self.fix_mod_pep_nterm_dict,\n", - " self.fix_mod_pep_cterm_dict,\n", - " allow_conflicts=False\n", - " )\n", - "\n", - " self.var_mod_aas = ''\n", - " self.var_mod_prot_nterm_dict = {}\n", - " self.var_mod_prot_cterm_dict = {}\n", - " self.var_mod_pep_nterm_dict = {}\n", - " self.var_mod_pep_cterm_dict = {}\n", - " self.var_mod_dict = {}\n", - "\n", - " global get_var_mods_per_sites\n", - " if self._check_if_multi_mods_on_aa(var_mods):\n", - " for mod in var_mods:\n", - " if mod.find('@')+2 == len(mod):\n", - " if mod[-1] in self.fix_mod_dict: continue\n", - " self.var_mod_aas += mod[-1]\n", - " if mod[-1] in self.var_mod_dict:\n", - " self.var_mod_dict[mod[-1]].append(mod)\n", - " else:\n", - " self.var_mod_dict[mod[-1]] = [mod]\n", - " get_var_mods_per_sites = get_var_mods_per_sites_multi_mods_on_aa\n", - " else:\n", - " for mod in var_mods:\n", - " if mod.find('@')+2 == len(mod):\n", - " if mod[-1] in self.fix_mod_dict: continue\n", - " self.var_mod_aas += mod[-1]\n", - " self.var_mod_dict[mod[-1]] = mod\n", - " get_var_mods_per_sites = get_var_mods_per_sites_single_mod_on_aa\n", - " \n", - " for mod in var_mods:\n", - " if mod.find('@')+2 < len(mod):\n", - " _set_term_mod(\n", - " mod, \n", - " self.var_mod_prot_nterm_dict,\n", - " self.var_mod_prot_cterm_dict,\n", - " self.var_mod_pep_nterm_dict,\n", - " self.var_mod_pep_cterm_dict,\n", - " allow_conflicts=True\n", - " )\n", - "\n", - " def _check_if_multi_mods_on_aa(self, var_mods):\n", - " mod_set = set()\n", - " for mod in var_mods:\n", - " if mod.find('@')+2 == len(mod):\n", - " if mod[-1] in mod_set: return True\n", - " mod_set.add(mod[-1])\n", - " return False\n", - "\n", - " def import_and_process_fasta(self, fasta_files:Union[str,list]):\n", - " \"\"\"Import and process a fasta file or a list of fasta files.\n", - " It includes:\n", - " - Load the fasta file(s)\n", - " - Append decoy peptide sequences\n", - " - Add modifications to peptides\n", - " - Add charge\n", - "\n", - " Parameters\n", - " ----------\n", - " fasta_files : Union[str,list]\n", - " A fasta file or a list of fasta files\n", - " \"\"\"\n", - " protein_dict = load_all_proteins(fasta_files)\n", - " self.import_and_process_protein_dict(protein_dict)\n", - "\n", - " def import_and_process_protein_dict(self, protein_dict:dict):\n", - " \"\"\" Import the protein_dict instead of fasta files.\n", - " ```\n", - " protein_dict = load_all_proteins(fasta_files)\n", - " ```\n", - "\n", - " Parameters\n", - " ----------\n", - " protein_dict : dict\n", - " Format:\n", - " {\n", - " 'prot_id1':\n", - " 'protein_id': 'prot_id1'\n", - " 'sequence': string\n", - " 'gene_name': string\n", - " 'description': string\n", - " 'prot_id2':\n", - " ...\n", - " }\n", - " \"\"\"\n", - " self.get_peptides_from_protein_dict(protein_dict)\n", - " self._process_after_load_pep_seqs()\n", - "\n", - " def import_and_process_peptide_sequences(self, \n", - " pep_seq_list:list, protein_list:list=None,\n", - " ):\n", - " \"\"\" Importing peptide sequences instead of proteins\n", - "\n", - " Parameters\n", - " ----------\n", - " pep_seq_list : list\n", - " Peptide sequence list\n", - "\n", - " protein_list : list, optional\n", - " Protein id list which maps to pep_seq_list one-by-one, \n", - " by default None\n", - " \"\"\"\n", - " self.get_peptides_from_peptide_sequence_list(\n", - " pep_seq_list, protein_list\n", - " )\n", - " self._process_after_load_pep_seqs()\n", - "\n", - " def _process_after_load_pep_seqs(self):\n", - " \"\"\"\n", - " Called by `import_and_process_...` methods. \n", - " \"\"\"\n", - " self.append_decoy_sequence()\n", - " self.add_modifications()\n", - " self.add_charge()\n", - "\n", - " def get_peptides_from_fasta(self, fasta_file:Union[str,list]):\n", - " \"\"\"Load peptide sequences from fasta files.\n", - "\n", - " Parameters\n", - " ----------\n", - " fasta_file : Union[str,list]\n", - " Could be a fasta file (str) or a list of fasta files (list[str])\n", - " \"\"\"\n", - " if isinstance(fasta_file, str):\n", - " self.get_peptides_from_fasta_list([fasta_file])\n", - " else:\n", - " self.get_peptides_from_fasta_list(fasta_file)\n", - "\n", - " def get_peptides_from_fasta_list(self, fasta_files:list):\n", - " \"\"\"Load peptide sequences from fasta file list\n", - "\n", - " Parameters\n", - " ----------\n", - " fasta_files : list\n", - " fasta file list\n", - " \"\"\"\n", - " protein_dict = load_all_proteins(fasta_files)\n", - " self.get_peptides_from_protein_dict(protein_dict)\n", - "\n", - " def get_peptides_from_protein_dict(self, protein_dict:dict):\n", - " \"\"\"Cleave the protein sequences in protein_dict.\n", - "\n", - " Parameters\n", - " ----------\n", - " protein_dict : dict\n", - " Format:\n", - " {\n", - " 'prot_id1':\n", - " 'protein_id': 'prot_id1'\n", - " 'sequence': string\n", - " 'gene_name': string\n", - " 'description': string\n", - " 'prot_id2':\n", - " ...\n", - " }\n", - " \"\"\"\n", - " self.protein_df = pd.DataFrame.from_dict(\n", - " protein_dict, orient='index'\n", - " ).reset_index(drop=True)\n", - "\n", - " if self.I_to_L:\n", - " self.protein_df[\n", - " 'sequence_I2L'\n", - " ] = self.protein_df.sequence.str.replace('I','L')\n", - " digest_seq = 'sequence_I2L'\n", - " else:\n", - " digest_seq = 'sequence'\n", - " self._cleave_to_peptides(\n", - " self.protein_df,\n", - " protein_seq_column=digest_seq\n", - " )\n", - "\n", - " def _cleave_to_peptides(self, \n", - " protein_df:pd.DataFrame,\n", - " protein_seq_column:str='sequence'\n", - " ):\n", - " \"\"\"Cleave protein sequences in protein_df\n", - "\n", - " Parameters\n", - " ----------\n", - " protein_df : pd.DataFrame\n", - " Protein DataFrame containing `protein_seq_column`\n", - " protein_seq_column : str, optional\n", - " Target column containing protein sequences, by default 'sequence'\n", - " \"\"\"\n", - " pep_dict = {}\n", - "\n", - " for i,prot_seq in enumerate(\n", - " protein_df[protein_seq_column].values\n", - " ):\n", - " (\n", - " seq_list, miss_list, nterm_list, cterm_list\n", - " ) = self._digest.cleave_sequence(prot_seq)\n", - " for seq,miss,nterm,cterm in zip(\n", - " seq_list,miss_list,nterm_list, cterm_list\n", - " ):\n", - " prot_id = str(i)\n", - " if seq in pep_dict:\n", - " if not pep_dict[seq][0].endswith(prot_id):\n", - " pep_dict[seq][0] += ';'+prot_id\n", - " if nterm:\n", - " pep_dict[seq][2] = nterm\n", - " if cterm:\n", - " pep_dict[seq][3] = cterm\n", - " else:\n", - " pep_dict[seq] = [prot_id,miss,nterm,cterm]\n", - " self._precursor_df = pd.DataFrame().from_dict(\n", - " pep_dict, orient='index', columns = [\n", - " 'protein_idxes','miss_cleavage',\n", - " 'is_prot_nterm','is_prot_cterm'\n", - " ]\n", - " )\n", - " self._precursor_df.reset_index(drop=False, inplace=True)\n", - " self._precursor_df.rename(\n", - " columns={'index':'sequence'}, inplace=True\n", - " )\n", - " self._precursor_df['mods'] = ''\n", - " self._precursor_df['mod_sites'] = ''\n", - " self.refine_df()\n", - "\n", - " def append_protein_name(self):\n", - " if (\n", - " 'protein_id' not in self.protein_df or \n", - " 'protein_idxes' not in self._precursor_df\n", - " ): \n", - " return\n", - "\n", - " self._precursor_df['proteins'] = self._precursor_df['protein_idxes'].apply(\n", - " protein_idxes_to_names,\n", - " protein_names=self.protein_df['protein_id'].values\n", - " )\n", - "\n", - " if 'gene_name' in self.protein_df.columns:\n", - " self._precursor_df['genes'] = self._precursor_df['protein_idxes'].apply(\n", - " protein_idxes_to_names,\n", - " protein_names=self.protein_df['gene_name'].values\n", - " )\n", - "\n", - " def get_peptides_from_peptide_sequence_list(self, \n", - " pep_seq_list:list,\n", - " protein_list:list = None\n", - " ):\n", - " self._precursor_df = pd.DataFrame()\n", - " self._precursor_df['sequence'] = pep_seq_list\n", - " if protein_list is not None:\n", - " self._precursor_df['protein_name'] = protein_list\n", - " self._precursor_df['is_prot_nterm'] = False\n", - " self._precursor_df['is_prot_cterm'] = False\n", - " self.refine_df()\n", - "\n", - " def add_mods_for_one_seq(self, sequence:str, \n", - " is_prot_nterm, is_prot_cterm\n", - " )->tuple:\n", - " \"\"\"Add fixed and variable modifications to a sequence\n", - "\n", - " Parameters\n", - " ----------\n", - " sequence : str\n", - " Peptide sequence\n", - " is_prot_nterm : bool\n", - " if protein N-term\n", - " is_prot_cterm : bool\n", - " if protein C-term\n", - "\n", - " Returns\n", - " -------\n", - " tuple\n", - " list[str]: list of modification names\n", - " list[str]: list of modification sites\n", - " \"\"\"\n", - " fix_mods, fix_mod_sites = get_fix_mods(\n", - " sequence, self.fix_mod_aas, self.fix_mod_dict\n", - " )\n", - " #TODO add prot and pep C-term fix mods\n", - " #TODO add prot and pep N-term fix mods\n", - "\n", - " if len(fix_mods) == 0:\n", - " fix_mods = ['']\n", - " fix_mod_sites = ['']\n", - " else:\n", - " fix_mods = [fix_mods]\n", - " fix_mod_sites = [fix_mod_sites]\n", - "\n", - " var_mods_list, var_mod_sites_list = get_var_mods(\n", - " sequence, self.var_mod_aas, self.var_mod_dict, \n", - " self.max_var_mod_num, self.max_mod_combinations-1, # 1 for unmodified\n", - " keep_unmodified=True\n", - " )\n", - "\n", - " nterm_var_mods = ['']\n", - " nterm_var_mod_sites = ['']\n", - " if is_prot_nterm and len(self.var_mod_prot_nterm_dict)>0:\n", - " if '' in self.var_mod_prot_nterm_dict:\n", - " nterm_var_mods.extend(self.var_mod_prot_nterm_dict[''])\n", - " if sequence[0] in self.var_mod_prot_nterm_dict:\n", - " nterm_var_mods.extend(self.var_mod_prot_nterm_dict[sequence[0]])\n", - " if len(self.var_mod_pep_nterm_dict)>0:\n", - " if '' in self.var_mod_pep_nterm_dict:\n", - " nterm_var_mods.extend(self.var_mod_pep_nterm_dict[''])\n", - " if sequence[0] in self.var_mod_pep_nterm_dict:\n", - " nterm_var_mods.extend(self.var_mod_pep_nterm_dict[sequence[0]])\n", - " nterm_var_mod_sites.extend(['0']*(len(nterm_var_mods)-1))\n", - "\n", - " #TODO add prot and pep C-term var mods\n", - "\n", - " return (\n", - " list(\n", - " ';'.join([i for i in items if i]) for items in itertools.product(\n", - " fix_mods, nterm_var_mods, var_mods_list\n", - " )\n", - " ),\n", - " list(\n", - " ';'.join([i for i in items if i]) for items in itertools.product(\n", - " fix_mod_sites, nterm_var_mod_sites, var_mod_sites_list\n", - " )\n", - " ),\n", - " )\n", - "\n", - " def add_modifications(self):\n", - " \"\"\"Add fixed and variable modifications to all peptide sequences in `self.precursor_df`\n", - " \"\"\"\n", - " if 'is_prot_nterm' not in self._precursor_df.columns:\n", - " self._precursor_df['is_prot_nterm'] = False\n", - " if 'is_prot_cterm' not in self._precursor_df.columns:\n", - " self._precursor_df['is_prot_cterm'] = False\n", - " \n", - " (\n", - " self._precursor_df['mods'],\n", - " self._precursor_df['mod_sites']\n", - " ) = zip(*self._precursor_df[\n", - " ['sequence','is_prot_nterm','is_prot_cterm']\n", - " ].apply(lambda x:\n", - " self.add_mods_for_one_seq(*x), axis=1\n", - " ))\n", - " self._precursor_df = explode_multiple_columns(\n", - " self._precursor_df,\n", - " ['mods','mod_sites']\n", - " )\n", - " self._precursor_df.reset_index(drop=True, inplace=True)\n", - "\n", - " def add_additional_modifications(self,\n", - " var_mods = ['Phospho@S','Phospho@T','Phospho@Y'], \n", - " max_mod_num:int=1, max_combs:int=100,\n", - " keep_unmodified:bool=True,\n", - " cannot_modify_pep_nterm_aa:bool=False,\n", - " cannot_modify_pep_cterm_aa:bool=False,\n", - " ):\n", - " \"\"\"Add external defined variable modifications to all peptide sequences in `self.precursor_df`.\n", - " See `append_regular_modifications` for details\n", - " \"\"\"\n", - " self._precursor_df = append_regular_modifications(\n", - " self.precursor_df,\n", - " var_mods=var_mods,\n", - " max_mod_num=max_mod_num,\n", - " max_combs=max_combs,\n", - " keep_unmodified=keep_unmodified,\n", - " cannot_modify_pep_nterm_aa=cannot_modify_pep_nterm_aa,\n", - " cannot_modify_pep_cterm_aa=cannot_modify_pep_cterm_aa,\n", - " )\n", - "\n", - " def add_peptide_labeling(self, labeling_channel_dict:dict):\n", - " \"\"\" \n", - " Add labeling onto peptides inplace of self._precursor_df\n", - "\n", - " Parameters\n", - " ----------\n", - " labeling_channel_dict : dict of list\n", - " For example:\n", - " {\n", - " 'reference': [], # not labelled for reference\n", - " '0': ['Dimethyl@Any N-term','Dimethyl@K'],\n", - " '4': ['Dimethyl:2H(4)@Any N-term','Dimethyl:2H(4)@K'],\n", - " '8': ['Dimethyl:2H(6)13C(2)@Any N-term','Dimethyl:2H(6)13C(2)@K'],\n", - " }.\n", - " The key name could be arbitrary distinguished strings for channel name,\n", - " and value must be a list of modification names (str) in alphabase format.\n", - " \n", - " \"\"\"\n", - " df_list = []\n", - " for channel, labels in labeling_channel_dict.items():\n", - " df = create_labeling_peptide_df(self._precursor_df, labels)\n", - " df['label_channel'] = channel\n", - " df_list.append(df)\n", - " self._precursor_df = pd.concat(df_list)\n", - " self._precursor_df.reset_index(drop=True, inplace=True)\n", - "\n", - " def add_charge(self):\n", - " \"\"\"Add charge states\n", - " \"\"\"\n", - " self._precursor_df['charge'] = [\n", - " np.arange(\n", - " self.min_precursor_charge, \n", - " self.max_precursor_charge+1\n", - " )\n", - " ]*len(self._precursor_df)\n", - " self._precursor_df = self._precursor_df.explode('charge')\n", - " self._precursor_df['charge'] = self._precursor_df.charge.astype(np.int8)\n", - " self._precursor_df.reset_index(drop=True, inplace=True)\n", - "\n", - " def save_hdf(self, hdf_file:str):\n", - " \"\"\"Save the contents into hdf file (attribute -> hdf_file):\n", - " - self.precursor_df -> library/precursor_df\n", - " - self.protein_df -> library/protein_df\n", - " - self.fragment_mz_df -> library/fragment_mz_df\n", - " - self.fragment_intensity_df -> library/fragment_intensity_df\n", - "\n", - " Parameters\n", - " ----------\n", - " hdf_file : str\n", - " The hdf file path\n", - " \"\"\"\n", - " super().save_hdf(hdf_file)\n", - " _hdf = HDF_File(\n", - " hdf_file,\n", - " read_only=False,\n", - " truncate=True,\n", - " delete_existing=False\n", - " )\n", - " _hdf.library.protein_df = self.protein_df\n", - "\n", - " def load_hdf(self, hdf_file:str, load_mod_seq:bool=False):\n", - " \"\"\"Load contents from hdf file:\n", - " - self.precursor_df <- library/precursor_df\n", - " - self.precursor_df <- library/mod_seq_df if load_mod_seq is True\n", - " - self.protein_df <- library/protein_df\n", - " - self.fragment_mz_df <- library/fragment_mz_df\n", - " - self.fragment_intensity_df <- library/fragment_intensity_df\n", - "\n", - " Parameters\n", - " ----------\n", - " hdf_file : str\n", - " hdf file path\n", - "\n", - " load_mod_seq : bool, optional\n", - " After library is generated with hash values (int64) for sequences (str) and modifications (str),\n", - " we don't need sequence information for searching. \n", - " So we can skip loading sequences to make the loading much faster.\n", - " By default False\n", - " \"\"\"\n", - " super().load_hdf(hdf_file, load_mod_seq=load_mod_seq)\n", - " try:\n", - " _hdf = HDF_File(\n", - " hdf_file,\n", - " )\n", - " self.protein_df = _hdf.library.protein_df.values\n", - " except (AttributeError, KeyError, ValueError, TypeError):\n", - " print(f\"No protein_df in {hdf_file}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| hide\n", - "from nbdev.showdoc import show_doc" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L1082){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.add_modifications\n", - "\n", - "> FastaLib.add_modifications ()\n", - "\n", - "Add fixed and variable modifications to all peptide sequences in `self.precursor_df`" - ], - "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L1082){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.add_modifications\n", - "\n", - "> FastaLib.add_modifications ()\n", - "\n", - "Add fixed and variable modifications to all peptide sequences in `self.precursor_df`" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "show_doc(FastaLib.add_modifications)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L1104){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.add_additional_modifications\n", - "\n", - "> FastaLib.add_additional_modifications (var_mods=['Phospho@S',\n", - "> 'Phospho@T', 'Phospho@Y'],\n", - "> max_mod_num:int=1,\n", - "> max_combs:int=100,\n", - "> keep_unmodified:bool=True, cannot_\n", - "> modify_pep_nterm_aa:bool=False, ca\n", - "> nnot_modify_pep_cterm_aa:bool=Fals\n", - "> e)\n", - "\n", - "Add external defined variable modifications to all peptide sequences in `self.precursor_df`.\n", - "See `append_regular_modifications` for details" - ], - "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L1104){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.add_additional_modifications\n", - "\n", - "> FastaLib.add_additional_modifications (var_mods=['Phospho@S',\n", - "> 'Phospho@T', 'Phospho@Y'],\n", - "> max_mod_num:int=1,\n", - "> max_combs:int=100,\n", - "> keep_unmodified:bool=True, cannot_\n", - "> modify_pep_nterm_aa:bool=False, ca\n", - "> nnot_modify_pep_cterm_aa:bool=Fals\n", - "> e)\n", - "\n", - "Add external defined variable modifications to all peptide sequences in `self.precursor_df`.\n", - "See `append_regular_modifications` for details" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "show_doc(FastaLib.add_additional_modifications)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L1014){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.add_mods_for_one_seq\n", - "\n", - "> FastaLib.add_mods_for_one_seq (sequence:str, is_prot_nterm,\n", - "> is_prot_cterm)\n", - "\n", - "Add fixed and variable modifications to a sequence\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| sequence | str | Peptide sequence |\n", - "| is_prot_nterm | bool | if protein N-term |\n", - "| is_prot_cterm | bool | if protein C-term |\n", - "| **Returns** | **tuple** | **list[str]: list of modification names
list[str]: list of modification sites** |" - ], - "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L1014){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.add_mods_for_one_seq\n", - "\n", - "> FastaLib.add_mods_for_one_seq (sequence:str, is_prot_nterm,\n", - "> is_prot_cterm)\n", - "\n", - "Add fixed and variable modifications to a sequence\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| sequence | str | Peptide sequence |\n", - "| is_prot_nterm | bool | if protein N-term |\n", - "| is_prot_cterm | bool | if protein C-term |\n", - "| **Returns** | **tuple** | **list[str]: list of modification names
list[str]: list of modification sites** |" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "show_doc(FastaLib.add_mods_for_one_seq)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L1124){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.add_peptide_labeling\n", - "\n", - "> FastaLib.add_peptide_labeling (labeling_channel_dict:dict)\n", - "\n", - "Add labeling onto peptides inplace of self._precursor_df\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| labeling_channel_dict | dict | For example:
{
'reference': [], # not labelled for reference
'0': ['Dimethyl@Any N-term','Dimethyl@K'],
'4': ['Dimethyl:2H(4)@Any N-term','Dimethyl:2H(4)@K'],
'8': ['Dimethyl:2H(6)13C(2)@Any N-term','Dimethyl:2H(6)13C(2)@K'],
}.
The key name could be arbitrary distinguished strings for channel name,
and value must be a list of modification names (str) in alphabase format. |" - ], - "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L1124){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.add_peptide_labeling\n", - "\n", - "> FastaLib.add_peptide_labeling (labeling_channel_dict:dict)\n", - "\n", - "Add labeling onto peptides inplace of self._precursor_df\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| labeling_channel_dict | dict | For example:
{
'reference': [], # not labelled for reference
'0': ['Dimethyl@Any N-term','Dimethyl@K'],
'4': ['Dimethyl:2H(4)@Any N-term','Dimethyl:2H(4)@K'],
'8': ['Dimethyl:2H(6)13C(2)@Any N-term','Dimethyl:2H(6)13C(2)@K'],
}.
The key name could be arbitrary distinguished strings for channel name,
and value must be a list of modification names (str) in alphabase format. |" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "show_doc(FastaLib.add_peptide_labeling)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#LNone){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### SpecLibBase.append_decoy_sequence\n", - "\n", - "> SpecLibBase.append_decoy_sequence ()\n", - "\n", - "Append decoy sequence into precursor_df.\n", - "Decoy method is based on self.decoy(str).\n", - "```\n", - "decoy_lib = (\n", - " decoy_lib_provider.get_decoy_lib(\n", - " self.decoy, self\n", - " )\n", - ")\n", - "decoy_lib.decoy_sequence()\n", - "...\n", - "```" - ], - "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#LNone){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### SpecLibBase.append_decoy_sequence\n", - "\n", - "> SpecLibBase.append_decoy_sequence ()\n", - "\n", - "Append decoy sequence into precursor_df.\n", - "Decoy method is based on self.decoy(str).\n", - "```\n", - "decoy_lib = (\n", - " decoy_lib_provider.get_decoy_lib(\n", - " self.decoy, self\n", - " )\n", - ")\n", - "decoy_lib.decoy_sequence()\n", - "...\n", - "```" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "show_doc(FastaLib.append_decoy_sequence)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L879){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.get_peptides_from_fasta\n", - "\n", - "> FastaLib.get_peptides_from_fasta (fasta_file:Union[str,list])\n", - "\n", - "Load peptide sequences from fasta files.\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| fasta_file | typing.Union[str, list] | Could be a fasta file (str) or a list of fasta files (list[str]) |" - ], - "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L879){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.get_peptides_from_fasta\n", - "\n", - "> FastaLib.get_peptides_from_fasta (fasta_file:Union[str,list])\n", - "\n", - "Load peptide sequences from fasta files.\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| fasta_file | typing.Union[str, list] | Could be a fasta file (str) or a list of fasta files (list[str]) |" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "show_doc(FastaLib.get_peptides_from_fasta)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L903){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.get_peptides_from_protein_dict\n", - "\n", - "> FastaLib.get_peptides_from_protein_dict (protein_dict:dict)\n", - "\n", - "Cleave the protein sequences in protein_dict.\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| protein_dict | dict | Format:
{
'prot_id1':
'protein_id': 'prot_id1'
'sequence': string
'gene_name': string
'description': string
'prot_id2':
...
} |" - ], - "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L903){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.get_peptides_from_protein_dict\n", - "\n", - "> FastaLib.get_peptides_from_protein_dict (protein_dict:dict)\n", - "\n", - "Cleave the protein sequences in protein_dict.\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| protein_dict | dict | Format:
{
'prot_id1':
'protein_id': 'prot_id1'
'sequence': string
'gene_name': string
'description': string
'prot_id2':
...
} |" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "show_doc(FastaLib.get_peptides_from_protein_dict)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L1002){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.get_peptides_from_peptide_sequence_list\n", - "\n", - "> FastaLib.get_peptides_from_peptide_sequence_list (pep_seq_list:list,\n", - "> protein_list:list=None)" - ], - "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L1002){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.get_peptides_from_peptide_sequence_list\n", - "\n", - "> FastaLib.get_peptides_from_peptide_sequence_list (pep_seq_list:list,\n", - "> protein_list:list=None)" + " (2, 4, 6),\n", + " (2, 4, 7),\n", + " (2, 5, 6),\n", + " (2, 5, 7)]" ] }, "execution_count": null, @@ -2079,7 +140,10 @@ } ], "source": [ - "show_doc(FastaLib.get_peptides_from_peptide_sequence_list)" + "seq = 'AMCMSTYK'\n", + "candidate_sites = get_candidate_sites(seq, 'MSTY')\n", + "assert np.all(np.array(candidate_sites)==np.array([2,4,5,6,7]))\n", + "get_var_mod_sites(seq, 'MSTY', 3, 20)" ] }, { @@ -2089,45 +153,51 @@ "outputs": [ { "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L813){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.import_and_process_fasta\n", - "\n", - "> FastaLib.import_and_process_fasta (fasta_files:Union[str,list])\n", - "\n", - "Import and process a fasta file or a list of fasta files.\n", - "It includes:\n", - "- Load the fasta file(s)\n", - "- Append decoy peptide sequences\n", - "- Add modifications to peptides\n", - "- Add charge\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| fasta_files | typing.Union[str, list] | A fasta file or a list of fasta files |" - ], "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L813){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.import_and_process_fasta\n", - "\n", - "> FastaLib.import_and_process_fasta (fasta_files:Union[str,list])\n", - "\n", - "Import and process a fasta file or a list of fasta files.\n", - "It includes:\n", - "- Load the fasta file(s)\n", - "- Append decoy peptide sequences\n", - "- Add modifications to peptides\n", - "- Add charge\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| fasta_files | typing.Union[str, list] | A fasta file or a list of fasta files |" + "(['mod@M',\n", + " 'mod@M',\n", + " 'mod@S',\n", + " 'modX@S',\n", + " 'mod@T',\n", + " 'mod@Y',\n", + " 'mod@M;mod@M',\n", + " 'mod@M;mod@S',\n", + " 'mod@M;modX@S',\n", + " 'mod@M;mod@T',\n", + " 'mod@M;mod@Y',\n", + " 'mod@M;mod@S',\n", + " 'mod@M;modX@S',\n", + " 'mod@M;mod@T',\n", + " 'mod@M;mod@Y',\n", + " 'mod@S;mod@T',\n", + " 'modX@S;mod@T',\n", + " 'mod@S;mod@Y',\n", + " 'modX@S;mod@Y',\n", + " 'mod@T;mod@Y',\n", + " 'mod@M;mod@M;mod@S',\n", + " 'mod@M;mod@M;modX@S'],\n", + " ['2',\n", + " '4',\n", + " '5',\n", + " '5',\n", + " '6',\n", + " '7',\n", + " '2;4',\n", + " '2;5',\n", + " '2;5',\n", + " '2;6',\n", + " '2;7',\n", + " '4;5',\n", + " '4;5',\n", + " '4;6',\n", + " '4;7',\n", + " '5;6',\n", + " '5;6',\n", + " '5;7',\n", + " '5;7',\n", + " '6;7',\n", + " '2;4;5',\n", + " '2;4;5'])" ] }, "execution_count": null, @@ -2136,7 +206,26 @@ } ], "source": [ - "show_doc(FastaLib.import_and_process_fasta)" + "#| hide\n", + "fasta.get_var_mods_per_sites = get_var_mods_per_sites_multi_mods_on_aa\n", + "seq = 'AMCMSTYK'\n", + "candidate_sites = get_candidate_sites(seq, 'MSTY')\n", + "mod_sites_list = get_var_mod_sites(seq, 'MSTY', 3, 20)\n", + "_mod_dict = {\n", + " 'M':['mod@M'],\n", + " 'S':['mod@S','modX@S'],\n", + " 'T':['mod@T'],\n", + " 'Y':['mod@Y'],\n", + "}\n", + "_mods, _sites = get_var_mods(seq, 'MSTY', _mod_dict, 3, 16)\n", + "\n", + "assert 'mod@M;mod@M;mod@S' in _mods\n", + "assert _sites[_mods.index('mod@M;mod@M;mod@S')] == '2;4;5'\n", + "assert 'mod@M;mod@M;modX@S' in _mods\n", + "assert _sites[_mods.index('mod@M;mod@M;modX@S')] == '2;4;5'\n", + "assert 'mod@M;mod@S' in _mods\n", + "assert 'mod@M;modX@S' in _mods\n", + "get_var_mods(seq, 'MSTY', _mod_dict, 3, 16)" ] }, { @@ -2146,41 +235,39 @@ "outputs": [ { "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L829){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.import_and_process_protein_dict\n", - "\n", - "> FastaLib.import_and_process_protein_dict (protein_dict:dict)\n", - "\n", - "Import the protein_dict instead of fasta files.\n", - "```\n", - "protein_dict = load_all_proteins(fasta_files)\n", - "```\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| protein_dict | dict | Format:
{
'prot_id1':
'protein_id': 'prot_id1'
'sequence': string
'gene_name': string
'description': string
'prot_id2':
...
} |" - ], "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L829){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.import_and_process_protein_dict\n", - "\n", - "> FastaLib.import_and_process_protein_dict (protein_dict:dict)\n", - "\n", - "Import the protein_dict instead of fasta files.\n", - "```\n", - "protein_dict = load_all_proteins(fasta_files)\n", - "```\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| protein_dict | dict | Format:
{
'prot_id1':
'protein_id': 'prot_id1'
'sequence': string
'gene_name': string
'description': string
'prot_id2':
...
} |" + "(['mod@M',\n", + " 'mod@M',\n", + " 'mod@S',\n", + " 'mod@T',\n", + " 'mod@Y',\n", + " 'mod@M;mod@M',\n", + " 'mod@M;mod@S',\n", + " 'mod@M;mod@T',\n", + " 'mod@M;mod@Y',\n", + " 'mod@M;mod@S',\n", + " 'mod@M;mod@T',\n", + " 'mod@M;mod@Y',\n", + " 'mod@S;mod@T',\n", + " 'mod@S;mod@Y',\n", + " 'mod@T;mod@Y',\n", + " 'mod@M;mod@M;mod@S'],\n", + " ['2',\n", + " '4',\n", + " '5',\n", + " '6',\n", + " '7',\n", + " '2;4',\n", + " '2;5',\n", + " '2;6',\n", + " '2;7',\n", + " '4;5',\n", + " '4;6',\n", + " '4;7',\n", + " '5;6',\n", + " '5;7',\n", + " '6;7',\n", + " '2;4;5'])" ] }, "execution_count": null, @@ -2189,172 +276,90 @@ } ], "source": [ - "show_doc(FastaLib.import_and_process_protein_dict)" + "#| hide\n", + "fasta.get_var_mods_per_sites = get_var_mods_per_sites_single_mod_on_aa\n", + "seq = 'AMCMSTYK'\n", + "candidate_sites = get_candidate_sites(seq, 'MSTY')\n", + "mod_sites_list = get_var_mod_sites(seq, 'MSTY', 3, 20)\n", + "_mod_dict = {\n", + " 'M':'mod@M',\n", + " 'S':'mod@S',\n", + " 'T':'mod@T',\n", + " 'Y':'mod@Y',\n", + "}\n", + "_mods, _sites = get_var_mods(seq, 'MSTY', _mod_dict, 3, 16)\n", + "assert len(_mods) == len(_sites) == 16\n", + "assert _sites[_mods.index('mod@M;mod@M;mod@S')] == '2;4;5'\n", + "get_var_mods(seq, 'MSTY', _mod_dict, 3, 16)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L852){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.import_and_process_peptide_sequences\n", - "\n", - "> FastaLib.import_and_process_peptide_sequences (pep_seq_list:list,\n", - "> protein_list:list=None)\n", - "\n", - "Importing peptide sequences instead of proteins\n", - "\n", - "| | **Type** | **Default** | **Details** |\n", - "| -- | -------- | ----------- | ----------- |\n", - "| pep_seq_list | list | | Peptide sequence list |\n", - "| protein_list | list | None | Protein id list which maps to pep_seq_list one-by-one,
by default None |" - ], - "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L852){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.import_and_process_peptide_sequences\n", - "\n", - "> FastaLib.import_and_process_peptide_sequences (pep_seq_list:list,\n", - "> protein_list:list=None)\n", - "\n", - "Importing peptide sequences instead of proteins\n", - "\n", - "| | **Type** | **Default** | **Details** |\n", - "| -- | -------- | ----------- | ----------- |\n", - "| pep_seq_list | list | | Peptide sequence list |\n", - "| protein_list | list | None | Protein id list which maps to pep_seq_list one-by-one,
by default None |" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "show_doc(FastaLib.import_and_process_peptide_sequences)" + "#| hide\n", + "assert parse_term_mod('Acetyl@Protein N-term') == ('', 'Protein N-term')\n", + "assert parse_term_mod('Gln->pyro-Glu@Q^Any N-term') == ('Q', 'Any N-term')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L1163){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.save_hdf\n", - "\n", - "> FastaLib.save_hdf (hdf_file:str)\n", - "\n", - "Save the contents into hdf file (attribute -> hdf_file):\n", - "- self.precursor_df -> library/precursor_df\n", - "- self.protein_df -> library/protein_df\n", - "- self.fragment_mz_df -> library/fragment_mz_df\n", - "- self.fragment_intensity_df -> library/fragment_intensity_df\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| hdf_file | str | The hdf file path |" - ], - "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L1163){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.save_hdf\n", - "\n", - "> FastaLib.save_hdf (hdf_file:str)\n", - "\n", - "Save the contents into hdf file (attribute -> hdf_file):\n", - "- self.precursor_df -> library/precursor_df\n", - "- self.protein_df -> library/protein_df\n", - "- self.fragment_mz_df -> library/fragment_mz_df\n", - "- self.fragment_intensity_df -> library/fragment_intensity_df\n", - "\n", - "| | **Type** | **Details** |\n", - "| -- | -------- | ----------- |\n", - "| hdf_file | str | The hdf file path |" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "show_doc(FastaLib.save_hdf)" + "#| hide\n", + "labels = ['label@Any N-term','label@K']\n", + "(\n", + " label_aas, label_mod_dict, \n", + " nterm_label_mod, cterm_label_mod\n", + ") = parse_labels(labels)\n", + "assert add_single_peptide_labeling(\n", + " 'ABCK','','', label_aas, label_mod_dict, \n", + " nterm_label_mod, cterm_label_mod\n", + ") == ('label@Any N-term;label@K', '0;4')\n", + "assert add_single_peptide_labeling(\n", + " 'ABCK','Mod@Any N-term','0', label_aas, label_mod_dict, \n", + " nterm_label_mod, cterm_label_mod\n", + ") == ('Mod@Any N-term;label@K', '0;4')\n", + "assert add_single_peptide_labeling(\n", + " 'KBCK','','', label_aas, label_mod_dict, \n", + " nterm_label_mod, cterm_label_mod\n", + ") == ('label@Any N-term;label@K;label@K', '0;1;4')\n", + "assert add_single_peptide_labeling(\n", + " 'KBCK','Mod@Any N-term','0', label_aas, label_mod_dict, \n", + " nterm_label_mod, cterm_label_mod\n", + ") == ('Mod@Any N-term;label@K;label@K', '0;1;4')\n", + "pep_df = pd.DataFrame({\n", + " 'sequence': ['ABCD','ABCK','KABK','EFGK'],\n", + " 'mods': ['']*3+['Mod@Any N-term'],\n", + " 'mod_sites': ['']*3+['0']\n", + "})\n", + "df = create_labeling_peptide_df(pep_df, labels)\n", + "assert np.all(df.mods.values!=pep_df.mods.values)\n", + "assert df[df.sequence=='ABCD'].mods.values[0] == 'label@Any N-term'\n", + "assert df[df.sequence=='ABCD'].mod_sites.values[0] == '0'\n", + "assert df[df.sequence=='ABCK'].mods.values[0] == 'label@Any N-term;label@K'\n", + "assert df[df.sequence=='ABCK'].mod_sites.values[0] == '0;4'\n", + "assert df[df.sequence=='KABK'].mods.values[0] == 'label@Any N-term;label@K;label@K'\n", + "assert df[df.sequence=='KABK'].mod_sites.values[0] == '0;1;4'\n", + "assert df[df.sequence=='EFGK'].mods.values[0] == 'Mod@Any N-term;label@K'\n", + "assert df[df.sequence=='EFGK'].mod_sites.values[0] == '0;4'\n", + "df = create_labeling_peptide_df(pep_df, [])\n", + "assert np.all(df.mods.values==pep_df.mods.values)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L1184){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.load_hdf\n", - "\n", - "> FastaLib.load_hdf (hdf_file:str, load_mod_seq:bool=False)\n", - "\n", - "Load contents from hdf file:\n", - "- self.precursor_df <- library/precursor_df\n", - "- self.precursor_df <- library/mod_seq_df if load_mod_seq is True\n", - "- self.protein_df <- library/protein_df\n", - "- self.fragment_mz_df <- library/fragment_mz_df\n", - "- self.fragment_intensity_df <- library/fragment_intensity_df\n", - "\n", - "| | **Type** | **Default** | **Details** |\n", - "| -- | -------- | ----------- | ----------- |\n", - "| hdf_file | str | | hdf file path |\n", - "| load_mod_seq | bool | False | After library is generated with hash values (int64) for sequences (str) and modifications (str),
we don't need sequence information for searching.
So we can skip loading sequences to make the loading much faster.
By default False |" - ], - "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/protein/fasta.py#L1184){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### FastaLib.load_hdf\n", - "\n", - "> FastaLib.load_hdf (hdf_file:str, load_mod_seq:bool=False)\n", - "\n", - "Load contents from hdf file:\n", - "- self.precursor_df <- library/precursor_df\n", - "- self.precursor_df <- library/mod_seq_df if load_mod_seq is True\n", - "- self.protein_df <- library/protein_df\n", - "- self.fragment_mz_df <- library/fragment_mz_df\n", - "- self.fragment_intensity_df <- library/fragment_intensity_df\n", - "\n", - "| | **Type** | **Default** | **Details** |\n", - "| -- | -------- | ----------- | ----------- |\n", - "| hdf_file | str | | hdf file path |\n", - "| load_mod_seq | bool | False | After library is generated with hash values (int64) for sequences (str) and modifications (str),
we don't need sequence information for searching.
So we can skip loading sequences to make the loading much faster.
By default False |" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "show_doc(FastaLib.load_hdf)" + "#| hide\n", + "assert protein_idxes_to_names('0;1', ['A','','B'])=='A'\n", + "assert protein_idxes_to_names('0;1', ['A','C','B'])=='A;C'" ] }, { @@ -4320,9 +2325,9 @@ " precursor_mz\n", " isotope_m1_intensity\n", " isotope_apex_intensity\n", - " isotope_apex_index\n", + " isotope_apex_offset\n", " isotope_right_most_intensity\n", - " isotope_right_most_index\n", + " isotope_right_most_offset\n", " isotope_m1_mz\n", " isotope_apex_mz\n", " isotope_right_most_mz\n", @@ -4603,31 +2608,31 @@ "82 13 0 3 510.273282 \n", "83 13 0 4 382.956781 \n", "\n", - " isotope_m1_intensity isotope_apex_intensity isotope_apex_index \\\n", - "0 0.478814 1.0 0 \n", - "1 0.478814 1.0 0 \n", - "2 0.478814 1.0 0 \n", - "3 0.478433 1.0 0 \n", - "4 0.478433 1.0 0 \n", - ".. ... ... ... \n", - "79 0.828432 1.0 0 \n", - "80 0.828432 1.0 0 \n", - "81 0.828051 1.0 0 \n", - "82 0.828051 1.0 0 \n", - "83 0.828051 1.0 0 \n", - "\n", - " isotope_right_most_intensity isotope_right_most_index isotope_m1_mz \\\n", - "0 0.478814 1 482.241484 \n", - "1 0.478814 1 321.830081 \n", - "2 0.478814 1 241.624380 \n", - "3 0.478433 1 474.244027 \n", - "4 0.478433 1 316.498443 \n", - ".. ... ... ... \n", - "79 0.420789 2 515.939354 \n", - "80 0.420789 2 387.206334 \n", - "81 0.418418 2 765.407935 \n", - "82 0.418418 2 510.607715 \n", - "83 0.418418 2 383.207606 \n", + " isotope_m1_intensity isotope_apex_intensity isotope_apex_offset \\\n", + "0 0.478814 1.0 0 \n", + "1 0.478814 1.0 0 \n", + "2 0.478814 1.0 0 \n", + "3 0.478433 1.0 0 \n", + "4 0.478433 1.0 0 \n", + ".. ... ... ... \n", + "79 0.828432 1.0 0 \n", + "80 0.828432 1.0 0 \n", + "81 0.828051 1.0 0 \n", + "82 0.828051 1.0 0 \n", + "83 0.828051 1.0 0 \n", + "\n", + " isotope_right_most_intensity isotope_right_most_offset isotope_m1_mz \\\n", + "0 0.478814 1 482.241484 \n", + "1 0.478814 1 321.830081 \n", + "2 0.478814 1 241.624380 \n", + "3 0.478433 1 474.244027 \n", + "4 0.478433 1 316.498443 \n", + ".. ... ... ... \n", + "79 0.420789 2 515.939354 \n", + "80 0.420789 2 387.206334 \n", + "81 0.418418 2 765.407935 \n", + "82 0.418418 2 510.607715 \n", + "83 0.418418 2 383.207606 \n", "\n", " isotope_apex_mz isotope_right_most_mz \n", "0 481.739834 482.241484 \n", @@ -4653,7 +2658,8 @@ "source": [ "_lib = FastaLib(\n", " ['b_z1','y_z1'], I_to_L=False, \n", - " decoy='pseudo_reverse'\n", + " decoy='pseudo_reverse',\n", + " precursor_mz_min=200,\n", ")\n", "prot1 = 'MACDESTYKBKFGHIKLMNPQRST'\n", "prot2 = 'FGHIKLMNPQR'\n", @@ -4673,7 +2679,7 @@ "assert (_lib.precursor_df.charge == _lib.max_precursor_charge).any()\n", "assert (_lib.precursor_df.decoy==1).any()\n", "assert ('MACDESTY'[::-1]+'K') in _lib.precursor_df.sequence.values\n", - "assert 'isotope_apex_index' in _lib.precursor_df.columns\n", + "assert 'isotope_apex_offset' in _lib.precursor_df.columns\n", "assert 'isotope_apex_intensity' in _lib.precursor_df.columns\n", "assert ~_lib.precursor_df.sequence.str.contains('B').any()\n", "_lib.precursor_df" @@ -4719,9 +2725,9 @@ " precursor_mz\n", " isotope_m1_intensity\n", " isotope_apex_intensity\n", - " isotope_apex_index\n", + " isotope_apex_offset\n", " isotope_right_most_intensity\n", - " isotope_right_most_index\n", + " isotope_right_most_offset\n", " isotope_m1_mz\n", " isotope_apex_mz\n", " isotope_right_most_mz\n", @@ -5026,44 +3032,44 @@ "166 3 heavy 534.323729 0.787646 \n", "167 4 heavy 400.994616 0.787646 \n", "\n", - " isotope_apex_intensity isotope_apex_index isotope_right_most_intensity \\\n", - "0 1.0 0 0.500906 \n", - "1 1.0 0 0.500906 \n", - "2 1.0 0 0.500906 \n", - "3 1.0 0 0.500525 \n", - "4 1.0 0 0.500525 \n", - ".. ... ... ... \n", - "163 1.0 0 0.392103 \n", - "164 1.0 0 0.392103 \n", - "165 1.0 0 0.389779 \n", - "166 1.0 0 0.389779 \n", - "167 1.0 0 0.389779 \n", - "\n", - " isotope_right_most_index isotope_m1_mz isotope_apex_mz \\\n", - "0 1 496.257134 495.755484 \n", - "1 1 331.173848 330.839415 \n", - "2 1 248.632205 248.381380 \n", - "3 1 488.259677 487.758027 \n", - "4 1 325.842210 325.507777 \n", - ".. ... ... ... \n", - "163 2 539.989801 539.655367 \n", - "164 2 405.244169 404.993344 \n", - "165 2 801.483605 800.981955 \n", - "166 2 534.658162 534.323729 \n", - "167 2 401.245441 400.994616 \n", - "\n", - " isotope_right_most_mz \n", - "0 496.257134 \n", - "1 331.173848 \n", - "2 248.632205 \n", - "3 488.259677 \n", - "4 325.842210 \n", - ".. ... \n", - "163 540.324234 \n", - "164 405.494994 \n", - "165 801.985255 \n", - "166 534.992596 \n", - "167 401.496266 \n", + " isotope_apex_intensity isotope_apex_offset \\\n", + "0 1.0 0 \n", + "1 1.0 0 \n", + "2 1.0 0 \n", + "3 1.0 0 \n", + "4 1.0 0 \n", + ".. ... ... \n", + "163 1.0 0 \n", + "164 1.0 0 \n", + "165 1.0 0 \n", + "166 1.0 0 \n", + "167 1.0 0 \n", + "\n", + " isotope_right_most_intensity isotope_right_most_offset isotope_m1_mz \\\n", + "0 0.500906 1 496.257134 \n", + "1 0.500906 1 331.173848 \n", + "2 0.500906 1 248.632205 \n", + "3 0.500525 1 488.259677 \n", + "4 0.500525 1 325.842210 \n", + ".. ... ... ... \n", + "163 0.392103 2 539.989801 \n", + "164 0.392103 2 405.244169 \n", + "165 0.389779 2 801.483605 \n", + "166 0.389779 2 534.658162 \n", + "167 0.389779 2 401.245441 \n", + "\n", + " isotope_apex_mz isotope_right_most_mz \n", + "0 495.755484 496.257134 \n", + "1 330.839415 331.173848 \n", + "2 248.381380 248.632205 \n", + "3 487.758027 488.259677 \n", + "4 325.507777 325.842210 \n", + ".. ... ... \n", + "163 539.655367 540.324234 \n", + "164 404.993344 405.494994 \n", + "165 800.981955 801.985255 \n", + "166 534.323729 534.992596 \n", + "167 400.994616 401.496266 \n", "\n", "[168 rows x 20 columns]" ] @@ -5082,7 +3088,7 @@ "_lib.calc_precursor_isotope()\n", "assert (_lib.precursor_df.decoy==1).any()\n", "assert ('MACDESTY'[::-1]+'K') in _lib.precursor_df.sequence.values\n", - "assert 'isotope_apex_index' in _lib.precursor_df.columns\n", + "assert 'isotope_apex_offset' in _lib.precursor_df.columns\n", "assert 'isotope_apex_intensity' in _lib.precursor_df.columns\n", "assert ~_lib.precursor_df.sequence.str.contains('B').any()\n", "_lib.precursor_df" diff --git a/nbdev_nbs/protein/test_fasta.ipynb b/nbdev_nbs/protein/test_fasta.ipynb index cfac0abc..cff8781e 100644 --- a/nbdev_nbs/protein/test_fasta.ipynb +++ b/nbdev_nbs/protein/test_fasta.ipynb @@ -160,10 +160,10 @@ "assert 'precursor_mz' in fastalib.precursor_df.columns\n", "assert 'isotope_apex_mz' in fastalib.precursor_df.columns\n", "assert 'isotope_apex_intensity' in fastalib.precursor_df.columns\n", - "assert 'isotope_apex_index' in fastalib.precursor_df.columns\n", + "assert 'isotope_apex_offset' in fastalib.precursor_df.columns\n", "assert 'isotope_right_most_mz' in fastalib.precursor_df.columns\n", "assert 'isotope_right_most_intensity' in fastalib.precursor_df.columns\n", - "assert 'isotope_right_most_index' in fastalib.precursor_df.columns\n", + "assert 'isotope_right_most_offset' in fastalib.precursor_df.columns\n", "assert 'isotope_m1_mz' in fastalib.precursor_df.columns\n", "assert 'isotope_m1_intensity' in fastalib.precursor_df.columns" ] diff --git a/nbdev_nbs/psm_reader/alphapept_reader.ipynb b/nbdev_nbs/psm_reader/alphapept_reader.ipynb index cdf49300..0b33aeca 100644 --- a/nbdev_nbs/psm_reader/alphapept_reader.ipynb +++ b/nbdev_nbs/psm_reader/alphapept_reader.ipynb @@ -6,7 +6,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| default_exp psm_reader.alphapept_reader" + "#---#| default_exp psm_reader.alphapept_reader" ] }, { @@ -17,22 +17,10 @@ ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "#| export\n", - "import numba\n", - "import os\n", - "import pandas as pd\n", - "import numpy as np\n", - "import h5py\n", - "\n", - "from alphabase.psm_reader.psm_reader import (\n", - " PSMReaderBase, psm_reader_provider,\n", - " psm_reader_yaml\n", - ")" + "### Column and modification mapping from alphabase to MaxQuant" ] }, { @@ -41,124 +29,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| export\n", - "\n", - "@numba.njit\n", - "def parse_ap(precursor):\n", - " \"\"\"\n", - " Parser to parse peptide strings\n", - " \"\"\"\n", - " items = precursor.split('_')\n", - " if len(items) == 3:\n", - " decoy = 1\n", - " else:\n", - " decoy = 0\n", - " modseq = items[0]\n", - " charge = items[-1]\n", - "\n", - " parsed = []\n", - " mods = []\n", - " sites = []\n", - " string = \"\"\n", - "\n", - " if modseq[0] == 'a':\n", - " sites.append('0')\n", - " mods.append('a')\n", - " modseq = modseq[1:]\n", - " elif modseq.startswith('tmt'):\n", - " for l in range(3, len(modseq)):\n", - " if modseq[l].isupper():\n", - " break\n", - " sites.append('0')\n", - " mods.append(modseq[:l])\n", - " modseq = modseq[l:]\n", - "\n", - " for i in modseq:\n", - " string += i\n", - " if i.isupper():\n", - " parsed.append(i)\n", - " if len(string) > 1:\n", - " sites.append(str(len(parsed)))\n", - " mods.append(string)\n", - " string = \"\"\n", - "\n", - " return ''.join(parsed), ';'.join(mods), ';'.join(sites), charge, decoy\n", - "\n", - "def get_x_tandem_score(df: pd.DataFrame) -> np.ndarray:\n", - " b = df['hits_b'].astype('int').apply(lambda x: np.math.factorial(x)).values\n", - " y = df['hits_y'].astype('int').apply(lambda x: np.math.factorial(x)).values\n", - " x_tandem = np.log(b.astype('float')*y.astype('float')*df['fragments_matched_int_sum'].values)\n", - "\n", - " x_tandem[x_tandem==-np.inf] = 0\n", - "\n", - " return x_tandem\n", - "\n", - "class AlphaPeptReader(PSMReaderBase):\n", - " def __init__(self,\n", - " *,\n", - " column_mapping:dict = None,\n", - " modification_mapping:dict = None,\n", - " fdr = 0.01,\n", - " keep_decoy = False,\n", - " **kwargs,\n", - " ):\n", - " \"\"\"\n", - " Reading PSMs from alphapept's *.ms_data.hdf\n", - " \"\"\"\n", - " super().__init__(\n", - " column_mapping=column_mapping,\n", - " modification_mapping=modification_mapping,\n", - " fdr = fdr,\n", - " keep_decoy = keep_decoy,\n", - " **kwargs,\n", - " )\n", - " if fdr <= 0.1:\n", - " self.hdf_dataset = 'peptide_fdr'\n", - " else:\n", - " self.hdf_dataset = 'second_search'\n", - "\n", - " def _init_column_mapping(self):\n", - " self.column_mapping = psm_reader_yaml[\n", - " 'alphapept'\n", - " ]['column_mapping']\n", - "\n", - " def _init_modification_mapping(self):\n", - " self.modification_mapping = psm_reader_yaml[\n", - " 'alphapept'\n", - " ]['modification_mapping']\n", - "\n", - " def _load_file(self, filename):\n", - " with h5py.File(filename, 'r') as _hdf:\n", - " dataset = _hdf[self.hdf_dataset]\n", - " df = pd.DataFrame({col:dataset[col] for col in dataset.keys()})\n", - " df['raw_name'] = os.path.basename(filename)[:-len('.ms_data.hdf')]\n", - " df['precursor'] = df['precursor'].str.decode('utf-8')\n", - " #df['naked_sequence'] = df['naked_sequence'].str.decode('utf-8')\n", - " if 'scan_no' in df.columns:\n", - " df['scan_no'] = df['scan_no'].astype('int')\n", - " df['raw_idx'] = df['scan_no']-1 # if thermo, use scan-1 as spec_idx\n", - " df['charge'] = df['charge'].astype(int)\n", - "\n", - " if 'score' not in df.columns:\n", - " df['score'] = get_x_tandem_score(df)\n", - " return df\n", - " \n", - " def _load_modifications(self, df: pd.DataFrame):\n", - " (\n", - " self._psm_df['sequence'], self._psm_df['mods'],\n", - " self._psm_df['mod_sites'], _charges,\n", - " self._psm_df['decoy']\n", - " ) = zip(*df['precursor'].apply(parse_ap))\n", - " self._psm_df.decoy = self._psm_df.decoy.astype(np.int8)\n", - " \n", - "psm_reader_provider.register_reader('alphapept', AlphaPeptReader)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Column and modification mapping from alphabase to MaxQuant" + "from alphabase.psm_reader.alphapept_reader import *" ] }, { diff --git a/nbdev_nbs/psm_reader/dia_psm_reader.ipynb b/nbdev_nbs/psm_reader/dia_psm_reader.ipynb index bca7cc76..3cf3b794 100644 --- a/nbdev_nbs/psm_reader/dia_psm_reader.ipynb +++ b/nbdev_nbs/psm_reader/dia_psm_reader.ipynb @@ -6,7 +6,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| default_exp psm_reader.dia_psm_reader" + "#---#| default_exp psm_reader.dia_psm_reader" ] }, { @@ -36,122 +36,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| export\n", - "\n", - "import pandas as pd\n", - "import numpy as np\n", - "\n", - "from alphabase.psm_reader.psm_reader import (\n", - " psm_reader_provider, psm_reader_yaml\n", - ")\n", - "\n", - "from alphabase.psm_reader.maxquant_reader import (\n", - " MaxQuantReader\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "class SpectronautReader(MaxQuantReader):\n", - " \"\"\"Reader for Spectronaut's output library TSV/CSV.\n", - "\n", - " Other parameters, please see `MaxQuantReader` \n", - " in `alphabase.psm_reader.maxquant_reader`\n", - "\n", - " Parameters\n", - " ----------\n", - " csv_sep : str, optional\n", - " Delimiter for TSV/CSV, by default '\\t'\n", - " \"\"\"\n", - " def __init__(self,\n", - " *,\n", - " column_mapping:dict = None,\n", - " modification_mapping:dict = None,\n", - " fdr = 0.01,\n", - " keep_decoy = False,\n", - " mod_sep = '[]',\n", - " underscore_for_ncterm=True,\n", - " fixed_C57 = False,\n", - " mod_seq_columns=psm_reader_yaml[\n", - " 'spectronaut'\n", - " ]['mod_seq_columns'],\n", - " csv_sep = '\\t',\n", - " rt_unit = 'minute',\n", - " **kwargs,\n", - " ):\n", - " super().__init__(\n", - " column_mapping=column_mapping,\n", - " modification_mapping=modification_mapping,\n", - " fdr=fdr, keep_decoy=keep_decoy,\n", - " mod_sep=mod_sep,\n", - " underscore_for_ncterm=underscore_for_ncterm,\n", - " mod_seq_columns = mod_seq_columns,\n", - " fixed_C57=fixed_C57,\n", - " rt_unit=rt_unit,\n", - " **kwargs,\n", - " )\n", - " self.csv_sep = csv_sep\n", - "\n", - " self.mod_seq_column = 'ModifiedPeptide'\n", - "\n", - " self._min_max_rt_norm = True\n", - "\n", - " def _init_column_mapping(self):\n", - " self.column_mapping = psm_reader_yaml[\n", - " 'spectronaut'\n", - " ]['column_mapping']\n", - " \n", - " def _load_file(self, filename):\n", - " df = pd.read_csv(filename, sep=self.csv_sep)\n", - " self._find_mod_seq_column(df)\n", - " if 'ReferenceRun' in df.columns:\n", - " df.drop_duplicates([\n", - " 'ReferenceRun',self.mod_seq_column, 'PrecursorCharge'\n", - " ], inplace=True)\n", - " else:\n", - " df.drop_duplicates([\n", - " self.mod_seq_column, 'PrecursorCharge'\n", - " ], inplace=True)\n", - " df.reset_index(drop=True, inplace=True)\n", - " \n", - " return df\n", - "\n", - "class SwathReader(SpectronautReader):\n", - " def __init__(self,\n", - " *,\n", - " column_mapping:dict = None,\n", - " modification_mapping:dict = None,\n", - " fdr = 0.01,\n", - " keep_decoy = False,\n", - " mod_sep = '()',\n", - " underscore_for_ncterm=False,\n", - " fixed_C57 = False,\n", - " mod_seq_columns=psm_reader_yaml[\n", - " 'spectronaut'\n", - " ]['mod_seq_columns'],\n", - " csv_sep = '\\t',\n", - " **kwargs,\n", - " ):\n", - " \"\"\" \n", - " SWATH or OpenSWATH library, similar to `SpectronautReader`\n", - " \"\"\"\n", - " super().__init__(\n", - " column_mapping=column_mapping,\n", - " modification_mapping=modification_mapping,\n", - " fdr=fdr, keep_decoy=keep_decoy,\n", - " mod_sep=mod_sep,\n", - " underscore_for_ncterm=underscore_for_ncterm,\n", - " fixed_C57=fixed_C57,\n", - " mod_seq_columns=mod_seq_columns,\n", - " csv_sep=csv_sep,\n", - " **kwargs,\n", - " )" + "from alphabase.psm_reader.dia_psm_reader import *" ] }, { @@ -233,138 +118,6 @@ "psm_reader_yaml['spectronaut']['mod_seq_columns']" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "class DiannReader(SpectronautReader):\n", - " def __init__(self,\n", - " *,\n", - " column_mapping:dict = None,\n", - " modification_mapping:dict = None,\n", - " fdr = 0.01,\n", - " keep_decoy = False,\n", - " mod_sep = '()',\n", - " underscore_for_ncterm=False,\n", - " fixed_C57 = False,\n", - " csv_sep = '\\t',\n", - " rt_unit = 'minute',\n", - " **kwargs,\n", - " ):\n", - " \"\"\"\n", - " Also similar to `MaxQuantReader`, \n", - " but different in column_mapping and modificatin_mapping\n", - " \"\"\"\n", - " super().__init__(\n", - " column_mapping=column_mapping,\n", - " modification_mapping=modification_mapping,\n", - " fdr=fdr, keep_decoy=keep_decoy,\n", - " mod_sep=mod_sep,\n", - " underscore_for_ncterm=underscore_for_ncterm,\n", - " fixed_C57=fixed_C57,\n", - " csv_sep=csv_sep,\n", - " rt_unit=rt_unit,\n", - " **kwargs,\n", - " )\n", - " self.mod_seq_column = 'Modified.Sequence'\n", - " self._min_max_rt_norm = False\n", - "\n", - " def _init_column_mapping(self):\n", - " self.column_mapping = psm_reader_yaml[\n", - " 'diann'\n", - " ]['column_mapping']\n", - " \n", - " def _load_file(self, filename):\n", - " df = pd.read_csv(filename, sep=self.csv_sep)\n", - "\n", - " return df\n", - "\n", - "psm_reader_provider.register_reader(\n", - " 'spectronaut', SpectronautReader\n", - ")\n", - "psm_reader_provider.register_reader(\n", - " 'openswath', SwathReader\n", - ")\n", - "psm_reader_provider.register_reader(\n", - " 'swath', SwathReader\n", - ")\n", - "psm_reader_provider.register_reader(\n", - " 'diann', DiannReader\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "class SpectronautReportReader(MaxQuantReader):\n", - " \"\"\"Reader for Spectronaut's report TSV/CSV.\n", - "\n", - " Other parameters, please see `MaxQuantReader` \n", - " in `alphabase.psm_reader.maxquant_reader`\n", - "\n", - " Parameters\n", - " ----------\n", - " csv_sep : str, optional\n", - " Delimiter for TSV/CSV, by default ','\n", - " \"\"\"\n", - " def __init__(self,\n", - " *,\n", - " column_mapping:dict = None,\n", - " modification_mapping:dict = None,\n", - " fdr = 0.01,\n", - " keep_decoy = False,\n", - " mod_sep = '[]',\n", - " underscore_for_ncterm=True,\n", - " fixed_C57 = False,\n", - " csv_sep = ',',\n", - " rt_unit = 'minute',\n", - " **kwargs,\n", - " ):\n", - " super().__init__(\n", - " column_mapping=column_mapping,\n", - " modification_mapping=modification_mapping,\n", - " fdr=fdr, keep_decoy=keep_decoy,\n", - " mod_sep=mod_sep,\n", - " underscore_for_ncterm=underscore_for_ncterm,\n", - " fixed_C57=fixed_C57,\n", - " rt_unit=rt_unit,\n", - " **kwargs,\n", - " )\n", - " self.csv_sep = csv_sep\n", - "\n", - " self.precursor_column = 'EG.PrecursorId'\n", - "\n", - " self._min_max_rt_norm = False\n", - "\n", - " def _init_column_mapping(self):\n", - " self.column_mapping = psm_reader_yaml[\n", - " 'spectronaut_report'\n", - " ]['column_mapping']\n", - " \n", - " def _load_file(self, filename):\n", - " self.mod_seq_column = 'ModifiedSequence'\n", - " df = pd.read_csv(filename, sep=self.csv_sep)\n", - " df[[self.mod_seq_column,'charge']] = df[\n", - " self.precursor_column\n", - " ].str.split('.', expand=True, n=2)\n", - " df['charge'] = df.charge.astype(np.int8)\n", - " return df\n", - "\n", - "\n", - "psm_reader_provider.register_reader(\n", - " 'spectronaut_report', SpectronautReportReader\n", - ")\n" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -390,7 +143,8 @@ " 'uniprot_ids': 'Protein.Ids',\n", " 'genes': 'Genes',\n", " 'scan_num': 'MS2.Scan',\n", - " 'score': 'CScore'}" + " 'score': 'CScore',\n", + " 'fdr': 'Q.Value'}" ] }, "execution_count": null, @@ -756,6 +510,7 @@ " genes\n", " scan_num\n", " score\n", + " fdr\n", " spec_idx\n", " mods\n", " mod_sites\n", @@ -778,8 +533,9 @@ " MAPK1\n", " 11191\n", " 0.843331\n", + " 0.006937\n", " 11190\n", - " Acetyl@Protein N-term;Oxidation@M\n", + " Acetyl@Any N-term;Oxidation@M\n", " 0;12\n", " 14\n", " 0.372721\n", @@ -798,8 +554,9 @@ " MAPK1\n", " 11239\n", " 0.951820\n", + " 0.001225\n", " 11238\n", - " Acetyl@Protein N-term;Oxidation@M\n", + " Acetyl@Any N-term;Oxidation@M\n", " 0;12\n", " 14\n", " 0.374635\n", @@ -818,8 +575,9 @@ " SRRD\n", " 30053\n", " 0.999997\n", + " 0.000040\n", " 30052\n", - " Acetyl@Protein N-term\n", + " Acetyl@Any N-term\n", " 0\n", " 17\n", " 1.000000\n", @@ -838,8 +596,9 @@ " SRRD\n", " 30029\n", " 0.995505\n", + " 0.000184\n", " 30028\n", - " Acetyl@Protein N-term\n", + " Acetyl@Any N-term\n", " 0\n", " 17\n", " 1.000000\n", @@ -858,8 +617,9 @@ " SRRD\n", " 30005\n", " 0.997286\n", + " 0.000185\n", " 30004\n", - " Acetyl@Protein N-term\n", + " Acetyl@Any N-term\n", " 0\n", " 17\n", " 1.000000\n", @@ -878,8 +638,9 @@ " SRRD\n", " 29981\n", " 0.996593\n", + " 0.000153\n", " 29980\n", - " Acetyl@Protein N-term\n", + " Acetyl@Any N-term\n", " 0\n", " 17\n", " 1.000000\n", @@ -898,8 +659,9 @@ " IPO9\n", " 22187\n", " 0.999999\n", + " 0.000040\n", " 22186\n", - " Acetyl@Protein N-term\n", + " Acetyl@Any N-term\n", " 0\n", " 21\n", " 0.738374\n", @@ -918,8 +680,9 @@ " IPO9\n", " 22091\n", " 0.999996\n", + " 0.000050\n", " 22090\n", - " Acetyl@Protein N-term\n", + " Acetyl@Any N-term\n", " 0\n", " 21\n", " 0.735775\n", @@ -938,8 +701,9 @@ " IPO9\n", " 22067\n", " 0.999999\n", + " 0.000061\n", " 22066\n", - " Acetyl@Protein N-term\n", + " Acetyl@Any N-term\n", " 0\n", " 21\n", " 0.735576\n", @@ -958,8 +722,9 @@ " IPO9\n", " 21947\n", " 0.999997\n", + " 0.000044\n", " 21946\n", - " Acetyl@Protein N-term\n", + " Acetyl@Any N-term\n", " 0\n", " 21\n", " 0.732136\n", @@ -978,6 +743,7 @@ " MECP2\n", " 11077\n", " 0.998266\n", + " 0.000142\n", " 11076\n", " \n", " \n", @@ -998,6 +764,7 @@ " MECP2\n", " 11029\n", " 0.994097\n", + " 0.000201\n", " 11028\n", " \n", " \n", @@ -1018,6 +785,7 @@ " MECP2\n", " 10981\n", " 0.999939\n", + " 0.000070\n", " 10980\n", " \n", " \n", @@ -1038,6 +806,7 @@ " MECP2\n", " 10957\n", " 0.971834\n", + " 0.000604\n", " 10956\n", " \n", " \n", @@ -1083,37 +852,53 @@ "12 AAAAAAAPSGGGGGGEEERLEEK 3 7.28562 1.01500 NaN P51608-2 \n", "13 AAAAAAAPSGGGGGGEEERLEEK 3 7.26825 1.01208 NaN P51608-2 \n", "\n", - " genes scan_num score spec_idx mods \\\n", - "0 MAPK1 11191 0.843331 11190 Acetyl@Protein N-term;Oxidation@M \n", - "1 MAPK1 11239 0.951820 11238 Acetyl@Protein N-term;Oxidation@M \n", - "2 SRRD 30053 0.999997 30052 Acetyl@Protein N-term \n", - "3 SRRD 30029 0.995505 30028 Acetyl@Protein N-term \n", - "4 SRRD 30005 0.997286 30004 Acetyl@Protein N-term \n", - "5 SRRD 29981 0.996593 29980 Acetyl@Protein N-term \n", - "6 IPO9 22187 0.999999 22186 Acetyl@Protein N-term \n", - "7 IPO9 22091 0.999996 22090 Acetyl@Protein N-term \n", - "8 IPO9 22067 0.999999 22066 Acetyl@Protein N-term \n", - "9 IPO9 21947 0.999997 21946 Acetyl@Protein N-term \n", - "10 MECP2 11077 0.998266 11076 \n", - "11 MECP2 11029 0.994097 11028 \n", - "12 MECP2 10981 0.999939 10980 \n", - "13 MECP2 10957 0.971834 10956 \n", + " genes scan_num score fdr spec_idx \\\n", + "0 MAPK1 11191 0.843331 0.006937 11190 \n", + "1 MAPK1 11239 0.951820 0.001225 11238 \n", + "2 SRRD 30053 0.999997 0.000040 30052 \n", + "3 SRRD 30029 0.995505 0.000184 30028 \n", + "4 SRRD 30005 0.997286 0.000185 30004 \n", + "5 SRRD 29981 0.996593 0.000153 29980 \n", + "6 IPO9 22187 0.999999 0.000040 22186 \n", + "7 IPO9 22091 0.999996 0.000050 22090 \n", + "8 IPO9 22067 0.999999 0.000061 22066 \n", + "9 IPO9 21947 0.999997 0.000044 21946 \n", + "10 MECP2 11077 0.998266 0.000142 11076 \n", + "11 MECP2 11029 0.994097 0.000201 11028 \n", + "12 MECP2 10981 0.999939 0.000070 10980 \n", + "13 MECP2 10957 0.971834 0.000604 10956 \n", + "\n", + " mods mod_sites nAA rt_norm precursor_mz \\\n", + "0 Acetyl@Any N-term;Oxidation@M 0;12 14 0.372721 650.819344 \n", + "1 Acetyl@Any N-term;Oxidation@M 0;12 14 0.374635 650.819344 \n", + "2 Acetyl@Any N-term 0 17 1.000000 834.428635 \n", + "3 Acetyl@Any N-term 0 17 1.000000 834.428635 \n", + "4 Acetyl@Any N-term 0 17 1.000000 834.428635 \n", + "5 Acetyl@Any N-term 0 17 1.000000 834.428635 \n", + "6 Acetyl@Any N-term 0 21 0.738374 895.991600 \n", + "7 Acetyl@Any N-term 0 21 0.735775 895.991600 \n", + "8 Acetyl@Any N-term 0 21 0.735576 895.991600 \n", + "9 Acetyl@Any N-term 0 21 0.732136 895.991600 \n", + "10 23 0.368908 695.666290 \n", + "11 23 0.367626 695.666290 \n", + "12 23 0.366309 695.666290 \n", + "13 23 0.365753 695.666290 \n", "\n", - " mod_sites nAA rt_norm precursor_mz ccs \n", - "0 0;12 14 0.372721 650.819344 412.544080 \n", - "1 0;12 14 0.374635 650.819344 411.961191 \n", - "2 0 17 1.000000 834.428635 483.435307 \n", - "3 0 17 1.000000 834.428635 482.595308 \n", - "4 0 17 1.000000 834.428635 482.227809 \n", - "5 0 17 1.000000 834.428635 481.125311 \n", - "6 0 21 0.738374 895.991600 494.430146 \n", - "7 0 21 0.735775 895.991600 492.581583 \n", - "8 0 21 0.735576 895.991600 495.269668 \n", - "9 0 21 0.732136 895.991600 495.439187 \n", - "10 23 0.368908 695.666290 610.813640 \n", - "11 23 0.367626 695.666290 613.335514 \n", - "12 23 0.366309 695.666290 613.837470 \n", - "13 23 0.365753 695.666290 612.071553 " + " ccs \n", + "0 412.544080 \n", + "1 411.961191 \n", + "2 483.435307 \n", + "3 482.595308 \n", + "4 482.227809 \n", + "5 481.125311 \n", + "6 494.430146 \n", + "7 492.581583 \n", + "8 495.269668 \n", + "9 495.439187 \n", + "10 610.813640 \n", + "11 613.335514 \n", + "12 613.837470 \n", + "13 612.071553 " ] }, "execution_count": null, @@ -1142,16 +927,16 @@ "_df = diann_reader.import_file(tsv)\n", "assert 'ccs' in diann_reader.psm_df.columns\n", "assert len(diann_reader.psm_df) == 14\n", - "assert np.sum(diann_reader.psm_df.mods.str.contains('Acetyl@Protein N-term')) == 10\n", - "assert np.sum(~diann_reader.psm_df.mods.str.contains('Acetyl@Protein N-term')) == 4\n", + "assert np.sum(diann_reader.psm_df.mods.str.contains('Acetyl@Protein N-term')|diann_reader.psm_df.mods.str.contains('Acetyl@Any N-term')) == 10\n", + "assert np.sum(~diann_reader.psm_df.mods.str.contains('Acetyl@Protein N-term')&~diann_reader.psm_df.mods.str.contains('Acetyl@Any N-term')) == 4\n", "assert np.sum(diann_reader.psm_df.mods.str.contains('Oxidation@M')) == 2\n", "assert np.all(np.array(diann_reader.modification_mapping['Phospho@S'])==np.array([\n", " 'S(Phospho (S))',\n", " 'S(Phospho (ST))',\n", " 'S(Phospho (STY))',\n", " 'S(ph)',\n", - " 'S(UniMod:21)',\n", " 'pS',\n", + " 'S(UniMod:21)',\n", " 'S[Phospho (S)]',\n", " 'S[Phospho (ST)]',\n", " 'S[Phospho (STY)]',\n", @@ -1188,16 +973,16 @@ "\n", "assert 'ccs' in diann_reader.psm_df.columns\n", "assert len(diann_reader.psm_df) == 14\n", - "assert np.sum(diann_reader.psm_df.mods.str.contains('Acetyl@Protein N-term')) == 10\n", - "assert np.sum(~diann_reader.psm_df.mods.str.contains('Acetyl@Protein N-term')) == 4\n", + "assert np.sum(diann_reader.psm_df.mods.str.contains('Acetyl@Any N-term')) == 10\n", + "assert np.sum(~diann_reader.psm_df.mods.str.contains('Acetyl@Any N-term')) == 4\n", "assert np.sum(diann_reader.psm_df.mods.str.contains('Oxidation@M')) == 2\n", "assert np.all(np.array(diann_reader.modification_mapping['Phospho@S'])==np.array([\n", " 'S(Phospho (S))',\n", " 'S(Phospho (ST))',\n", " 'S(Phospho (STY))',\n", " 'S(ph)',\n", - " 'S(UniMod:21)',\n", " 'pS',\n", + " 'S(UniMod:21)',\n", " 'S[Phospho (S)]',\n", " 'S[Phospho (ST)]',\n", " 'S[Phospho (STY)]',\n", @@ -1206,6 +991,26 @@ ")" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Acetyl@Any N-term'" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "diann_reader.rev_mod_mapping['(UniMod:1)']" + ] + }, { "cell_type": "code", "execution_count": null, diff --git a/nbdev_nbs/psm_reader/maxquant_reader.ipynb b/nbdev_nbs/psm_reader/maxquant_reader.ipynb index 010f0d6e..81d3c7be 100644 --- a/nbdev_nbs/psm_reader/maxquant_reader.ipynb +++ b/nbdev_nbs/psm_reader/maxquant_reader.ipynb @@ -6,7 +6,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| default_exp psm_reader.maxquant_reader" + "#---#| default_exp psm_reader.maxquant_reader" ] }, { @@ -22,235 +22,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| export\n", - "import pandas as pd\n", - "import numpy as np\n", - "import numba\n", - "import copy\n", - "\n", - "from alphabase.psm_reader.psm_reader import (\n", - " PSMReaderBase, psm_reader_provider,\n", - " psm_reader_yaml\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "@numba.njit\n", - "def parse_mod_seq(\n", - " modseq:str,\n", - " mod_sep:str='()',\n", - " fixed_C57:bool=True,\n", - " underscore_for_ncterm:bool=True,\n", - ")->tuple:\n", - " \"\"\"Extract modifications and sites from the modified sequence (modseq)\n", - "\n", - " Parameters\n", - " ----------\n", - " modseq : str\n", - " modified sequence to extract modifications.\n", - "\n", - " mod_sep : str, optional\n", - " separator to indicate the modification section. \n", - " Defaults to '()'\n", - "\n", - " fixed_C : bool\n", - " If Carbamidomethyl@C is a fixed modification \n", - " and not displayed in the sequence. Defaults to True for MaxQuant.\n", - "\n", - " underscore_for_ncterm : bool\n", - " If modseq starts and ends with underscores. \n", - " Defaults to True.\n", - "\n", - " Returns\n", - " -------\n", - " tuple\n", - " str: modification names, separated by ';'\n", - " \n", - " str: modification sites, separated by ';'. \n", - " 0 for N-term; -1 for C-term; 1 to N for normal modifications.\n", - " \"\"\"\n", - " PeptideModSeq = modseq\n", - " mod_list = []\n", - " site_list = []\n", - " site = PeptideModSeq.find(mod_sep[0])\n", - " while site != -1:\n", - " site_end = PeptideModSeq.find(mod_sep[1],site+1)+1\n", - " if site_end < len(PeptideModSeq) and PeptideModSeq[site_end] == mod_sep[1]: \n", - " site_end += 1\n", - " if underscore_for_ncterm: site_list.append(site-1)\n", - " else: site_list.append(site)\n", - " start_mod = site\n", - " if start_mod > 0: start_mod -= 1\n", - " mod_list.append(PeptideModSeq[start_mod:site_end])\n", - " PeptideModSeq = PeptideModSeq[:site] + PeptideModSeq[site_end:]\n", - " site = PeptideModSeq.find(mod_sep[0], site)\n", - "\n", - " # patch for phos. How many other modification formats does MQ have?\n", - " site = PeptideModSeq.find('p') \n", - " while site != -1:\n", - " mod_list.append(PeptideModSeq[site:site+2])\n", - " site_list = [i-1 if i > site else i for i in site_list]\n", - " if underscore_for_ncterm: site_list.append(site)\n", - " else: site_list.append(site+1)\n", - " PeptideModSeq = PeptideModSeq[:site] + PeptideModSeq[site+1:]\n", - " site = PeptideModSeq.find('p', site)\n", - " \n", - " if fixed_C57:\n", - " site = PeptideModSeq.find('C')\n", - " while site != -1:\n", - " if underscore_for_ncterm: site_list.append(site)\n", - " else: site_list.append(site+1)\n", - " mod_list.append('C'+\"Carbamidomethyl (C)\".join(mod_sep))\n", - " site = PeptideModSeq.find('C',site+1)\n", - " sequence = PeptideModSeq.strip('_')\n", - " nAA = len(sequence)\n", - " return sequence, ';'.join(mod_list), ';'.join([str(i) if i <= nAA else '-1' for i in site_list])\n", - "\n", - "\n", - "class MaxQuantReader(PSMReaderBase):\n", - " def __init__(self,\n", - " *,\n", - " column_mapping:dict = None,\n", - " modification_mapping:dict = None,\n", - " fdr = 0.01,\n", - " keep_decoy = False,\n", - " mod_sep = '()',\n", - " underscore_for_ncterm=True,\n", - " fixed_C57 = True,\n", - " mod_seq_columns = ['Modified sequence'],\n", - " **kwargs,\n", - " ):\n", - " \"\"\"Reader for MaxQuant msms.txt and evidence.txt\n", - "\n", - " Parameters\n", - " ----------\n", - " column_mapping : dict, optional\n", - " By default None. If None, use \n", - " `psm_reader_yaml['maxquant']['column_mapping']` \n", - " (alphabase.psm_reader.psm_reader_yaml).\n", - "\n", - " modification_mapping : dict, optional\n", - " By default None. If None, use \n", - " `psm_reader_yaml['maxquant']['modification_mapping']` \n", - " (alphabase.psm_reader.psm_reader_yaml).\n", - "\n", - " fdr : float, optional\n", - " Load PSMs with FDR < this fdr, by default 0.01\n", - "\n", - " keep_decoy : bool, optional\n", - " If keep decoy PSMs, by default False\n", - "\n", - " mod_sep : str, optional\n", - " Symbols to separate modified sequences,\n", - " e.g. `AM(Oxidation)PIC(+57)QMK`.\n", - " By default '()'\n", - "\n", - " underscore_for_ncterm : bool, optional\n", - " If search engine uses an under score in N- and C-term, \n", - " `_(Acetyl)AM(Oxidation)PIC(+57)QMK_`.\n", - " by default True\n", - "\n", - " fixed_C57 : bool, optional\n", - " If true, the search engine will not show `Carbamidomethyl`\n", - " in the modified sequences. \n", - " by default True\n", - "\n", - " mod_seq_columns : list, optional\n", - " The columns to find modified sequences, \n", - " by default ['Modified sequence']\n", - " \"\"\"\n", - " super().__init__(\n", - " column_mapping=column_mapping,\n", - " modification_mapping=modification_mapping,\n", - " fdr = fdr,\n", - " keep_decoy = keep_decoy,\n", - " **kwargs,\n", - " )\n", - "\n", - " self.mod_sep = mod_sep\n", - " self.underscore_for_ncterm = underscore_for_ncterm\n", - " self.fixed_C57 = fixed_C57\n", - " self._mod_seq_columns = mod_seq_columns\n", - " self.mod_seq_column = 'Modified sequence'\n", - "\n", - " def _find_mod_seq_column(self, df):\n", - " for mod_seq_col in self._mod_seq_columns:\n", - " if mod_seq_col in df.columns:\n", - " self.mod_seq_column = mod_seq_col\n", - " break\n", - " \n", - " def _init_modification_mapping(self):\n", - " self.modification_mapping = copy.deepcopy(\n", - " # otherwise maxquant reader will modify the dict inplace\n", - " psm_reader_yaml['maxquant'][\n", - " 'modification_mapping'\n", - " ]\n", - " ) \n", - "\n", - " def set_modification_mapping(self, modification_mapping: dict):\n", - " super().set_modification_mapping(modification_mapping)\n", - " self._extend_mod_brackets()\n", - " self._reverse_mod_mapping()\n", - "\n", - " def _extend_mod_brackets(self):\n", - " for key, mod_list in list(self.modification_mapping.items()):\n", - " extend_mods = []\n", - " for mod in mod_list:\n", - " if mod[1] == '(':\n", - " extend_mods.append(f'{mod[0]}[{mod[2:-1]}]')\n", - " elif mod[1] == '[':\n", - " extend_mods.append(f'{mod[0]}({mod[2:-1]})')\n", - "\n", - " self.modification_mapping[key].extend(extend_mods)\n", - " \n", - " self.modification_mapping[key].extend(\n", - " [f'{mod[1:]}' for mod in mod_list if mod.startswith('_')]\n", - " )\n", - " \n", - " def _translate_decoy(self, origin_df=None):\n", - " if 'decoy' in self._psm_df.columns:\n", - " self._psm_df.decoy = (\n", - " self._psm_df.decoy == '-'\n", - " ).astype(np.int8)\n", - "\n", - " def _init_column_mapping(self):\n", - " self.column_mapping = psm_reader_yaml[\n", - " 'maxquant'\n", - " ]['column_mapping']\n", - "\n", - " def _load_file(self, filename):\n", - " df = pd.read_csv(filename, sep='\\t')\n", - " self._find_mod_seq_column(df)\n", - " df = df[~pd.isna(df['Retention time'])]\n", - " df.fillna('', inplace=True)\n", - " # if 'K0' in df.columns:\n", - " # df['Mobility'] = df['K0'] # Bug in MaxQuant? It should be 1/K0\n", - " # min_rt = df['Retention time'].min()\n", - " return df\n", - "\n", - " def _load_modifications(self, origin_df: pd.DataFrame):\n", - " (\n", - " seqs,\n", - " self._psm_df['mods'], \n", - " self._psm_df['mod_sites']\n", - " ) = zip(\n", - " *origin_df[self.mod_seq_column].apply(\n", - " parse_mod_seq, mod_sep=self.mod_sep,\n", - " fixed_C57=self.fixed_C57,\n", - " underscore_for_ncterm=self.underscore_for_ncterm\n", - " )\n", - " )\n", - " if 'sequence' not in self._psm_df.columns:\n", - " self._psm_df['sequence'] = seqs\n", - "\n", - "psm_reader_provider.register_reader('maxquant', MaxQuantReader)" + "from alphabase.psm_reader.maxquant_reader import *" ] }, { @@ -279,7 +51,8 @@ " 'score': 'Score',\n", " 'proteins': 'Proteins',\n", " 'genes': ['Gene Names', 'Gene names'],\n", - " 'decoy': 'Reverse'}" + " 'decoy': 'Reverse',\n", + " 'intensity': 'Intensity'}" ] }, "execution_count": null, @@ -299,28 +72,20 @@ { "data": { "text/plain": [ - "{'Acetyl@Protein N-term': ['_(Acetyl (Protein N-term))',\n", - " '_(ac)',\n", - " '_(UniMod:1)'],\n", - " 'Carbamidomethyl@C': ['C(Carbamidomethyl (C))', 'C(UniMod:4)'],\n", - " 'Oxidation@M': ['M(Oxidation (M))', 'M(ox)', 'M(UniMod:35)'],\n", + "{'Acetyl@Protein N-term': ['_(Acetyl (Protein N-term))', '_(ac)'],\n", + " 'Carbamidomethyl@C': ['C(Carbamidomethyl (C))'],\n", + " 'Oxidation@M': ['M(Oxidation (M))', 'M(ox)'],\n", " 'Phospho@S': ['S(Phospho (S))',\n", " 'S(Phospho (ST))',\n", " 'S(Phospho (STY))',\n", " 'S(ph)',\n", - " 'S(UniMod:21)',\n", " 'pS'],\n", " 'Phospho@T': ['T(Phospho (T))',\n", " 'T(Phospho (ST))',\n", " 'T(Phospho (STY))',\n", " 'T(ph)',\n", - " 'T(UniMod:21)',\n", " 'pT'],\n", - " 'Phospho@Y': ['Y(Phospho (Y))',\n", - " 'Y(Phospho (STY))',\n", - " 'Y(ph)',\n", - " 'Y(UniMod:21)',\n", - " 'pY'],\n", + " 'Phospho@Y': ['Y(Phospho (Y))', 'Y(Phospho (STY))', 'Y(ph)', 'pY'],\n", " 'Deamidated@N': ['N(Deamidation (NQ))', 'N(de)'],\n", " 'Deamidated@Q': ['Q(Deamidation (NQ))', 'Q(de)'],\n", " 'GlyGly@K': ['K(GlyGly (K))', 'K(gl)']}" @@ -345,7 +110,7 @@ "assert ('HAESVMTMGLK','M(ox);M(ox);_(x@Cterm)', '6;8;-1') == parse_mod_seq(\"_HAESVM(ox)TM(ox)GLK_(x@Cterm)\")\n", "assert ('HAESVMTMGLK','M(ox);M(ox);pS;pT', '6;8;4;7') == parse_mod_seq(\"_HAEpSVM(ox)pTM(ox)GLK_\")\n", "assert ('HAESVHTGLK','pS;pT', '4;7') == parse_mod_seq(\"_HAEpSVHpTGLK_\")\n", - "assert ('HAESVHTGLK','pS;pT', '4;7') == parse_mod_seq(\"HAEpSVHpTGLK\", underscore_for_ncterm=False)\n", + "assert ('HAESVHTGLK','pS;pT', '4;7') == parse_mod_seq(\"HAEpSVHpTGLK\")\n", "assert ('HAEMVHTGLK','M(Oxidation (M))', '4') == parse_mod_seq(\"_HAEM(Oxidation (M))VHTGLK_\")\n", "assert ('ACLDYPVTSVLPPASLMK','C(Cys-Cys);M(Oxidation (M));C(Carbamidomethyl (C))', '2;17;2') == parse_mod_seq(\"_AC(Cys-Cys)LDYPVTSVLPPASLM(Oxidation (M))K_\")\n", "assert ('VSHGSSPSLLEALSSDFLACK','_(Acetyl (N-term));C(Carbamidomethyl (C))', '0;20') == parse_mod_seq(\"_(Acetyl (N-term))VSHGSSPSLLEALSSDFLAC(Carbamidomethyl (C))K_\", fixed_C57=False)\n", @@ -356,10 +121,10 @@ "assert ('VSHGSSPSLLEALSSDFLACK','_[Acetyl (N-term)];C[Carbamidomethyl (C)]', '0;20') == parse_mod_seq(\"_[Acetyl (N-term)]VSHGSSPSLLEALSSDFLAC[Carbamidomethyl (C)]K_\", fixed_C57=False, mod_sep='[]')\n", "assert ('VSHGSSPSLLEALSSDFLACK','_[Acetyl (N-term)];C[Carbamidomethyl (C)];C[Carbamidomethyl (C)]', '0;20;20') == parse_mod_seq(\"_[Acetyl (N-term)]VSHGSSPSLLEALSSDFLAC[Carbamidomethyl (C)]K_\", fixed_C57=True, mod_sep='[]')\n", "assert ('EKPLLEKSHCIC','E[Glu->pyro-Glu];C[Carbamidomethyl (C)];C[Carbamidomethyl (C)]', '1;10;12') == parse_mod_seq(\"_E[Glu->pyro-Glu]KPLLEKSHCIC_\", fixed_C57=True, mod_sep='[]')\n", - "assert ('HAEMVHTGLK','M(UniMod:35)', '4') == parse_mod_seq(\"HAEM(UniMod:35)VHTGLK\",underscore_for_ncterm=False)\n", - "assert ('VSHGSSPSLLEALSSDFLACK','C(UniMod:4);C(Carbamidomethyl (C))', '20;20') == parse_mod_seq(\"VSHGSSPSLLEALSSDFLAC(UniMod:4)K\",fixed_C57=True, underscore_for_ncterm=False)\n", - "assert ('VSHGSSPSLLEALSSDFLACK','C(UniMod:4)', '20') == parse_mod_seq(\"VSHGSSPSLLEALSSDFLAC(UniMod:4)K\",fixed_C57=False, underscore_for_ncterm=False)\n", - "assert ('AAAAAAGAGPEMVR','(UniMod:1);M(UniMod:35)','0;12') == parse_mod_seq('(UniMod:1)AAAAAAGAGPEM(UniMod:35)VR', underscore_for_ncterm=False)" + "assert ('HAEMVHTGLK','M(UniMod:35)', '4') == parse_mod_seq(\"HAEM(UniMod:35)VHTGLK\")\n", + "assert ('VSHGSSPSLLEALSSDFLACK','C(UniMod:4);C(Carbamidomethyl (C))', '20;20') == parse_mod_seq(\"VSHGSSPSLLEALSSDFLAC(UniMod:4)K\",fixed_C57=True)\n", + "assert ('VSHGSSPSLLEALSSDFLACK','C(UniMod:4)', '20') == parse_mod_seq(\"VSHGSSPSLLEALSSDFLAC(UniMod:4)K\",fixed_C57=False)\n", + "assert ('AAAAAAGAGPEMVR','(UniMod:1);M(UniMod:35)','0;12') == parse_mod_seq('(UniMod:1)AAAAAAGAGPEM(UniMod:35)VR')" ] }, { @@ -523,14 +288,14 @@ " 'S(Phospho (ST))',\n", " 'S(Phospho (STY))',\n", " 'S(ph)',\n", - " 'S(UniMod:21)',\n", " 'pS',\n", + " 'S(UniMod:21)',\n", " 'S[Phospho (S)]',\n", " 'S[Phospho (ST)]',\n", " 'S[Phospho (STY)]',\n", " 'S[ph]',\n", " 'S[UniMod:21]'])\n", - ")\n", + "), mq_reader.modification_mapping['Phospho@S']\n", "mq_reader.psm_df" ] }, diff --git a/nbdev_nbs/psm_reader/msfragger_reader.ipynb b/nbdev_nbs/psm_reader/msfragger_reader.ipynb index d149b365..15ebf595 100644 --- a/nbdev_nbs/psm_reader/msfragger_reader.ipynb +++ b/nbdev_nbs/psm_reader/msfragger_reader.ipynb @@ -6,7 +6,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| default_exp psm_reader.msfragger_reader" + "#---#| default_exp psm_reader.msfragger_reader" ] }, { @@ -22,24 +22,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| export\n", - "\n", - "import numpy as np\n", - "import pandas as pd\n", - "\n", - "from alphabase.psm_reader.psm_reader import (\n", - " PSMReaderBase, psm_reader_yaml,\n", - " psm_reader_provider\n", - ")\n", - "from alphabase.psm_reader.maxquant_reader import MaxQuantReader\n", - "from alphabase.constants.aa import AA_ASCII_MASS\n", - "from alphabase.constants.modification import MOD_INFO_DICT as mod_info\n", - "\n", - "#| export\n", - "try:\n", - " import pyteomics.pepxml as pepxml\n", - "except:\n", - " pepxml = None\n" + "from alphabase.psm_reader.msfragger_reader import *" ] }, { @@ -48,798 +31,269 @@ "metadata": {}, "outputs": [], "source": [ - "#| export\n", - "\n", - "def _is_fragger_decoy(proteins):\n", - " for prot in proteins:\n", - " if not prot.startswith('rev_'):\n", - " return False\n", - " return True\n", - "\n", - "mass_mapped_mods = psm_reader_yaml['msfragger_pepxml']['mass_mapped_mods']\n", - "mod_mass_tol = psm_reader_yaml['msfragger_pepxml']['mod_mass_tol']\n", - "\n", - "def _get_msf_mods(sequence, msf_aa_mods):\n", - " mods = []\n", - " mod_sites = []\n", - " mod_deltas = []\n", - " mod_delta_sites = []\n", - " for mod in msf_aa_mods:\n", - " mod_mass, site_str = mod.split('@')\n", - " mod_mass = float(mod_mass)\n", - " site = int(site_str)-1\n", - " mod_mass = mod_mass - AA_ASCII_MASS[ord(sequence[site])]\n", - "\n", - " mod_considered = False\n", - " for mod_name in mass_mapped_mods:\n", - " if abs(mod_mass-mod_info[mod_name]['mass'])\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
sequencechargertquery_idspec_idxscoreproteinsraw_namedecoymodsmod_sitesmod_deltasmod_delta_sitesnAArt_normprecursor_mz
0HDYKPAT28.60669820190627_QX0_AnBr_SA_BPP_DDA_M01_02.2674.2674.22674-1.913190rev_sp|Q71H61|ILDR2_HUMAN Immunoglobulin-like ...20190627_QX0_AnBr_SA_BPP_DDA_M01_02170.072516416.203410
1FPSPGPP28.62142320190627_QX0_AnBr_SA_BPP_DDA_M01_02.2685.2685.22685-2.084439sp|Q9H3S7|PTN23_HUMAN Tyrosine-protein phospha...20190627_QX0_AnBr_SA_BPP_DDA_M01_02070.072640349.679040
2IGEAGWVP28.60611120190627_QX0_AnBr_SA_BPP_DDA_M01_02.2673.2673.22673-1.108953rev_sp|Q76N32|CEP68_HUMAN Centrosomal protein ...20190627_QX0_AnBr_SA_BPP_DDA_M01_02180.072511414.716153
3VAAMVIDH28.61733020190627_QX0_AnBr_SA_BPP_DDA_M01_02.2682.2682.22682-1.480048sp|Q9UN73|PCDA6_HUMAN Protocadherin alpha-6 OS...20190627_QX0_AnBr_SA_BPP_DDA_M01_02080.072606428.223288
4EPDSPLDKL31.39424920190627_QX0_AnBr_SA_BPP_DDA_M01_02.426.426.3426-0.340774rev_sp|O60566|BUB1B_HUMAN Mitotic checkpoint s...20190627_QX0_AnBr_SA_BPP_DDA_M01_021Glu->pyro-Glu@E^Any N-term090.011747332.506319
5ALSSQHQAR35.57091520190627_QX0_AnBr_SA_BPP_DDA_M01_02.1717.1717.31717-0.673023sp|P11021|BIP_HUMAN Endoplasmic reticulum chap...20190627_QX0_AnBr_SA_BPP_DDA_M01_02090.046938333.177307
6EFGVSPDKI38.61323420190627_QX0_AnBr_SA_BPP_DDA_M01_02.2679.2679.32679-1.969079sp|P26640|SYVC_HUMAN Valine--tRNA ligase OS=Ho...20190627_QX0_AnBr_SA_BPP_DDA_M01_02090.072571331.174680
7TAMEIIMCGLAW38.60763720190627_QX0_AnBr_SA_BPP_DDA_M01_02.2675.2675.32675-0.929250rev_sp|Q8IVW4|CDKL3_HUMAN Cyclin-dependent kin...20190627_QX0_AnBr_SA_BPP_DDA_M01_021Oxidation@M3119.003815040450018120.072524491.879582
8QEGDMDRSLHKP48.61082520190627_QX0_AnBr_SA_BPP_DDA_M01_02.2677.2677.42677-0.543173rev_sp|A8K0R7|ZN839_HUMAN Zinc finger protein ...20190627_QX0_AnBr_SA_BPP_DDA_M01_021Oxidation@M5120.072551357.918858
9YTETDLEESMDKI48.60935620190627_QX0_AnBr_SA_BPP_DDA_M01_02.2676.2676.42676-1.509287sp|Q9UKF6|CPSF3_HUMAN Cleavage and polyadenyla...20190627_QX0_AnBr_SA_BPP_DDA_M01_020Oxidation@M10130.072539398.177635
10TVCHQLFFSGFVSP48.61264420190627_QX0_AnBr_SA_BPP_DDA_M01_02.2678.2678.42678-2.015136rev_sp|P42704|LPPRC_HUMAN Leucine-rich PPR mot...20190627_QX0_AnBr_SA_BPP_DDA_M01_021119.003815040450013140.072566422.695564
11EGATIEMSAPNKSDEPK38.61550020190627_QX0_AnBr_SA_BPP_DDA_M01_02.2680.2680.326800.545963rev_sp|O14513|NCKP5_HUMAN Nck-associated prote...20190627_QX0_AnBr_SA_BPP_DDA_M01_021170.072591601.952491
12AGPSCGTYDMCEDTEADMLGPPGQ2118.68627920190627_QX0_AnBr_SA_BPP_DDA_M01_02.57903.57903.257903-0.519306rev_sp|Q86V15|CASZ1_HUMAN Zinc finger protein ...20190627_QX0_AnBr_SA_BPP_DDA_M01_021Oxidation@M10119.003815040450015241.0000001290.470466
\n", - "" - ], - "text/plain": [ - " sequence charge rt \\\n", - "0 HDYKPAT 2 8.606698 \n", - "1 FPSPGPP 2 8.621423 \n", - "2 IGEAGWVP 2 8.606111 \n", - "3 VAAMVIDH 2 8.617330 \n", - "4 EPDSPLDKL 3 1.394249 \n", - "5 ALSSQHQAR 3 5.570915 \n", - "6 EFGVSPDKI 3 8.613234 \n", - "7 TAMEIIMCGLAW 3 8.607637 \n", - "8 QEGDMDRSLHKP 4 8.610825 \n", - "9 YTETDLEESMDKI 4 8.609356 \n", - "10 TVCHQLFFSGFVSP 4 8.612644 \n", - "11 EGATIEMSAPNKSDEPK 3 8.615500 \n", - "12 AGPSCGTYDMCEDTEADMLGPPGQ 2 118.686279 \n", - "\n", - " query_id spec_idx score \\\n", - "0 20190627_QX0_AnBr_SA_BPP_DDA_M01_02.2674.2674.2 2674 -1.913190 \n", - "1 20190627_QX0_AnBr_SA_BPP_DDA_M01_02.2685.2685.2 2685 -2.084439 \n", - "2 20190627_QX0_AnBr_SA_BPP_DDA_M01_02.2673.2673.2 2673 -1.108953 \n", - "3 20190627_QX0_AnBr_SA_BPP_DDA_M01_02.2682.2682.2 2682 -1.480048 \n", - "4 20190627_QX0_AnBr_SA_BPP_DDA_M01_02.426.426.3 426 -0.340774 \n", - "5 20190627_QX0_AnBr_SA_BPP_DDA_M01_02.1717.1717.3 1717 -0.673023 \n", - "6 20190627_QX0_AnBr_SA_BPP_DDA_M01_02.2679.2679.3 2679 -1.969079 \n", - "7 20190627_QX0_AnBr_SA_BPP_DDA_M01_02.2675.2675.3 2675 -0.929250 \n", - "8 20190627_QX0_AnBr_SA_BPP_DDA_M01_02.2677.2677.4 2677 -0.543173 \n", - "9 20190627_QX0_AnBr_SA_BPP_DDA_M01_02.2676.2676.4 2676 -1.509287 \n", - "10 20190627_QX0_AnBr_SA_BPP_DDA_M01_02.2678.2678.4 2678 -2.015136 \n", - "11 20190627_QX0_AnBr_SA_BPP_DDA_M01_02.2680.2680.3 2680 0.545963 \n", - "12 20190627_QX0_AnBr_SA_BPP_DDA_M01_02.57903.57903.2 57903 -0.519306 \n", - "\n", - " proteins \\\n", - "0 rev_sp|Q71H61|ILDR2_HUMAN Immunoglobulin-like ... \n", - "1 sp|Q9H3S7|PTN23_HUMAN Tyrosine-protein phospha... \n", - "2 rev_sp|Q76N32|CEP68_HUMAN Centrosomal protein ... \n", - "3 sp|Q9UN73|PCDA6_HUMAN Protocadherin alpha-6 OS... \n", - "4 rev_sp|O60566|BUB1B_HUMAN Mitotic checkpoint s... \n", - "5 sp|P11021|BIP_HUMAN Endoplasmic reticulum chap... \n", - "6 sp|P26640|SYVC_HUMAN Valine--tRNA ligase OS=Ho... \n", - "7 rev_sp|Q8IVW4|CDKL3_HUMAN Cyclin-dependent kin... \n", - "8 rev_sp|A8K0R7|ZN839_HUMAN Zinc finger protein ... \n", - "9 sp|Q9UKF6|CPSF3_HUMAN Cleavage and polyadenyla... \n", - "10 rev_sp|P42704|LPPRC_HUMAN Leucine-rich PPR mot... \n", - "11 rev_sp|O14513|NCKP5_HUMAN Nck-associated prote... \n", - "12 rev_sp|Q86V15|CASZ1_HUMAN Zinc finger protein ... \n", - "\n", - " raw_name decoy mods \\\n", - "0 20190627_QX0_AnBr_SA_BPP_DDA_M01_02 1 \n", - "1 20190627_QX0_AnBr_SA_BPP_DDA_M01_02 0 \n", - "2 20190627_QX0_AnBr_SA_BPP_DDA_M01_02 1 \n", - "3 20190627_QX0_AnBr_SA_BPP_DDA_M01_02 0 \n", - "4 20190627_QX0_AnBr_SA_BPP_DDA_M01_02 1 Glu->pyro-Glu@E^Any N-term \n", - "5 20190627_QX0_AnBr_SA_BPP_DDA_M01_02 0 \n", - "6 20190627_QX0_AnBr_SA_BPP_DDA_M01_02 0 \n", - "7 20190627_QX0_AnBr_SA_BPP_DDA_M01_02 1 Oxidation@M \n", - "8 20190627_QX0_AnBr_SA_BPP_DDA_M01_02 1 Oxidation@M \n", - "9 20190627_QX0_AnBr_SA_BPP_DDA_M01_02 0 Oxidation@M \n", - "10 20190627_QX0_AnBr_SA_BPP_DDA_M01_02 1 \n", - "11 20190627_QX0_AnBr_SA_BPP_DDA_M01_02 1 \n", - "12 20190627_QX0_AnBr_SA_BPP_DDA_M01_02 1 Oxidation@M \n", - "\n", - " mod_sites mod_deltas mod_delta_sites nAA rt_norm precursor_mz \n", - "0 7 0.072516 416.203410 \n", - "1 7 0.072640 349.679040 \n", - "2 8 0.072511 414.716153 \n", - "3 8 0.072606 428.223288 \n", - "4 0 9 0.011747 332.506319 \n", - "5 9 0.046938 333.177307 \n", - "6 9 0.072571 331.174680 \n", - "7 3 119.00381504045001 8 12 0.072524 491.879582 \n", - "8 5 12 0.072551 357.918858 \n", - "9 10 13 0.072539 398.177635 \n", - "10 119.00381504045001 3 14 0.072566 422.695564 \n", - "11 17 0.072591 601.952491 \n", - "12 10 119.00381504045001 5 24 1.000000 1290.470466 " - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "#| hide\n", - "pepxml_str = \"\"\"\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\"\"\"\n", - "def read_msf():\n", - " filename = 'x.pepxml'\n", - " with open(filename,'w') as f: f.write(pepxml_str)\n", - " reader = MSFraggerPepXML(keep_decoy=True)\n", - " reader.import_file(filename)\n", - " os.remove(filename)\n", - " return reader.psm_df\n", - "df = read_msf()\n", - "assert len(df)==13\n", - "assert np.sum(df.decoy) == 8\n", - "assert df.mods.str.contains('N-term').any()\n", - "assert (df.mod_sites[df.mods.str.contains('N-term')] == '0').all()\n", - "assert df.mod_deltas.str.startswith('119').any()\n", - "df" + "# #| hide\n", + "# pepxml_str = \"\"\"\n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \n", + "# \"\"\"\n", + "# def read_msf():\n", + "# filename = 'x.pepxml'\n", + "# with open(filename,'w') as f: f.write(pepxml_str)\n", + "# reader = MSFraggerPepXML(keep_decoy=True)\n", + "# reader.import_file(filename)\n", + "# os.remove(filename)\n", + "# return reader.psm_df\n", + "# df = read_msf()\n", + "# assert len(df)==13\n", + "# assert np.sum(df.decoy) == 8\n", + "# assert df.mods.str.contains('N-term').any()\n", + "# assert (df.mod_sites[df.mods.str.contains('N-term')] == '0').all()\n", + "# assert df.mod_deltas.str.startswith('119').any()\n", + "# df" ] }, { diff --git a/nbdev_nbs/psm_reader/pfind_reader.ipynb b/nbdev_nbs/psm_reader/pfind_reader.ipynb index 957978ea..82d13c70 100644 --- a/nbdev_nbs/psm_reader/pfind_reader.ipynb +++ b/nbdev_nbs/psm_reader/pfind_reader.ipynb @@ -6,7 +6,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| default_exp psm_reader.pfind_reader" + "#---#| default_exp psm_reader.pfind_reader" ] }, { @@ -33,97 +33,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| export\n", - "\n", - "import pandas as pd\n", - "import numpy as np\n", - "\n", - "import alphabase.constants.modification as ap_mod\n", - "\n", - "from alphabase.psm_reader.psm_reader import (\n", - " PSMReaderBase, psm_reader_provider,\n", - " psm_reader_yaml\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def convert_one_pFind_mod(mod):\n", - " if mod[-1] == ')':\n", - " mod = mod[:(mod.find('(')-1)]\n", - " idx = mod.rfind('[')\n", - " name = mod[:idx]\n", - " site = mod[(idx+1):]\n", - " else:\n", - " idx = mod.rfind('[')\n", - " name = mod[:idx]\n", - " site = mod[(idx+1):-1]\n", - " if len(site) == 1:\n", - " return name + '@' + site\n", - " elif site == 'AnyN-term':\n", - " return name + '@' + 'Any N-term'\n", - " elif site == 'ProteinN-term':\n", - " return name + '@' + 'Protein N-term'\n", - " elif site.startswith('AnyN-term'):\n", - " return name + '@' + site[-1] + '^Any N-term'\n", - " elif site.startswith('ProteinN-term'):\n", - " return name + '@' + site[-1] + '^Protein N-term'\n", - " elif site == 'AnyC-term':\n", - " return name + '@' + 'Any C-term'\n", - " elif site == 'ProteinC-term':\n", - " return name + '@' + 'Protein C-term'\n", - " elif site.startswith('AnyC-term'):\n", - " return name + '@' + site[-1] + '^Any C-term'\n", - " elif site.startswith('ProteinC-term'):\n", - " return name + '@' + site[-1] + '^Protein C-term'\n", - " else:\n", - " return None\n", - "\n", - "def translate_pFind_mod(mod_str):\n", - " if not mod_str: return \"\"\n", - " ret_mods = []\n", - " for mod in mod_str.split(';'):\n", - " mod = convert_one_pFind_mod(mod)\n", - " if not mod: return pd.NA\n", - " elif mod not in ap_mod.MOD_INFO_DICT: return pd.NA\n", - " else: ret_mods.append(mod)\n", - " return ';'.join(ret_mods)\n", - "\n", - "def get_pFind_mods(pfind_mod_str):\n", - " pfind_mod_str = pfind_mod_str.strip(';')\n", - " if not pfind_mod_str: return \"\", \"\"\n", - "\n", - " items = [\n", - " item.split(',',3) \n", - " for item in pfind_mod_str.split(';')\n", - " ]\n", - " \n", - " items = [\n", - " ('-1',mod) if (mod.endswith('C-term]') \n", - " or mod[:-2].endswith('C-term'))\n", - " #else ('0', mod) if mod.endswith('N-term]')\n", - " else (site, mod) for site, mod in items\n", - " ]\n", - " items = list(zip(*items))\n", - " return ';'.join(items[1]), ';'.join(items[0])\n", - "\n", - "def parse_pfind_protein(protein, keep_reverse=True):\n", - " proteins = protein.strip('/').split('/')\n", - " return ';'.join(\n", - " [\n", - " protein for protein in proteins \n", - " if (\n", - " not protein.startswith('REV_') \n", - " or keep_reverse\n", - " )\n", - " ]\n", - " )\n" + "from alphabase.psm_reader.pfind_reader import *" ] }, { @@ -141,75 +51,6 @@ "assert get_pFind_mods('1,A[N];9,B[AnyC-termB]') == ('A[N];B[AnyC-termB]','1;-1')" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "class pFindReader(PSMReaderBase):\n", - " def __init__(self,\n", - " *,\n", - " column_mapping:dict = None,\n", - " modification_mapping:dict = None,\n", - " fdr = 0.01,\n", - " keep_decoy = False,\n", - " **kwargs,\n", - " ):\n", - " super().__init__(\n", - " column_mapping=column_mapping,\n", - " modification_mapping=modification_mapping,\n", - " fdr = fdr,\n", - " keep_decoy = keep_decoy,\n", - " **kwargs,\n", - " )\n", - "\n", - " def _init_column_mapping(self):\n", - " self.column_mapping = psm_reader_yaml[\n", - " 'pfind'\n", - " ]['column_mapping']\n", - " \n", - " def _init_modification_mapping(self):\n", - " self.modification_mapping = {}\n", - "\n", - " def _translate_modifications(self):\n", - " pass\n", - "\n", - " def _load_file(self, filename):\n", - " pfind_df = pd.read_csv(filename, index_col=False, sep='\\t')\n", - " pfind_df.fillna('', inplace=True)\n", - " pfind_df = pfind_df[pfind_df.Sequence != '']\n", - " pfind_df['raw_name'] = pfind_df[\n", - " 'File_Name'\n", - " ].str.split('.').apply(lambda x: x[0])\n", - " pfind_df['Proteins'] = pfind_df[\n", - " 'Proteins'\n", - " ].apply(parse_pfind_protein)\n", - " return pfind_df\n", - "\n", - " def _translate_decoy(self, origin_df=None):\n", - " self._psm_df.decoy = (\n", - " self._psm_df.decoy == 'decoy'\n", - " ).astype(np.int8)\n", - " \n", - " def _translate_score(self, origin_df=None):\n", - " self._psm_df.score = -np.log(\n", - " self._psm_df.score.astype(float)+1e-100\n", - " )\n", - "\n", - " def _load_modifications(self, pfind_df):\n", - " (\n", - " self._psm_df['mods'], self._psm_df['mod_sites']\n", - " ) = zip(*pfind_df['Modification'].apply(get_pFind_mods))\n", - "\n", - " self._psm_df['mods'] = self._psm_df['mods'].apply(\n", - " translate_pFind_mod\n", - " )\n", - " \n", - "psm_reader_provider.register_reader('pfind', pFindReader)" - ] - }, { "cell_type": "markdown", "metadata": {}, diff --git a/nbdev_nbs/psm_reader/psm_reader.ipynb b/nbdev_nbs/psm_reader/psm_reader.ipynb index 0b2e3951..88094ab8 100644 --- a/nbdev_nbs/psm_reader/psm_reader.ipynb +++ b/nbdev_nbs/psm_reader/psm_reader.ipynb @@ -6,7 +6,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| default_exp psm_reader.psm_reader" + "#---#| default_exp psm_reader.psm_reader" ] }, { @@ -33,81 +33,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| export\n", - "import pandas as pd\n", - "import numpy as np\n", - "import alphabase.peptide.mobility as mobility\n", - "from alphabase.peptide.precursor import (\n", - " update_precursor_mz, reset_precursor_df\n", - ")\n", - "from alphabase.constants._const import CONST_FILE_FOLDER" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def translate_other_modification(\n", - " mod_str: str, \n", - " mod_dict: dict\n", - ")->str:\n", - " '''\n", - " Translate modifications of `mod_str` to the AlphaBase \n", - " format mapped by mod_dict.\n", - " \n", - " Parameters\n", - " ----------\n", - " mod_str : str\n", - " mod list in str format, seperated by ';', \n", - " e.g. ModA;ModB\n", - " mod_dict : dict\n", - " translate mod dict from others to AlphaBase, \n", - " e.g. for pFind, key=['Phospho[S]','Oxidation[M]'], \n", - " value=['Phospho@S','Oxidation@M']\n", - " Returns\n", - " -------\n", - " str\n", - " new mods in AlphaBase format seperated by ';'. if any\n", - " modification is not in `mod_dict`, return pd.NA.\n", - " '''\n", - " if not mod_str: return \"\"\n", - " ret_mods = []\n", - " for mod in mod_str.split(';'):\n", - " if mod in mod_dict:\n", - " ret_mods.append(mod_dict[mod])\n", - " else:\n", - " return pd.NA\n", - " return \";\".join(ret_mods)\n", - "\n", - "def keep_modifications(\n", - " mod_str: str, \n", - " mod_set: set\n", - ")->str:\n", - " '''\n", - " Check if modifications of `mod_str` are in `mod_set`.\n", - "\n", - " Parameters\n", - " ----------\n", - " mod_str : str\n", - " mod list in str format, seperated by ';', \n", - " e.g. Oxidation@M;Phospho@S.\n", - " mod_set : set\n", - " mod set to check\n", - " Returns\n", - " -------\n", - " str\n", - " original `mod_str` if all modifications are in mod_set \n", - " else pd.NA.\n", - " '''\n", - " if not mod_str: return \"\"\n", - " for mod in mod_str.split(';'):\n", - " if not mod in mod_set:\n", - " return pd.NA\n", - " return mod_str\n" + "from alphabase.psm_reader.psm_reader import *" ] }, { @@ -123,25 +49,6 @@ "assert 'a;b' == translate_other_modification('A;B', {'A':'a','B':'b'})" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "from alphabase.yaml_utils import load_yaml\n", - "import os\n", - "import copy\n", - "\n", - "psm_reader_yaml = load_yaml(\n", - " os.path.join(\n", - " CONST_FILE_FOLDER,\n", - " 'psm_reader.yaml'\n", - " )\n", - ")" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -187,462 +94,30 @@ "20. `decoy`: 0 if the peptide is target match, otherwise 1." ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "class PSMReaderBase(object):\n", - " def __init__(self,\n", - " *,\n", - " column_mapping:dict = None,\n", - " modification_mapping:dict = None,\n", - " fdr = 0.01,\n", - " keep_decoy = False,\n", - " rt_unit:str = 'minute',\n", - " **kwargs,\n", - " ):\n", - " \"\"\"The Base class for all PSMReaders. The key of the sub-classes for different \n", - " search engine format is to re-define `column_mapping` and `modification_mapping`.\n", - " \n", - " Parameters\n", - " ----------\n", - " column_mapping : dict, optional\n", - " A dict that maps alphabase's columns to other search engine's.\n", - " The key of the column_mapping is alphabase's column name, and \n", - " the value could be the column name or a list of column names\n", - " in other engine's result.\n", - " If it is None, this dict will be init by \n", - " `self._init_column_mapping`. The dict values could be \n", - " either str or list, for exaplme:\n", - " columns_mapping = {\n", - " 'sequence': 'NakedSequence', #str\n", - " 'charge': 'Charge', #str\n", - " 'proteins':['Proteins','UniprotIDs'], # list, this reader will automatically detect all of them.\n", - " }\n", - " Defaults to None.\n", - " modification_mapping : dict, optional\n", - " A dict that maps alphabase's modifications to other engine's.\n", - " If it is None, this dict will be init by \n", - " `self._init_modification_mapping`. The dict values could be \n", - " either str or list, for exaplme:\n", - " modification_mapping = {\n", - " 'Oxidation@M': 'Oxidation (M)', # str\n", - " 'Phospho@S': ['S(Phospho (STY))','S(ph)','pS'], # list, this reader will automatically detect all of them.\n", - " }\n", - " Defaults to None.\n", - " fdr : float, optional\n", - " FDR level to keep PSMs.\n", - " Defaults to 0.01.\n", - " keep_decoy : bool, optional\n", - " If keep decoy PSMs in self.psm_df.\n", - " Defautls to False.\n", - " \n", - " Attributes\n", - " ----------\n", - " column_mapping : dict\n", - " Dict structure same as column_mapping in Args.\n", - " modification_mapping : dict\n", - " Dict structure same as modification_mapping in Args.\n", - " We must use self.set_modification_mapping(new_mapping) to update it.\n", - " _psm_df : pd.DataFrame\n", - " the PSM DataFrame after loading from search engines.\n", - " psm_df : pd.DataFrame\n", - " the getter of self._psm_df\n", - " keep_fdr : float\n", - " The only PSMs with FDR<=keep_fdr were returned in self._psm_df. \n", - " keep_decoy : bool\n", - " If keep decoy PSMs in self.psm_df.\n", - " _min_max_rt_norm : bool\n", - " if True, the 'rt_norm' values in self._psm_df \n", - " will be normalized by rt_norm = (self.psm_df.rt-rt_min)/(rt_max-rt_min).\n", - " It is useful to normalize iRT values as they contain negative values.\n", - " Defaults to False.\n", - " \"\"\"\n", - "\n", - " self.set_modification_mapping(modification_mapping)\n", - " \n", - " if column_mapping is not None:\n", - " self.column_mapping = column_mapping\n", - " else:\n", - " self._init_column_mapping()\n", - "\n", - " self._psm_df = pd.DataFrame()\n", - " self.keep_fdr = fdr\n", - " self.keep_decoy = keep_decoy\n", - " self._min_max_rt_norm = False\n", - " self._engine_rt_unit = rt_unit\n", - "\n", - " @property\n", - " def psm_df(self)->pd.DataFrame:\n", - " return self._psm_df\n", - "\n", - " def add_modification_mapping(self, modification_mapping:dict):\n", - " if (\n", - " modification_mapping is None or\n", - " len(modification_mapping) == 0\n", - " ):\n", - " return\n", - " \n", - " self.modification_mapping.update(modification_mapping)\n", - " self.set_modification_mapping(self.modification_mapping)\n", - "\n", - " def set_modification_mapping(self, modification_mapping:dict):\n", - " if modification_mapping is None:\n", - " self._init_modification_mapping()\n", - " elif isinstance(modification_mapping, str):\n", - " if modification_mapping in psm_reader_yaml:\n", - " self.modification_mapping = copy.deepcopy(\n", - " psm_reader_yaml[\n", - " modification_mapping\n", - " ]['modification_mapping']\n", - " )\n", - " else:\n", - " raise ValueError(\n", - " f'Unknown modification mapping: {modification_mapping}'\n", - " )\n", - " else:\n", - " self.modification_mapping = copy.deepcopy(\n", - " modification_mapping\n", - " )\n", - " self._reverse_mod_mapping()\n", - "\n", - " def _init_modification_mapping(self):\n", - " self.modification_mapping = {}\n", - " \n", - " def _reverse_mod_mapping(self):\n", - " self.rev_mod_mapping = {}\n", - " for (\n", - " this_mod, other_mod\n", - " ) in self.modification_mapping.items():\n", - " if isinstance(other_mod, (list, tuple)):\n", - " for _mod in other_mod:\n", - " self.rev_mod_mapping[_mod] = this_mod\n", - " else:\n", - " self.rev_mod_mapping[other_mod] = this_mod\n", - " \n", - " def _init_column_mapping(self):\n", - " raise NotImplementedError(\n", - " f'\"{self.__class__}\" must implement \"_init_column_mapping()\"'\n", - " )\n", - " \n", - " def load(self, _file):\n", - " \"\"\" Wrapper for import_file() \"\"\"\n", - " return self.import_file(_file)\n", - "\n", - " def import_file(self, _file:str):\n", - " \"\"\"\n", - " This is the main entry function of PSM readers, \n", - " it imports the file with following steps:\n", - " ```\n", - " origin_df = self._load_file(_file)\n", - " self._translate_columns(origin_df)\n", - " self._translate_decoy(origin_df)\n", - " self._translate_score(origin_df)\n", - " self._load_modifications(origin_df)\n", - " self._translate_modifications()\n", - " self._post_process(origin_df)\n", - " ```\n", - " \n", - " Parameters\n", - " ----------\n", - " _file: str\n", - " file path or file stream (io).\n", - " \"\"\"\n", - " origin_df = self._load_file(_file)\n", - " if len(origin_df) == 0:\n", - " self._psm_df = pd.DataFrame()\n", - " else:\n", - " self._translate_columns(origin_df)\n", - " self._translate_decoy(origin_df)\n", - " self._translate_score(origin_df)\n", - " self._load_modifications(origin_df)\n", - " self._translate_modifications()\n", - " self._post_process(origin_df)\n", - " return self._psm_df\n", - "\n", - " def _translate_decoy(\n", - " self, \n", - " origin_df:pd.DataFrame=None\n", - " ):\n", - " pass\n", - "\n", - " def _translate_score(\n", - " self, \n", - " origin_df:pd.DataFrame=None\n", - " ):\n", - " # some scores are evalue/pvalue, it should be translated\n", - " # to -log(evalue), as score is the larger the better\n", - " pass\n", - "\n", - " def normalize_rt(self):\n", - " if 'rt' in self.psm_df.columns:\n", - " if self._engine_rt_unit == 'second':\n", - " # self.psm_df['rt_sec'] = self.psm_df.rt\n", - " self.psm_df['rt'] = self.psm_df.rt/60\n", - " # elif self._engine_rt_unit == 'minute':\n", - " # self.psm_df['rt_sec'] = self.psm_df.rt*60\n", - " min_rt = self.psm_df.rt.min()\n", - " if not self._min_max_rt_norm or min_rt > 0:\n", - " min_rt = 0\n", - " self.psm_df['rt_norm'] = (\n", - " self.psm_df.rt - min_rt\n", - " ) / (self.psm_df.rt.max()-min_rt)\n", - "\n", - " def norm_rt(self):\n", - " self.normalize_rt()\n", - "\n", - " def normalize_rt_by_raw_name(self):\n", - " if not 'rt' in self.psm_df.columns:\n", - " return\n", - " if not 'rt_norm' in self.psm_df.columns:\n", - " self.norm_rt()\n", - " if not 'raw_name' in self.psm_df.columns:\n", - " return\n", - " for raw_name, df_group in self.psm_df.groupby('raw_name'):\n", - " self.psm_df.loc[\n", - " df_group.index,'rt_norm'\n", - " ] = df_group.rt_norm / df_group.rt_norm.max()\n", - "\n", - " def _load_file(self, filename:str)->pd.DataFrame:\n", - " \"\"\"\n", - " Load original dataframe from PSM filename. \n", - " Different search engines may store PSMs in different ways:\n", - " tsv, csv, HDF, XML, ...\n", - "\n", - " Parameters\n", - " ----------\n", - " filename : str\n", - " psm filename\n", - "\n", - " Raises\n", - " ------\n", - " NotImplementedError\n", - " Subclasses must re-implement this method\n", - "\n", - " Returns:\n", - " pd.DataFrame\n", - " loaded dataframe\n", - " \"\"\"\n", - " raise NotImplementedError(\n", - " f'\"{self.__class__}\" must implement \"_load_file()\"'\n", - " )\n", - "\n", - " def _translate_columns(self, origin_df:pd.DataFrame):\n", - " \"\"\"\n", - " Translate the dataframe from other search engines \n", - " to AlphaBase format\n", - "\n", - " Parameters\n", - " ----------\n", - " origin_df : pd.DataFrame\n", - " df of other search engines\n", - "\n", - " Returns\n", - " -------\n", - " None\n", - " Add information inplace into self._psm_df\n", - " \"\"\"\n", - " self._psm_df = pd.DataFrame()\n", - " for col, map_col in self.column_mapping.items():\n", - " if isinstance(map_col, str):\n", - " if map_col in origin_df.columns:\n", - " self._psm_df[col] = origin_df[map_col]\n", - " else:\n", - " for other_col in map_col:\n", - " if other_col in origin_df.columns:\n", - " self._psm_df[col] = origin_df[other_col]\n", - " break\n", - " \n", - " if (\n", - " 'scan_num' in self._psm_df.columns and \n", - " not 'spec_idx' in self._psm_df.columns\n", - " ):\n", - " self._psm_df['spec_idx'] = self._psm_df.scan_num - 1\n", - " \n", - "\n", - " def _load_modifications(self, origin_df:pd.DataFrame):\n", - " \"\"\"Read modification information from 'origin_df'. \n", - " Some of search engines use modified_sequence, some of them\n", - " use additional columns to store modifications and the sites.\n", - "\n", - " Parameters\n", - " ----------\n", - " origin_df : pd.DataFrame\n", - " dataframe of original search engine.\n", - " \"\"\"\n", - " raise NotImplementedError(\n", - " f'\"{self.__class__}\" must implement \"_load_modifications()\"'\n", - " )\n", - "\n", - " def _translate_modifications(self):\n", - " '''\n", - " Translate modifications to AlphaBase format.\n", - "\n", - " Raises\n", - " ------\n", - " KeyError\n", - " if `mod` in `mod_names` is \n", - " not in `self.modification_mapping`\n", - " '''\n", - " self._psm_df.mods = self._psm_df.mods.apply(\n", - " translate_other_modification, \n", - " mod_dict=self.rev_mod_mapping\n", - " )\n", - "\n", - " def _post_process(self, \n", - " origin_df:pd.DataFrame\n", - " ):\n", - " \"\"\"\n", - " Set 'nAA' columns, remove unknown modifications \n", - " and perform other post processings, \n", - " e.g. get 'rt_norm', remove decoys, filter FDR...\n", - "\n", - " Parameters\n", - " ----------\n", - " origin_df : pd.DataFrame\n", - " the loaded original df\n", - " \"\"\"\n", - " self._psm_df['nAA'] = self._psm_df.sequence.str.len()\n", - "\n", - " self.normalize_rt_by_raw_name()\n", - "\n", - " self._psm_df = self._psm_df[\n", - " ~self._psm_df['mods'].isna()\n", - " ]\n", - "\n", - " keep_rows = np.ones(\n", - " len(self._psm_df), dtype=bool\n", - " )\n", - " if 'fdr' in self._psm_df.columns:\n", - " keep_rows &= (self._psm_df.fdr <= self.keep_fdr)\n", - " if (\n", - " 'decoy' in self._psm_df.columns \n", - " and not self.keep_decoy\n", - " ):\n", - " keep_rows &= (self._psm_df.decoy == 0)\n", - "\n", - " self._psm_df = self._psm_df[keep_rows]\n", - " \n", - " reset_precursor_df(self._psm_df)\n", - " \n", - " if 'precursor_mz' not in self._psm_df:\n", - " self._psm_df = update_precursor_mz(self._psm_df)\n", - "\n", - " if (\n", - " 'ccs' in self._psm_df.columns and \n", - " 'mobility' not in self._psm_df.columns\n", - " ):\n", - " self._psm_df['mobility'] = (\n", - " mobility.ccs_to_mobility_for_df(\n", - " self._psm_df,\n", - " 'ccs'\n", - " )\n", - " )\n", - " elif (\n", - " 'mobility' in self._psm_df.columns and\n", - " 'ccs' not in self._psm_df.columns\n", - " ):\n", - " self._psm_df['ccs'] = (\n", - " mobility.mobility_to_ccs_for_df(\n", - " self._psm_df,\n", - " 'mobility'\n", - " )\n", - " )\n", - "\n", - " def filter_psm_by_modifications(self, include_mod_set = set([\n", - " 'Oxidation@M','Phospho@S','Phospho@T',\n", - " 'Phospho@Y','Acetyl@Protein N-term'\n", - " ])):\n", - " '''\n", - " Only keeps peptides with modifications in `include_mod_list`.\n", - " '''\n", - " self._psm_df.mods = self._psm_df.mods.apply(\n", - " keep_modifications, mod_set=include_mod_set\n", - " )\n", - " \n", - " self._psm_df.dropna(\n", - " subset=['mods'], inplace=True\n", - " )\n", - " self._psm_df.reset_index(drop=True, inplace=True)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| hide\n", - "from nbdev.showdoc import show_doc" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/psm_reader/psm_reader.py#L172){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### PSMReaderBase.add_modification_mapping\n", - "\n", - "> PSMReaderBase.add_modification_mapping (modification_mapping:dict)" - ], - "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/psm_reader/psm_reader.py#L172){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### PSMReaderBase.add_modification_mapping\n", - "\n", - "> PSMReaderBase.add_modification_mapping (modification_mapping:dict)" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "show_doc(PSMReaderBase.add_modification_mapping)" - ] - }, { "cell_type": "markdown", "metadata": {}, "source": [ - "`modification_mapping` example (MaxQuant):\n", + "`modification_mapping` example (MaxQuant, unimod will be automatically added):\n", "\n", "```python\n", "{\n", " 'Acetyl@Protein N-term': [\n", " '_(Acetyl (Protein N-term))',\n", " '_(ac)',\n", - " '_(UniMod:1)',\n", " ]\n", " 'Carbamidomethyl@C': [\n", " 'C(Carbamidomethyl (C))',\n", - " 'C(UniMod:4)',\n", " ]\n", " 'Oxidation@M': [\n", " 'M(Oxidation (M))',\n", " 'M(ox)',\n", - " 'M(UniMod:35)',\n", " ]\n", " 'Phospho@S': [\n", " 'S(Phospho (S))',\n", " 'S(Phospho (ST))',\n", " 'S(Phospho (STY))',\n", " 'S(ph)',\n", - " 'S(UniMod:21)',\n", " 'pS',\n", " ]\n", " 'Phospho@T': [\n", @@ -650,14 +125,12 @@ " 'T(Phospho (ST))',\n", " 'T(Phospho (STY))',\n", " 'T(ph)',\n", - " 'T(UniMod:21)',\n", " 'pT',\n", " ]\n", " 'Phospho@Y': [\n", " 'Y(Phospho (Y))',\n", " 'Y(Phospho (STY))',\n", " 'Y(ph)',\n", - " 'Y(UniMod:21)',\n", " 'pY',\n", " ]\n", " 'Deamidated@N': ['N(Deamidation (NQ))','N(de)']\n", @@ -667,170 +140,6 @@ "```" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/psm_reader/psm_reader.py#L182){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### PSMReaderBase.set_modification_mapping\n", - "\n", - "> PSMReaderBase.set_modification_mapping (modification_mapping:dict)" - ], - "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/psm_reader/psm_reader.py#L182){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### PSMReaderBase.set_modification_mapping\n", - "\n", - "> PSMReaderBase.set_modification_mapping (modification_mapping:dict)" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "show_doc(PSMReaderBase.set_modification_mapping)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/psm_reader/psm_reader.py#L225){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### PSMReaderBase.import_file\n", - "\n", - "> PSMReaderBase.import_file (_file:str)\n", - "\n", - "This is the main entry function of PSM readers, \n", - "it imports the file with following steps:\n", - "```\n", - "origin_df = self._load_file(_file)\n", - "self._translate_columns(origin_df)\n", - "self._translate_decoy(origin_df)\n", - "self._translate_score(origin_df)\n", - "self._load_modifications(origin_df)\n", - "self._translate_modifications()\n", - "self._post_process(origin_df)\n", - "```" - ], - "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/psm_reader/psm_reader.py#L225){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### PSMReaderBase.import_file\n", - "\n", - "> PSMReaderBase.import_file (_file:str)\n", - "\n", - "This is the main entry function of PSM readers, \n", - "it imports the file with following steps:\n", - "```\n", - "origin_df = self._load_file(_file)\n", - "self._translate_columns(origin_df)\n", - "self._translate_decoy(origin_df)\n", - "self._translate_score(origin_df)\n", - "self._load_modifications(origin_df)\n", - "self._translate_modifications()\n", - "self._post_process(origin_df)\n", - "```" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "show_doc(PSMReaderBase.import_file)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/psm_reader/psm_reader.py#L270){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### PSMReaderBase.normalize_rt\n", - "\n", - "> PSMReaderBase.normalize_rt ()" - ], - "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/psm_reader/psm_reader.py#L270){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### PSMReaderBase.normalize_rt\n", - "\n", - "> PSMReaderBase.normalize_rt ()" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "show_doc(PSMReaderBase.normalize_rt)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/markdown": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/psm_reader/psm_reader.py#L282){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### PSMReaderBase.normalize_rt_by_raw_name\n", - "\n", - "> PSMReaderBase.normalize_rt_by_raw_name ()" - ], - "text/plain": [ - "---\n", - "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/psm_reader/psm_reader.py#L282){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### PSMReaderBase.normalize_rt_by_raw_name\n", - "\n", - "> PSMReaderBase.normalize_rt_by_raw_name ()" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "show_doc(PSMReaderBase.normalize_rt_by_raw_name)" - ] - }, { "cell_type": "code", "execution_count": null, @@ -859,45 +168,6 @@ "After a subclass of `PSMReaderBase` is defined, for example `AlphaPeptReader`, we can then register it in to `psm_reader_provider` by using `psm_reader_provider.register_reader('alphapept', AlphaPeptReader)`. Once we are going to use it, we just need to create a `AlphaPeptReader` object with `psm_reader_provider.get_reader('alphapept')`." ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "class PSMReaderProvider:\n", - " def __init__(self):\n", - " self.reader_dict = {}\n", - "\n", - " def register_reader(self, reader_type, reader_class):\n", - " self.reader_dict[reader_type.lower()] = reader_class\n", - "\n", - " def get_reader(self, \n", - " reader_type:str,\n", - " *,\n", - " column_mapping:dict=None, \n", - " modification_mapping:dict=None,\n", - " fdr=0.01, keep_decoy=False,\n", - " **kwargs\n", - " )->PSMReaderBase:\n", - " return self.reader_dict[reader_type.lower()](\n", - " column_mapping = column_mapping,\n", - " modification_mapping=modification_mapping,\n", - " fdr=fdr, keep_decoy=keep_decoy, **kwargs\n", - " )\n", - "\n", - " def get_reader_by_yaml(self, \n", - " yaml_dict:dict,\n", - " )->PSMReaderBase:\n", - " return self.get_reader(\n", - " **copy.deepcopy(yaml_dict)\n", - " )\n", - "\n", - "psm_reader_provider = PSMReaderProvider()" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -930,15 +200,15 @@ "assert isinstance(psm_reader_provider.get_reader_by_yaml(psm_reader_yaml['maxquant']), maxquant_reader.MaxQuantReader)\n", "assert isinstance(psm_reader_provider.get_reader_by_yaml(psm_reader_yaml['diann']), dia_psm_reader.DiannReader)\n", "assert isinstance(psm_reader_provider.get_reader_by_yaml(psm_reader_yaml['spectronaut']), dia_psm_reader.SpectronautReader)\n", - "assert isinstance(psm_reader_provider.get_reader_by_yaml(psm_reader_yaml['pfind']), pfind_reader.pFindReader)\n", + "# assert isinstance(psm_reader_provider.get_reader_by_yaml(psm_reader_yaml['pfind']), pfind_reader.pFindReader)\n", "reader = psm_reader_provider.get_reader_by_yaml(psm_reader_yaml['diann'])\n", "assert np.all(np.array(reader.modification_mapping['Phospho@S'])==np.array([\n", " 'S(Phospho (S))',\n", " 'S(Phospho (ST))',\n", " 'S(Phospho (STY))',\n", " 'S(ph)',\n", - " 'S(UniMod:21)',\n", " 'pS',\n", + " 'S(UniMod:21)',\n", " 'S[Phospho (S)]',\n", " 'S[Phospho (ST)]',\n", " 'S[Phospho (STY)]',\n", diff --git a/nbdev_nbs/scoring/fdr.ipynb b/nbdev_nbs/scoring/fdr.ipynb new file mode 100644 index 00000000..20dc6383 --- /dev/null +++ b/nbdev_nbs/scoring/fdr.ipynb @@ -0,0 +1,438 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#---#| default_exp scoring.fdr" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# FDR functionalities" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Functionalities to calculate FDR.\n", + "\n", + "> In alphabase dataframes, we refer fdr values as q_values without loss of generacity." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from alphabase.scoring.fdr import *" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
scoredecoykindfdr
41720.9867510True0.000000
48620.9588030True0.000000
4620.9542440True0.000000
13120.8324400True0.000000
23620.8095950True0.000000
...............
11110.0463660False0.504008
7090.0408411False0.504505
12090.0308410False0.504505
9390.0137041False0.505000
14390.0037040False0.505000
\n", + "

1505 rows × 4 columns

\n", + "
" + ], + "text/plain": [ + " score decoy kind fdr\n", + "417 20.986751 0 True 0.000000\n", + "486 20.958803 0 True 0.000000\n", + "46 20.954244 0 True 0.000000\n", + "131 20.832440 0 True 0.000000\n", + "236 20.809595 0 True 0.000000\n", + "... ... ... ... ...\n", + "1111 0.046366 0 False 0.504008\n", + "709 0.040841 1 False 0.504505\n", + "1209 0.030841 0 False 0.504505\n", + "939 0.013704 1 False 0.505000\n", + "1439 0.003704 0 False 0.505000\n", + "\n", + "[1505 rows x 4 columns]" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = pd.DataFrame(\n", + " {\n", + " 'score': np.random.random(500)*10+11,\n", + " 'decoy': 0,\n", + " 'kind': True,\n", + " }\n", + ")\n", + "f_score = np.random.random(500)*9.9\n", + "df = df.append(\n", + " pd.DataFrame(\n", + " {\n", + " 'score': f_score+0.01,\n", + " 'decoy': 1,\n", + " 'kind': False\n", + " }\n", + " )\n", + ")\n", + "df = df.append(\n", + " pd.DataFrame(\n", + " {\n", + " 'score': f_score,\n", + " 'decoy': 0,\n", + " 'kind': False\n", + " }\n", + " )\n", + ")\n", + "df = df.append(\n", + " pd.DataFrame(\n", + " {\n", + " 'score': np.random.random(5)+10,\n", + " 'decoy': 1,\n", + " 'kind': False\n", + " }\n", + " )\n", + ")\n", + "\n", + "df = calculate_fdr(df, 'score', 'decoy')\n", + "df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
scoredecoykindfdr
41720.9867510True0.0
48620.9588030True0.0
4620.9542440True0.0
13120.8324400True0.0
23620.8095950True0.0
...............
31311.0706950True0.0
22711.0284310True0.0
15311.0143300True0.0
11311.0139780True0.0
4811.0106290True0.0
\n", + "

500 rows × 4 columns

\n", + "
" + ], + "text/plain": [ + " score decoy kind fdr\n", + "417 20.986751 0 True 0.0\n", + "486 20.958803 0 True 0.0\n", + "46 20.954244 0 True 0.0\n", + "131 20.832440 0 True 0.0\n", + "236 20.809595 0 True 0.0\n", + ".. ... ... ... ...\n", + "313 11.070695 0 True 0.0\n", + "227 11.028431 0 True 0.0\n", + "153 11.014330 0 True 0.0\n", + "113 11.013978 0 True 0.0\n", + "48 11.010629 0 True 0.0\n", + "\n", + "[500 rows x 4 columns]" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df[(df.fdr < 0.01)&(df.decoy==0)]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| hide\n", + "assert len(df[(df.fdr < 0.01)&(df.decoy==0)]) == 500" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| hide\n", + "dff = pd.DataFrame(\n", + " {\n", + " 'score': np.random.random(500)*10+11,\n", + " 'decoy': 0\n", + " }\n", + ")\n", + "f_score = np.random.random(500)*9.9\n", + "dff = dff.append(\n", + " pd.DataFrame(\n", + " {\n", + " 'score': f_score+0.01,\n", + " 'decoy': 1\n", + " }\n", + " )\n", + ")\n", + "dff = dff.append(\n", + " pd.DataFrame(\n", + " {\n", + " 'score': f_score,\n", + " 'decoy': 0\n", + " }\n", + " )\n", + ")\n", + "dff = dff.append(\n", + " pd.DataFrame(\n", + " {\n", + " 'score': np.random.random(5)+10,\n", + " 'decoy': 1\n", + " }\n", + " )\n", + ")\n", + "\n", + "dff['fdr'] = fdr_from_ref(dff.score.values, df.score.values, df.fdr.values)\n", + "\n", + "assert len(dff[(dff.fdr < 0.01)&(dff.decoy==0)]) == 500" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| hide\n", + "dff = calculate_fdr_from_ref(dff, df.score.values, df.fdr.values, 'score')\n", + "assert len(dff[(dff.fdr < 0.01)&(dff.decoy==0)]) == 500" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.8.3 ('base')", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/nbdev_nbs/scoring/feature_extraction_base.ipynb b/nbdev_nbs/scoring/feature_extraction_base.ipynb new file mode 100644 index 00000000..dd9a7517 --- /dev/null +++ b/nbdev_nbs/scoring/feature_extraction_base.ipynb @@ -0,0 +1,162 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#---#| default_exp scoring.feature_extraction_base" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Base Class of Feature Extractors" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from alphabase.scoring.feature_extraction_base import *" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| hide\n", + "from nbdev.showdoc import show_doc" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/scoring/feature_extraction_base.py#L30){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### BaseFeatureExtractor.extract_features\n", + "\n", + "> BaseFeatureExtractor.extract_features\n", + "> (psm_df:pandas.core.frame.DataFram\n", + "> e, *args, **kwargs)\n", + "\n", + "Extract the scoring features (self._feature_list) \n", + "and append them inplace into candidate PSMs (psm_df).\n", + "\n", + "**All sub-classes must re-implement this method.**\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| psm_df | DataFrame | PSMs to be rescored |\n", + "| args | | |\n", + "| kwargs | | |\n", + "| **Returns** | **DataFrame** | **psm_df with appended feature columns extracted by this extractor** |" + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/scoring/feature_extraction_base.py#L30){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### BaseFeatureExtractor.extract_features\n", + "\n", + "> BaseFeatureExtractor.extract_features\n", + "> (psm_df:pandas.core.frame.DataFram\n", + "> e, *args, **kwargs)\n", + "\n", + "Extract the scoring features (self._feature_list) \n", + "and append them inplace into candidate PSMs (psm_df).\n", + "\n", + "**All sub-classes must re-implement this method.**\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| psm_df | DataFrame | PSMs to be rescored |\n", + "| args | | |\n", + "| kwargs | | |\n", + "| **Returns** | **DataFrame** | **psm_df with appended feature columns extracted by this extractor** |" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "show_doc(BaseFeatureExtractor.extract_features)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/scoring/feature_extraction_base.py#L52){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### BaseFeatureExtractor.update_features\n", + "\n", + "> BaseFeatureExtractor.update_features (psm_df:pandas.core.frame.DataFrame)\n", + "\n", + "This method allow us to update adaptive features\n", + "during the iteration of Percolator algorithm\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| psm_df | DataFrame | psm_df |\n", + "| **Returns** | **DataFrame** | **psm_df with updated feature values** |" + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/scoring/feature_extraction_base.py#L52){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### BaseFeatureExtractor.update_features\n", + "\n", + "> BaseFeatureExtractor.update_features (psm_df:pandas.core.frame.DataFrame)\n", + "\n", + "This method allow us to update adaptive features\n", + "during the iteration of Percolator algorithm\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| psm_df | DataFrame | psm_df |\n", + "| **Returns** | **DataFrame** | **psm_df with updated feature values** |" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "show_doc(BaseFeatureExtractor.update_features)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.8.3 ('base')", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/nbdev_nbs/scoring/ml_scoring_base.ipynb b/nbdev_nbs/scoring/ml_scoring_base.ipynb new file mode 100644 index 00000000..104044f4 --- /dev/null +++ b/nbdev_nbs/scoring/ml_scoring_base.ipynb @@ -0,0 +1,926 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#---#| default_exp scoring.ml_scoring_base" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Base Class of ML Scoring Methods" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from alphabase.scoring.ml_scoring_base import *" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are two key modules in ML-based rescoring: feature extraction and rescoring algorithm. Here we designed these two modules as flexible as possible for future extensions." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Feature extraction\n", + "\n", + "The feature extractor is more important than the ML methods, so we designed a flexible architecture for feature extraction. As shown in `BaseFeatureExtractor`, a feature extractor inherited from `BaseFeatureExtractor` must re-implement `BaseFeatureExtractor.extract_features`, and tells the ML methods what are the extracted features by providing `BaseFeatureExtractor.feature_list`. \n", + "\n", + "For example, if we have two feature extractors, `AlphaPeptFE` and `AlphaPeptDeepFE`:\n", + "\n", + "```python\n", + "class AlphaPeptFE(BaseFeatureExtractor):\n", + " def extract_features(self, psm_df):\n", + " psm_df['ap_f1'] = ...\n", + " self._feature_list.append('ap_f1')\n", + " psm_df['ap_f2'] = ...\n", + " self._feature_list.append('ap_f2')\n", + "\n", + "class AlphaPeptDeepFE(BaseFeatureExtractor):\n", + " def extract_features(self, psm_df):\n", + " psm_df['ad_f1'] = ...\n", + " self._feature_list.append('ad_f1')\n", + " psm_df['ad_f2'] = ...\n", + " self._feature_list.append('ad_f2')\n", + "```\n", + "\n", + "We can easily design a new feature extractor which combines these two and more feature extractors:\n", + "\n", + "```python\n", + "class CombFE(BaseFeatureExtractor):\n", + " def __init__(self):\n", + " self.fe_list = [AlphaPeptFE(),AlphaPeptDeepFE()]\n", + "\n", + " def extract_features(self, psm_df):\n", + " for fe in self.fe_list:\n", + " fe.extract_features(psm_df)\n", + "\n", + " @property\n", + " def feature_list(self):\n", + " f_set = set()\n", + " for fe in self.fe_list:\n", + " f_set.update(fe.feature_list)\n", + " return list(f_set)\n", + "```\n", + "\n", + "This will be useful for rescoring with DL features, for instance, when AlphaPeptDeep is or is not installed." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Rescoring Algorithm\n", + "\n", + "The rescoring algorithm called `Percolator` (Kall et al. 2007) based on the semi-supervised learning algorithm is still the most widely used in MS-based proteomics. Therefore, we used `Percolator` as the base rescoring class and others can re-implement its methods for different algorithms. as well as different \n", + "\n", + "1. Rescoring algorithm. We have provided the base rescoring code structure in `Percolator`. If we are going to support DiaNN's brute-force supervised learning methods, we can define the class like this:\n", + "\n", + "```python\n", + "class DiaNNRescoring(Percolator):\n", + " def __init__(self):\n", + " super().__init__()\n", + " self.training_fdr = 100000 # disable target filtration on FDR, which is the same as DiaNN but different from Percolator\n", + "\n", + " self._ml_model.fit(\n", + " train_df[self.feature_list].values, \n", + " train_label\n", + " )\n", + " def rescore(self, psm_df):\n", + " # We don't need iteration anymore, but cross validation is still necessary\n", + " df = self._cv_score(df)\n", + " return self._estimate_fdr(df)\n", + "```\n", + "\n", + "2. ML models. Personally, `Percolator` with a linear classifier (SVM or LogisticRegression) is prefered. But as a framework, we should support different ML models. We can easily switch to the random forest by `self.ml_model = RandomForestClassifier()`. We can also use a DL model which provides sklearn-like `fit()` and `decision_function()` APIs for rescoring." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| hide\n", + "from nbdev.showdoc import show_doc" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Properties of `Percolator`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/scoring/ml_scoring_base.py#L46){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### Percolator.ml_model\n", + "\n", + "> Percolator.ml_model ()\n", + "\n", + "ML model in Percolator.\n", + "It can be sklearn models or other models but implement \n", + "the methods `fit()` and `decision_function()` (or `predict_proba()`) \n", + "which are the same as sklearn models." + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/scoring/ml_scoring_base.py#L46){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### Percolator.ml_model\n", + "\n", + "> Percolator.ml_model ()\n", + "\n", + "ML model in Percolator.\n", + "It can be sklearn models or other models but implement \n", + "the methods `fit()` and `decision_function()` (or `predict_proba()`) \n", + "which are the same as sklearn models." + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "show_doc(Percolator.ml_model)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/scoring/ml_scoring_base.py#L66){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### Percolator.feature_extractor\n", + "\n", + "> Percolator.feature_extractor ()\n", + "\n", + "The feature extractor inherited from `BaseFeatureExtractor`" + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/scoring/ml_scoring_base.py#L66){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### Percolator.feature_extractor\n", + "\n", + "> Percolator.feature_extractor ()\n", + "\n", + "The feature extractor inherited from `BaseFeatureExtractor`" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "show_doc(Percolator.feature_extractor)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/scoring/ml_scoring_base.py#L37){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### Percolator.feature_list\n", + "\n", + "> Percolator.feature_list ()\n", + "\n", + "Get extracted feature_list. Property, read-only" + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/scoring/ml_scoring_base.py#L37){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### Percolator.feature_list\n", + "\n", + "> Percolator.feature_list ()\n", + "\n", + "Get extracted feature_list. Property, read-only" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "show_doc(Percolator.feature_list)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Methods of `Percolator`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/scoring/ml_scoring_base.py#L69){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### Percolator.extract_features\n", + "\n", + "> Percolator.extract_features (psm_df:pandas.core.frame.DataFrame, *args,\n", + "> **kwargs)\n", + "\n", + "Extract features for rescoring.\n", + "\n", + "*args and **kwargs are used for \n", + "`self.feature_extractor.extract_features`.\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| psm_df | DataFrame | PSM DataFrame |\n", + "| args | | |\n", + "| kwargs | | |\n", + "| **Returns** | **DataFrame** | **psm_df with feature columns appended inplace.** |" + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/scoring/ml_scoring_base.py#L69){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### Percolator.extract_features\n", + "\n", + "> Percolator.extract_features (psm_df:pandas.core.frame.DataFrame, *args,\n", + "> **kwargs)\n", + "\n", + "Extract features for rescoring.\n", + "\n", + "*args and **kwargs are used for \n", + "`self.feature_extractor.extract_features`.\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| psm_df | DataFrame | PSM DataFrame |\n", + "| args | | |\n", + "| kwargs | | |\n", + "| **Returns** | **DataFrame** | **psm_df with feature columns appended inplace.** |" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "show_doc(Percolator.extract_features)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/scoring/ml_scoring_base.py#L95){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### Percolator.rescore\n", + "\n", + "> Percolator.rescore (df:pandas.core.frame.DataFrame)\n", + "\n", + "Estimate ML scores and then FDRs (q-values)\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| df | DataFrame | psm_df |\n", + "| **Returns** | **DataFrame** | **psm_df with `ml_score` and `fdr` columns updated inplace** |" + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/scoring/ml_scoring_base.py#L95){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### Percolator.rescore\n", + "\n", + "> Percolator.rescore (df:pandas.core.frame.DataFrame)\n", + "\n", + "Estimate ML scores and then FDRs (q-values)\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| df | DataFrame | psm_df |\n", + "| **Returns** | **DataFrame** | **psm_df with `ml_score` and `fdr` columns updated inplace** |" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "show_doc(Percolator.rescore)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/scoring/ml_scoring_base.py#L171){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### Percolator.run_rescore_workflow\n", + "\n", + "> Percolator.run_rescore_workflow (psm_df:pandas.core.frame.DataFrame,\n", + "> *args, **kwargs)\n", + "\n", + "Run percolator workflow:\n", + "\n", + "- self.extract_features()\n", + "- self.rescore()\n", + "\n", + "*args and **kwargs are used for \n", + "`self.feature_extractor.extract_features`.\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| psm_df | DataFrame | PSM DataFrame |\n", + "| args | | |\n", + "| kwargs | | |\n", + "| **Returns** | **DataFrame** | **psm_df with feature columns appended inplace.** |" + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/scoring/ml_scoring_base.py#L171){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### Percolator.run_rescore_workflow\n", + "\n", + "> Percolator.run_rescore_workflow (psm_df:pandas.core.frame.DataFrame,\n", + "> *args, **kwargs)\n", + "\n", + "Run percolator workflow:\n", + "\n", + "- self.extract_features()\n", + "- self.rescore()\n", + "\n", + "*args and **kwargs are used for \n", + "`self.feature_extractor.extract_features`.\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| psm_df | DataFrame | PSM DataFrame |\n", + "| args | | |\n", + "| kwargs | | |\n", + "| **Returns** | **DataFrame** | **psm_df with feature columns appended inplace.** |" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "show_doc(Percolator.run_rescore_workflow)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/scoring/ml_scoring_base.py#L117){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### Percolator.run_rerank_workflow\n", + "\n", + "> Percolator.run_rerank_workflow (top_k_psm_df:pandas.core.frame.DataFrame,\n", + "> rerank_column:str='spec_idx', *args,\n", + "> **kwargs)\n", + "\n", + "Run percolator workflow with reranking \n", + "the peptides for each spectrum.\n", + "\n", + "- self.extract_features()\n", + "- self.rescore()\n", + "\n", + "*args and **kwargs are used for \n", + "`self.feature_extractor.extract_features`.\n", + "\n", + "| | **Type** | **Default** | **Details** |\n", + "| -- | -------- | ----------- | ----------- |\n", + "| top_k_psm_df | DataFrame | | PSM DataFrame |\n", + "| rerank_column | str | spec_idx | The column use to rerank PSMs.

For example, use the following code to select
the top-ranked peptide for each spectrum.
```
rerank_column = 'spec_idx' # scan_num
idx = top_k_psm_df.groupby(
['raw_name',rerank_column]
)['ml_score'].idxmax()
psm_df = top_k_psm_df.loc[idx].copy()
``` |\n", + "| args | | | |\n", + "| kwargs | | | |\n", + "| **Returns** | **DataFrame** | | |" + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/scoring/ml_scoring_base.py#L117){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### Percolator.run_rerank_workflow\n", + "\n", + "> Percolator.run_rerank_workflow (top_k_psm_df:pandas.core.frame.DataFrame,\n", + "> rerank_column:str='spec_idx', *args,\n", + "> **kwargs)\n", + "\n", + "Run percolator workflow with reranking \n", + "the peptides for each spectrum.\n", + "\n", + "- self.extract_features()\n", + "- self.rescore()\n", + "\n", + "*args and **kwargs are used for \n", + "`self.feature_extractor.extract_features`.\n", + "\n", + "| | **Type** | **Default** | **Details** |\n", + "| -- | -------- | ----------- | ----------- |\n", + "| top_k_psm_df | DataFrame | | PSM DataFrame |\n", + "| rerank_column | str | spec_idx | The column use to rerank PSMs.

For example, use the following code to select
the top-ranked peptide for each spectrum.
```
rerank_column = 'spec_idx' # scan_num
idx = top_k_psm_df.groupby(
['raw_name',rerank_column]
)['ml_score'].idxmax()
psm_df = top_k_psm_df.loc[idx].copy()
``` |\n", + "| args | | | |\n", + "| kwargs | | | |\n", + "| **Returns** | **DataFrame** | | |" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "show_doc(Percolator.run_rerank_workflow)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Simple Examples" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
scorenAAchargedecoyspec_idxraw_nameml_scorefdr
099.851979263018raw138.1427660.000000
198.74605273012raw133.8677790.000000
297.415167162016raw133.4477610.000000
396.857314143015raw131.8773180.000000
494.606208173048raw128.7857130.000000
...........................
1950.346523182189raw-17.0086490.979798
1960.703782153182raw-17.2927480.989899
1970.058571223177raw-17.3522931.000000
1980.90198392164raw-17.3577041.000000
1990.32037882031raw-18.3954211.000000
\n", + "

200 rows × 8 columns

\n", + "
" + ], + "text/plain": [ + " score nAA charge decoy spec_idx raw_name ml_score fdr\n", + "0 99.851979 26 3 0 18 raw 138.142766 0.000000\n", + "1 98.746052 7 3 0 12 raw 133.867779 0.000000\n", + "2 97.415167 16 2 0 16 raw 133.447761 0.000000\n", + "3 96.857314 14 3 0 15 raw 131.877318 0.000000\n", + "4 94.606208 17 3 0 48 raw 128.785713 0.000000\n", + ".. ... ... ... ... ... ... ... ...\n", + "195 0.346523 18 2 1 89 raw -17.008649 0.979798\n", + "196 0.703782 15 3 1 82 raw -17.292748 0.989899\n", + "197 0.058571 22 3 1 77 raw -17.352293 1.000000\n", + "198 0.901983 9 2 1 64 raw -17.357704 1.000000\n", + "199 0.320378 8 2 0 31 raw -18.395421 1.000000\n", + "\n", + "[200 rows x 8 columns]" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = pd.DataFrame({\n", + " 'score': list(np.random.uniform(0,100,100))+list(np.random.uniform(0,10,100)),\n", + " 'nAA': list(np.random.randint(7,30,200)),\n", + " 'charge': list(np.random.randint(2,4,200)),\n", + " 'decoy': [0]*100+[1]*100,\n", + " 'spec_idx': np.repeat(np.arange(100),2),\n", + " 'raw_name': 'raw',\n", + "})\n", + "perc = Percolator()\n", + "perc.min_training_sample = 10\n", + "perc.run_rescore_workflow(df)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
scorenAAchargedecoyspec_idxraw_nameml_scorefdr
5444.98600025200raw23.2398710.000000
694.0206587301raw61.7629730.000000
7323.02806814202raw5.3460260.000000
1779.16353728303raw50.5846930.000000
3661.67392323204raw36.5007280.000000
...........................
1702.30608673195raw-11.4759200.744898
1058.10719282196raw-6.7650490.191011
929.717331103197raw-5.4596660.044944
1434.381494293198raw-9.1000270.565217
1305.831152263199raw-8.0403860.423913
\n", + "

100 rows × 8 columns

\n", + "
" + ], + "text/plain": [ + " score nAA charge decoy spec_idx raw_name ml_score fdr\n", + "54 44.986000 25 2 0 0 raw 23.239871 0.000000\n", + "6 94.020658 7 3 0 1 raw 61.762973 0.000000\n", + "73 23.028068 14 2 0 2 raw 5.346026 0.000000\n", + "17 79.163537 28 3 0 3 raw 50.584693 0.000000\n", + "36 61.673923 23 2 0 4 raw 36.500728 0.000000\n", + ".. ... ... ... ... ... ... ... ...\n", + "170 2.306086 7 3 1 95 raw -11.475920 0.744898\n", + "105 8.107192 8 2 1 96 raw -6.765049 0.191011\n", + "92 9.717331 10 3 1 97 raw -5.459666 0.044944\n", + "143 4.381494 29 3 1 98 raw -9.100027 0.565217\n", + "130 5.831152 26 3 1 99 raw -8.040386 0.423913\n", + "\n", + "[100 rows x 8 columns]" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "perc.run_rerank_workflow(df, rerank_column='spec_idx')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.8.3 ('base')", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/nbdev_nbs/sidebar.yml b/nbdev_nbs/sidebar.yml index b4c2cebb..8c1e5629 100644 --- a/nbdev_nbs/sidebar.yml +++ b/nbdev_nbs/sidebar.yml @@ -31,7 +31,16 @@ website: - psm_reader/msfragger_reader.ipynb - psm_reader/pfind_reader.ipynb - psm_reader/psm_reader.ipynb + - section: scoring + contents: + - scoring/fdr.ipynb + - scoring/feature_extraction_base.ipynb + - scoring/ml_scoring_base.ipynb - section: spectral_library contents: - spectral_library/decoy_library.ipynb - - spectral_library/library_base.ipynb \ No newline at end of file + - spectral_library/library_base.ipynb + - spectral_library/translate.ipynb + - section: statistics + contents: + - statistics/regression.ipynb \ No newline at end of file diff --git a/nbdev_nbs/spectral_library/decoy_library.ipynb b/nbdev_nbs/spectral_library/decoy_library.ipynb index 9f2144ef..f128dea9 100644 --- a/nbdev_nbs/spectral_library/decoy_library.ipynb +++ b/nbdev_nbs/spectral_library/decoy_library.ipynb @@ -6,7 +6,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| default_exp spectral_library.decoy_library" + "#---#| default_exp spectral_library.decoy" ] }, { @@ -22,190 +22,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| export\n", - "\n", - "import copy\n", - "from alphabase.spectral_library.library_base import SpecLibBase\n", - "from alphabase.io.hdf import HDF_File" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "class DecoyLib(SpecLibBase):\n", - " def __init__(self, \n", - " target_lib:SpecLibBase,\n", - " fix_C_term = True,\n", - " **kwargs,\n", - " ):\n", - " \"\"\"Pseudo-reverse peptide decoy generator\n", - " Currently, only sequence-level decoy is implemented,\n", - " but AlphaPeptDeep will add modifications onto both target and decoy sequences,\n", - " so it is enough for practical uses.\n", - "\n", - " Parameters\n", - " ----------\n", - " target_lib : SpecLibBase\n", - " Target library to decoy.\n", - "\n", - " fix_C_term : bool, optional\n", - " If fix C-term AA when decoy. \n", - " Defaults to True.\n", - " \n", - " Attributes\n", - " ----------\n", - " target_lib : SpecLibBase\n", - " same as 'target_lib' in Args.\n", - " \"\"\"\n", - " self.__dict__ = copy.deepcopy(target_lib.__dict__)\n", - " self.target_lib = target_lib\n", - " self.fix_C_term = fix_C_term\n", - "\n", - " def translate_to_decoy(self):\n", - " \"\"\"Main entry of this class, it calls follows methods:\n", - " self.decoy_sequence()\n", - " self._decoy_mods()\n", - " self._decoy_meta()\n", - " self._decoy_frags()\n", - " \"\"\"\n", - " self.decoy_sequence()\n", - " self._decoy_mods()\n", - " self._decoy_meta()\n", - " self._decoy_frags()\n", - "\n", - " def decoy_sequence(self):\n", - " \"\"\"Generate decoy sequences from `self.target_lib`\"\"\"\n", - " self._decoy_seq()\n", - " self._remove_target_seqs()\n", - "\n", - " def append_decoy_sequence(self):\n", - " pass\n", - "\n", - " def _decoy_seq(self):\n", - " (\n", - " self._precursor_df.sequence\n", - " ) = self._precursor_df.sequence.apply(\n", - " lambda x: (x[:-1][::-1]+x[-1])\n", - " if self.fix_C_term else x[::-1]\n", - " )\n", - "\n", - " def _remove_target_seqs(self):\n", - " target_seqs = set(\n", - " self.target_lib._precursor_df.sequence.values\n", - " )\n", - " self._precursor_df.drop(\n", - " self._precursor_df.loc[\n", - " self._precursor_df.sequence.isin(target_seqs)\n", - " ].index, inplace=True\n", - " )\n", - "\n", - " def _decoy_meta(self):\n", - " \"\"\"\n", - " Decoy for CCS/RT or other meta data\n", - " \"\"\"\n", - " pass\n", - "\n", - " def _decoy_mods(self):\n", - " \"\"\"\n", - " Decoy for modifications and modification sites\n", - " \"\"\"\n", - " pass\n", - "\n", - " def _decoy_frags(self):\n", - " \"\"\"\n", - " Decoy for fragment masses and intensities\n", - " \"\"\"\n", - " self._decoy_fragment_mz()\n", - " self._decoy_fragment_intensity()\n", - " \n", - " def _decoy_fragment_mz(self):\n", - " pass\n", - " \n", - " def _decoy_fragment_intensity(self):\n", - " pass\n", - "\n", - " def _get_hdf_to_save(self, \n", - " hdf_file, \n", - " delete_existing=False\n", - " ):\n", - " _hdf = HDF_File(\n", - " hdf_file, \n", - " read_only=False, \n", - " truncate=True,\n", - " delete_existing=delete_existing\n", - " )\n", - " return _hdf.library.decoy\n", - "\n", - " def _get_hdf_to_load(self,\n", - " hdf_file, \n", - " ):\n", - " _hdf = HDF_File(\n", - " hdf_file,\n", - " )\n", - " return _hdf.library.decoy\n", - "\n", - " def save_hdf(self, hdf_file):\n", - " _hdf = HDF_File(\n", - " hdf_file, \n", - " read_only=False, \n", - " truncate=True,\n", - " delete_existing=False\n", - " )\n", - " _hdf.library.decoy = {\n", - " 'precursor_df': self._precursor_df,\n", - " 'fragment_mz_df': self._fragment_mz_df,\n", - " 'fragment_intensity_df': self._fragment_intensity_df,\n", - " }\n", - "\n", - " def load_hdf(self, hdf_file):\n", - " _hdf = HDF_File(\n", - " hdf_file,\n", - " )\n", - " _hdf_lib = _hdf.library\n", - " self._precursor_df = _hdf_lib.decoy.precursor_df.values\n", - " self._fragment_mz_df = _hdf_lib.decoy.fragment_mz_df.values\n", - " self._fragment_intensity_df = _hdf_lib.decoy.fragment_intensity_df.values\n", - "\n", - "class DiaNNDecoyLib(DecoyLib):\n", - " def __init__(self, \n", - " target_lib:SpecLibBase,\n", - " raw_AAs:str = 'GAVLIFMPWSCTYHKRQEND',\n", - " mutated_AAs:str = 'LLLVVLLLLTSSSSLLNDQE', #DiaNN\n", - " **kwargs,\n", - " ): \n", - " \"\"\"DiaNN-like decoy peptide generator\n", - "\n", - " Parameters\n", - " ----------\n", - " target_lib : SpecLibBase\n", - " Target library object\n", - "\n", - " raw_AAs : str, optional\n", - " AAs those DiaNN decoy from. \n", - " Defaults to 'GAVLIFMPWSCTYHKRQEND'.\n", - "\n", - " mutated_AAs : str, optional\n", - " AAs those DiaNN decoy to. \n", - " Defaults to 'LLLVVLLLLTSSSSLLNDQE'.\n", - " \n", - " \"\"\"\n", - " super().__init__(target_lib)\n", - " self.raw_AAs = raw_AAs\n", - " self.mutated_AAs = mutated_AAs\n", - "\n", - " def _decoy_seq(self):\n", - " (\n", - " self._precursor_df.sequence\n", - " ) = self._precursor_df.sequence.apply(\n", - " lambda x:\n", - " x[0]+self.mutated_AAs[self.raw_AAs.index(x[1])]+\n", - " x[2:-2]+self.mutated_AAs[self.raw_AAs.index(x[-2])]+x[-1]\n", - " )" + "from alphabase.spectral_library.decoy import *" ] }, { @@ -257,53 +74,6 @@ "show_doc(DecoyLib.decoy_sequence)" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "class DecoyLibProvider(object):\n", - " def __init__(self):\n", - " self.decoy_dict = {}\n", - "\n", - " def register(self, name:str, decoy_class:DecoyLib):\n", - " \"\"\"Register a new decoy class\"\"\"\n", - " self.decoy_dict[name.lower()] = decoy_class\n", - "\n", - " def get_decoy_lib(self, name:str, \n", - " target_lib:SpecLibBase, **kwargs\n", - " )->DecoyLib:\n", - " \"\"\"Get an object of a subclass of `DecoyLib` based on \n", - " registered name.\n", - "\n", - " Parameters\n", - " ----------\n", - " name : str\n", - " Registered decoy class name\n", - " target_lib : SpecLibBase\n", - " Target library for decoy generation\n", - "\n", - " Returns\n", - " -------\n", - " DecoyLib\n", - " Decoy library object\n", - " \"\"\"\n", - " if name is None: return None\n", - " name = name.lower()\n", - " if name in self.decoy_dict:\n", - " return self.decoy_dict[name](\n", - " target_lib, **kwargs\n", - " )\n", - " else:\n", - " return None\n", - "\n", - "decoy_lib_provider = DecoyLibProvider()\n", - "decoy_lib_provider.register('pseudo_reverse', DecoyLib)\n", - "decoy_lib_provider.register('diann', DiaNNDecoyLib)" - ] - }, { "cell_type": "code", "execution_count": null, diff --git a/nbdev_nbs/spectral_library/flat_library.ipynb b/nbdev_nbs/spectral_library/flat_library.ipynb new file mode 100644 index 00000000..7f47e870 --- /dev/null +++ b/nbdev_nbs/spectral_library/flat_library.ipynb @@ -0,0 +1,790 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#---#| default_exp spectral_library.flat_library" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from alphabase.spectral_library.flat import *" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#|hide \n", + "from nbdev.showdoc import show_doc" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/flat_library.py#L101){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### FlatSpecLib.parse_base_library\n", + "\n", + "> FlatSpecLib.parse_base_library\n", + "> (library:alphabase.spectral_library.libra\n", + "> ry_base.SpecLibBase)\n", + "\n", + "Flatten a SpecLibBase object\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| library | SpecLibBase | the library with fragment_mz_df and fragment_intensity_df |" + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/flat_library.py#L101){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### FlatSpecLib.parse_base_library\n", + "\n", + "> FlatSpecLib.parse_base_library\n", + "> (library:alphabase.spectral_library.libra\n", + "> ry_base.SpecLibBase)\n", + "\n", + "Flatten a SpecLibBase object\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| library | SpecLibBase | the library with fragment_mz_df and fragment_intensity_df |" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "show_doc(FlatSpecLib.parse_base_library)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/flat_library.py#L118){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### FlatSpecLib.save_hdf\n", + "\n", + "> FlatSpecLib.save_hdf (hdf_file:str)\n", + "\n", + "Save library dataframes into hdf_file.\n", + "For `self.precursor_df`, this method will save it into two hdf groups:\n", + " hdf_file: `flat_library/precursor_df` and `library/mod_seq_df`.\n", + "\n", + "`flat_library/precursor_df` contains all essential numberic columns those \n", + "can be loaded faster from hdf file into memory:\n", + " 'precursor_mz', 'charge', 'mod_seq_hash', 'mod_seq_charge_hash',\n", + " 'frag_start_idx', 'frag_end_idx', 'decoy', 'rt_pred', 'ccs_pred',\n", + " 'mobility_pred', 'miss_cleave', 'nAA', \n", + " ['isotope_mz_m1', 'isotope_intensity_m1'], ...\n", + "\n", + "`flat_library/mod_seq_df` contains all string columns and the other \n", + "not essential columns:\n", + " 'sequence','mods','mod_sites', ['proteins', 'genes']...\n", + "as well as 'mod_seq_hash', 'mod_seq_charge_hash' columns to map \n", + "back to `precursor_df`\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| hdf_file | str | the hdf file path to save |" + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/flat_library.py#L118){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### FlatSpecLib.save_hdf\n", + "\n", + "> FlatSpecLib.save_hdf (hdf_file:str)\n", + "\n", + "Save library dataframes into hdf_file.\n", + "For `self.precursor_df`, this method will save it into two hdf groups:\n", + " hdf_file: `flat_library/precursor_df` and `library/mod_seq_df`.\n", + "\n", + "`flat_library/precursor_df` contains all essential numberic columns those \n", + "can be loaded faster from hdf file into memory:\n", + " 'precursor_mz', 'charge', 'mod_seq_hash', 'mod_seq_charge_hash',\n", + " 'frag_start_idx', 'frag_end_idx', 'decoy', 'rt_pred', 'ccs_pred',\n", + " 'mobility_pred', 'miss_cleave', 'nAA', \n", + " ['isotope_mz_m1', 'isotope_intensity_m1'], ...\n", + "\n", + "`flat_library/mod_seq_df` contains all string columns and the other \n", + "not essential columns:\n", + " 'sequence','mods','mod_sites', ['proteins', 'genes']...\n", + "as well as 'mod_seq_hash', 'mod_seq_charge_hash' columns to map \n", + "back to `precursor_df`\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| hdf_file | str | the hdf file path to save |" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "show_doc(FlatSpecLib.save_hdf)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/flat_library.py#L171){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### FlatSpecLib.load_hdf\n", + "\n", + "> FlatSpecLib.load_hdf (hdf_file:str, load_mod_seq:bool=False)\n", + "\n", + "Load the hdf library from hdf_file\n", + "\n", + "| | **Type** | **Default** | **Details** |\n", + "| -- | -------- | ----------- | ----------- |\n", + "| hdf_file | str | | hdf library path to load |\n", + "| load_mod_seq | bool | False | if also load mod_seq_df.
Defaults to False. |" + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/flat_library.py#L171){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### FlatSpecLib.load_hdf\n", + "\n", + "> FlatSpecLib.load_hdf (hdf_file:str, load_mod_seq:bool=False)\n", + "\n", + "Load the hdf library from hdf_file\n", + "\n", + "| | **Type** | **Default** | **Details** |\n", + "| -- | -------- | ----------- | ----------- |\n", + "| hdf_file | str | | hdf library path to load |\n", + "| load_mod_seq | bool | False | if also load mod_seq_df.
Defaults to False. |" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "show_doc(FlatSpecLib.load_hdf)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| hide\n", + "from io import StringIO\n", + "from alphabase.spectral_library.reader import SWATHLibraryReader" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
mzintensitytype
0609.3007550.450362121
1511.3238601.000000121
2510.2323410.106543121
3412.2554460.374123121
4411.1639270.069116121
5313.1870320.173858121
6321.6946900.515072121
7545.3293390.745664121
8326.1710470.14370398
9432.2452751.000000121
10397.2081610.09488898
11361.2081610.377585121
12496.2765750.05498098
13686.2756630.103734121
14588.2987671.000000121
15349.1717760.092058121
16661.2956700.198974121
17563.3187740.774316121
18494.2973101.000000121
19256.1291830.64971598
20347.2288970.882733121
21403.1975960.35178198
22490.2296250.40047498
23701.2905840.24435098
24603.3136890.63100098
25762.2583120.084908121
26664.2814170.328738121
27497.2830570.284129121
28496.1915390.276969121
29268.1655680.05755498
30398.2146430.262853121
31267.0740500.08743998
32329.1931801.000000121
33435.1639270.06162798
34698.3120480.602346121
35600.3351531.000000121
36611.2800200.141106121
37513.3031240.705295121
38498.1959560.108914121
39400.2190600.279959121
40331.1975960.492018121
\n", + "
" + ], + "text/plain": [ + " mz intensity type\n", + "0 609.300755 0.450362 121\n", + "1 511.323860 1.000000 121\n", + "2 510.232341 0.106543 121\n", + "3 412.255446 0.374123 121\n", + "4 411.163927 0.069116 121\n", + "5 313.187032 0.173858 121\n", + "6 321.694690 0.515072 121\n", + "7 545.329339 0.745664 121\n", + "8 326.171047 0.143703 98\n", + "9 432.245275 1.000000 121\n", + "10 397.208161 0.094888 98\n", + "11 361.208161 0.377585 121\n", + "12 496.276575 0.054980 98\n", + "13 686.275663 0.103734 121\n", + "14 588.298767 1.000000 121\n", + "15 349.171776 0.092058 121\n", + "16 661.295670 0.198974 121\n", + "17 563.318774 0.774316 121\n", + "18 494.297310 1.000000 121\n", + "19 256.129183 0.649715 98\n", + "20 347.228897 0.882733 121\n", + "21 403.197596 0.351781 98\n", + "22 490.229625 0.400474 98\n", + "23 701.290584 0.244350 98\n", + "24 603.313689 0.631000 98\n", + "25 762.258312 0.084908 121\n", + "26 664.281417 0.328738 121\n", + "27 497.283057 0.284129 121\n", + "28 496.191539 0.276969 121\n", + "29 268.165568 0.057554 98\n", + "30 398.214643 0.262853 121\n", + "31 267.074050 0.087439 98\n", + "32 329.193180 1.000000 121\n", + "33 435.163927 0.061627 98\n", + "34 698.312048 0.602346 121\n", + "35 600.335153 1.000000 121\n", + "36 611.280020 0.141106 121\n", + "37 513.303124 0.705295 121\n", + "38 498.195956 0.108914 121\n", + "39 400.219060 0.279959 121\n", + "40 331.197596 0.492018 121" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| hide\n", + "tsv_str = \"\"\"PrecursorCharge\tModifiedPeptide\tStrippedPeptide\tiRT\tLabeledPeptide\tPrecursorMz\tFragmentLossType\tFragmentNumber\tFragmentType\tFragmentCharge\tFragmentMz\tRelativeIntensity\tIonMobility\n", + "2\t_DPLAVDK_\tDPLAVDK\t-15.0871\t_DPLAVDK_\t379.2081611\tnoloss\t3\tb\t1\t326.1710473\t14.37029\t0.9\n", + "2\t_DPLAVDK_\tDPLAVDK\t-15.0871\t_DPLAVDK_\t379.2081611\tnoloss\t3\ty\t1\t361.2081611\t37.7585\t0.9\n", + "2\t_DPLAVDK_\tDPLAVDK\t-15.0871\t_DPLAVDK_\t379.2081611\tnoloss\t4\tb\t1\t397.2081611\t9.488808\t0.9\n", + "2\t_DPLAVDK_\tDPLAVDK\t-15.0871\t_DPLAVDK_\t379.2081611\tnoloss\t4\ty\t1\t432.2452749\t100\t0.9\n", + "2\t_DPLAVDK_\tDPLAVDK\t-15.0871\t_DPLAVDK_\t379.2081611\tnoloss\t5\tb\t1\t496.276575\t5.498003\t0.9\n", + "2\t_DPLAVDK_\tDPLAVDK\t-15.0871\t_DPLAVDK_\t379.2081611\tnoloss\t5\ty\t1\t545.3293389\t74.56643\t0.9\n", + "2\t_DPLAVDK_\tDPLAVDK\t-15.0871\t_DPLAVDK_\t379.2081611\tnoloss\t6\ty\t2\t321.6946896\t51.50719\t0.9\n", + "2\t_AVVVS[Phospho (STY)]PK_\tAVVVSPK\t-22.84974\t_AVVVS[Phospho (STY)]PK_\t390.2067795\tnoloss\t3\ty\t1\t411.1639269\t6.911595\t0.9\n", + "2\t_AVVVS[Phospho (STY)]PK_\tAVVVSPK\t-22.84974\t_AVVVS[Phospho (STY)]PK_\t390.2067795\tH3PO4\t3\ty\t1\t313.1870287\t17.38582\t0.9\n", + "2\t_AVVVS[Phospho (STY)]PK_\tAVVVSPK\t-22.84974\t_AVVVS[Phospho (STY)]PK_\t390.2067795\tnoloss\t4\ty\t1\t510.2323409\t10.65426\t0.9\n", + "2\t_AVVVS[Phospho (STY)]PK_\tAVVVSPK\t-22.84974\t_AVVVS[Phospho (STY)]PK_\t390.2067795\tH3PO4\t4\ty\t1\t412.2554427\t37.41231\t0.9\n", + "2\t_AVVVS[Phospho (STY)]PK_\tAVVVSPK\t-22.84974\t_AVVVS[Phospho (STY)]PK_\t390.2067795\tnoloss\t5\ty\t1\t609.3007548\t45.03617\t0.9\n", + "2\t_AVVVS[Phospho (STY)]PK_\tAVVVSPK\t-22.84974\t_AVVVS[Phospho (STY)]PK_\t390.2067795\tH3PO4\t5\ty\t1\t511.3238566\t100\t0.9\n", + "2\t_MGS[Phospho (STY)]LDSK_\tMGSLDSK\t-27.5635\t_MGS[Phospho (STY)]LDSK_\t409.1617118\tnoloss\t3\ty\t1\t349.1717756\t9.20575\t0.9\n", + "2\t_MGS[Phospho (STY)]LDSK_\tMGSLDSK\t-27.5635\t_MGS[Phospho (STY)]LDSK_\t409.1617118\tnoloss\t6\ty\t1\t686.2756622\t10.37339\t0.9\n", + "2\t_MGS[Phospho (STY)]LDSK_\tMGSLDSK\t-27.5635\t_MGS[Phospho (STY)]LDSK_\t409.1617118\tH3PO4\t6\ty\t1\t588.298764\t100\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tnoloss\t3\ty\t1\t347.2288965\t88.27327\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tH3PO4\t3\tb\t1\t256.1291795\t64.97146\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tnoloss\t4\ty\t1\t494.2973105\t100\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tH3PO4\t4\tb\t1\t403.1975934\t35.17805\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tnoloss\t5\ty\t1\t661.2956694\t19.89741\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tH3PO4\t5\tb\t1\t490.2296218\t40.04738\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tH3PO4\t5\ty\t1\t563.3187712\t77.43164\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tnoloss\t6\tb\t1\t701.290584\t24.43497\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tH3PO4\t6\tb\t1\t603.3136858\t63.09999\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\t1(+H2+O)1(+H3+O4+P)\t3\tb\t1\t238.1186147\t62.60851\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\t1(+H2+O)1(+H3+O4+P)\t5\tb\t1\t472.219057\t22.99903\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\t1(+H2+O)1(+H3+O4+P)\t6\tb\t1\t585.303121\t66.30389\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tnoloss\t3\ty\t1\t329.1931797\t100\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tH3PO4\t3\tb\t1\t268.165565\t5.755442\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tnoloss\t4\tb\t2\t267.0740493\t8.743931\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tnoloss\t4\ty\t1\t496.1915387\t27.69686\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tH3PO4\t4\tb\t1\t435.1639239\t6.162673\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\t2(+H3+O4+P)\t4\tb\t1\t337.1870258\t10.84257\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tH3PO4\t4\ty\t1\t398.2146405\t26.28527\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tH3PO4\t5\ty\t1\t497.2830544\t28.41294\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tnoloss\t6\ty\t1\t762.2583115\t8.490795\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tH3PO4\t6\ty\t1\t664.2814133\t32.87384\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\t2(+H3+O4+P)\t6\ty\t1\t566.3045151\t35.87218\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\tnoloss\t3\ty\t1\t331.1975964\t49.20179\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\tnoloss\t4\ty\t1\t498.1959553\t10.89141\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\tH3PO4\t4\ty\t1\t400.2190571\t27.99594\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\tnoloss\t5\ty\t1\t611.2800193\t14.11057\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\tH3PO4\t5\ty\t1\t513.3031211\t70.5295\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\tnoloss\t6\ty\t1\t698.3120477\t60.23455\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\tH3PO4\t6\ty\t1\t600.3351495\t100\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\t1(+H2+O)1(+H3+O4+P)\t6\ty\t1\t582.3245847\t5.233977\t0.9\n", + "\"\"\"\n", + "\n", + "reader = SWATHLibraryReader()\n", + "reader.import_file(StringIO(tsv_str))\n", + "flat_lib = FlatSpecLib(custom_fragment_df_columns=['type'])\n", + "flat_lib.parse_base_library(reader)\n", + "flat_lib.fragment_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sequencechargertmobilitymodsmod_sitesnAAfrag_start_idxfrag_end_idxrt_normprecursor_mzccs
0AVVVSPK2-22.8497400.9Phospho@S57060.075327390.206780366.858877
1DPLAVDK2-15.0871000.976130.199375379.208161367.043100
2MGSLDSK2-27.5635000.9Phospho@S3713160.000000409.161712366.564438
3SVSFSLK135.0141100.9Phospho@S3716251.000000847.396112183.178171
4VSVSPGR2-23.9308500.9Phospho@S;Phospho@S2;4725340.058050431.167001366.254833
5YSLSPSK2-6.4281980.9Phospho@S4734410.337745431.191327366.254509
\n", + "
" + ], + "text/plain": [ + " sequence charge rt mobility mods mod_sites nAA \\\n", + "0 AVVVSPK 2 -22.849740 0.9 Phospho@S 5 7 \n", + "1 DPLAVDK 2 -15.087100 0.9 7 \n", + "2 MGSLDSK 2 -27.563500 0.9 Phospho@S 3 7 \n", + "3 SVSFSLK 1 35.014110 0.9 Phospho@S 3 7 \n", + "4 VSVSPGR 2 -23.930850 0.9 Phospho@S;Phospho@S 2;4 7 \n", + "5 YSLSPSK 2 -6.428198 0.9 Phospho@S 4 7 \n", + "\n", + " frag_start_idx frag_end_idx rt_norm precursor_mz ccs \n", + "0 0 6 0.075327 390.206780 366.858877 \n", + "1 6 13 0.199375 379.208161 367.043100 \n", + "2 13 16 0.000000 409.161712 366.564438 \n", + "3 16 25 1.000000 847.396112 183.178171 \n", + "4 25 34 0.058050 431.167001 366.254833 \n", + "5 34 41 0.337745 431.191327 366.254509 " + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| hide\n", + "flat_lib.precursor_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.8.3 ('base')", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/nbdev_nbs/spectral_library/library_base.ipynb b/nbdev_nbs/spectral_library/library_base.ipynb index 93d4986f..b5f29fc4 100644 --- a/nbdev_nbs/spectral_library/library_base.ipynb +++ b/nbdev_nbs/spectral_library/library_base.ipynb @@ -6,7 +6,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| default_exp spectral_library.library_base" + "#---#| default_exp spectral_library.base" ] }, { @@ -22,449 +22,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| export\n", - "\n", - "import pandas as pd\n", - "import numpy as np\n", - "import typing\n", - "\n", - "import alphabase.peptide.fragment as fragment\n", - "import alphabase.peptide.precursor as precursor\n", - "from alphabase.io.hdf import HDF_File" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export \n", - "class SpecLibBase(object):\n", - " def __init__(self,\n", - " # ['b_z1','b_z2','y_z1','y_modloss_z1', ...]; \n", - " # 'b_z1': 'b' is the fragment type and \n", - " # 'z1' is the charge state z=1.\n", - " charged_frag_types:typing.List[str] = [\n", - " 'b_z1','b_z2','y_z1', 'y_z2'\n", - " ], \n", - " precursor_mz_min = 400, precursor_mz_max = 6000,\n", - " decoy:str = None,\n", - " ):\n", - " \"\"\"Base spectral library in alphabase and alphapeptdeep.\n", - "\n", - " Parameters\n", - " ----------\n", - " charged_frag_types : typing.List[str], optional\n", - " fragment types with charge. \n", - " Defaults to [ 'b_z1','b_z2','y_z1', 'y_z2' ].\n", - "\n", - " precursor_mz_min : int, optional\n", - " Use this to clip precursor df. \n", - " Defaults to 400.\n", - "\n", - " precursor_mz_max : int, optional\n", - " Use this to clip precursor df. \n", - " Defaults to 6000.\n", - "\n", - " decoy : str, optional\n", - " Decoy methods, could be \"pseudo_reverse\" or \"diann\".\n", - " Defaults to None.\n", - "\n", - " Attributes\n", - " ----------\n", - " precursor_df : pd.DataFrame\n", - " precursor dataframe.\n", - "\n", - " fragment_mz_df : pd.DataFrame\n", - " fragment m/z dataframe.\n", - "\n", - " fragment_intensity_df : pd.DataFrame\n", - " fragment intensity dataframe.\n", - "\n", - " charged_frag_types : list\n", - " same as `charged_frag_types` in Args.\n", - "\n", - " min_precursor_mz : float\n", - " same as `precursor_mz_min` in Args.\n", - "\n", - " max_precursor_mz : float\n", - " same as `precursor_mz_max` in Args.\n", - "\n", - " decoy : str\n", - " same as `decoy` in Args.\n", - "\n", - " key_numeric_columns : list of str\n", - " key numeric columns to be saved \n", - " into library/precursor_df in the hdf file. Others will be saved into\n", - " library/mod_seq_df instead.\n", - " \n", - " \"\"\"\n", - " self.charged_frag_types = charged_frag_types\n", - " self._precursor_df = pd.DataFrame()\n", - " self._fragment_intensity_df = pd.DataFrame()\n", - " self._fragment_mz_df = pd.DataFrame()\n", - " self.min_precursor_mz = precursor_mz_min\n", - " self.max_precursor_mz = precursor_mz_max\n", - "\n", - " self.key_numeric_columns = [\n", - " 'ccs_pred', 'charge', \n", - " 'decoy',\n", - " 'frag_end_idx', 'frag_start_idx',\n", - " 'isotope_m1_intensity', 'isotope_m1_mz',\n", - " 'isotope_apex_mz', 'isotope_apex_intensity',\n", - " 'isotope_apex_index',\n", - " 'isotope_right_most_mz', 'isotope_right_most_intensity',\n", - " 'isotope_right_most_index',\n", - " 'miss_cleavage', 'mobility_pred',\n", - " 'nAA', \n", - " 'precursor_mz', \n", - " 'rt_pred', 'rt_norm_pred'\n", - " ]\n", - " self.decoy = decoy\n", - " \n", - " @property\n", - " def precursor_df(self)->pd.DataFrame:\n", - " \"\"\": pd.DataFrame : precursor dataframe with columns\n", - " 'sequence', 'mods', 'mod_sites', 'charge', ...\n", - " Identical to `self.peptide_df`.\n", - " \"\"\"\n", - " return self._precursor_df\n", - "\n", - " @precursor_df.setter\n", - " def precursor_df(self, df:pd.DataFrame):\n", - " self._precursor_df = df\n", - " precursor.refine_precursor_df(\n", - " self._precursor_df,\n", - " drop_frag_idx=False,\n", - " ensure_data_validity=True,\n", - " )\n", - "\n", - " @property\n", - " def peptide_df(self)->pd.DataFrame:\n", - " \"\"\": pd.DataFrame : peptide dataframe with columns\n", - " 'sequence', 'mods', 'mod_sites', 'charge', ...\n", - " Identical to `self.precursor_df`.\n", - " \"\"\"\n", - " return self._precursor_df\n", - "\n", - " @peptide_df.setter\n", - " def peptide_df(self, df:pd.DataFrame):\n", - " self.precursor_df = df\n", - "\n", - " @property\n", - " def fragment_mz_df(self)->pd.DataFrame:\n", - " \"\"\": pd.DataFrame : The fragment mz dataframe with \n", - " fragment types as columns (['b_z1', 'y_z2', ...])\n", - " \"\"\"\n", - " return self._fragment_mz_df\n", - "\n", - " @property\n", - " def fragment_intensity_df(self)->pd.DataFrame:\n", - " \"\"\": pd.DataFrame : The fragment intensity dataframe with \n", - " fragment types as columns (['b_z1', 'y_z2', ...])\n", - " \"\"\"\n", - " return self._fragment_intensity_df\n", - "\n", - " def refine_df(self):\n", - " \"\"\"Sort nAA and reset_index for faster calculation (or prediction)\n", - " \"\"\"\n", - " precursor.refine_precursor_df(\n", - " self._precursor_df\n", - " )\n", - "\n", - " def append_decoy_sequence(self):\n", - " \"\"\"Append decoy sequence into precursor_df.\n", - " Decoy method is based on self.decoy(str).\n", - " ```\n", - " decoy_lib = (\n", - " decoy_lib_provider.get_decoy_lib(\n", - " self.decoy, self\n", - " )\n", - " )\n", - " decoy_lib.decoy_sequence()\n", - " ...\n", - " ```\n", - " \"\"\"\n", - " from alphabase.spectral_library.decoy_library import (\n", - " decoy_lib_provider\n", - " )\n", - " decoy_lib = (\n", - " decoy_lib_provider.get_decoy_lib(\n", - " self.decoy, self\n", - " )\n", - " )\n", - " if decoy_lib is None: return None\n", - " decoy_lib.decoy_sequence()\n", - " self._precursor_df['decoy'] = 0\n", - " decoy_lib._precursor_df['decoy'] = 1\n", - " self._precursor_df = pd.concat((\n", - " self._precursor_df,\n", - " decoy_lib._precursor_df\n", - " ))\n", - " self.refine_df()\n", - "\n", - " def clip_by_precursor_mz_(self):\n", - " ''' \n", - " Clip self._precursor_df inplace by self.min_precursor_mz and self.max_precursor_mz\n", - " '''\n", - " self._precursor_df.drop(\n", - " self._precursor_df.loc[\n", - " (self._precursor_df['precursor_mz']self.max_precursor_mz)\n", - " ].index, inplace=True\n", - " )\n", - " self._precursor_df.reset_index(drop=True, inplace=True)\n", - "\n", - "\n", - " def flatten_fragment_data(\n", - " self\n", - " )->typing.Tuple[np.ndarray, np.ndarray]:\n", - " '''\n", - " Create flattened (1-D) np.ndarray for fragment mz and intensity \n", - " dataframes, respectively. The arrays are references to \n", - " original data, that means: \n", - " 1. This method is fast; \n", - " 2. Changing the array values will change the df values. \n", - " They can be unraveled back using:\n", - " `array.reshape(len(self._fragment_mz_df.columns), -1)`\n", - "\n", - " Returns\n", - " -------\n", - " Tuple[np.ndarray, np.ndarray]\n", - " np.ndarray. 1-D flattened mz array (a reference to \n", - " original fragment mz df data)\n", - " np.ndarray. 1-D flattened intensity array (a reference to \n", - " original fragment intensity df data)\n", - " '''\n", - " return (\n", - " self._fragment_mz_df.values.reshape(-1),\n", - " self._fragment_intensity_df.values.reshape(-1)\n", - " )\n", - "\n", - " def calc_precursor_mz(self):\n", - " \"\"\"\n", - " Calculate precursor mz for self._precursor_df,\n", - " and clip the self._precursor_df using `self.clip_by_precursor_mz_`\n", - " \"\"\"\n", - " fragment.update_precursor_mz(self._precursor_df)\n", - " self.clip_by_precursor_mz_()\n", - "\n", - " def update_precursor_mz(self):\n", - " \"\"\"\n", - " Calculate precursor mz for self._precursor_df,\n", - " and clip the self._precursor_df using `self.clip_by_precursor_mz_`\n", - " \"\"\"\n", - " self.calc_precursor_mz()\n", - " \n", - " def calc_precursor_isotope(self, \n", - " multiprocessing:bool=True,\n", - " mp_process_num:int=8,\n", - " mp_process_bar=None,\n", - " min_num_for_mp:int=1000,\n", - " ):\n", - " \"\"\"\n", - " Append isotope columns into self.precursor_df.\n", - " See `alphabase.peptide.precursor.calc_precursor_isotope` for details.\n", - " \"\"\"\n", - " if 'precursor_mz' not in self._precursor_df.columns:\n", - " self.calc_precursor_mz()\n", - " self.clip_by_precursor_mz_()\n", - " if multiprocessing and len(self.precursor_df)>min_num_for_mp:\n", - " (\n", - " self._precursor_df\n", - " ) = precursor.calc_precursor_isotope_mp(\n", - " self.precursor_df, \n", - " processes=mp_process_num,\n", - " process_bar=mp_process_bar,\n", - " )\n", - " else:\n", - " (\n", - " self._precursor_df\n", - " ) = precursor.calc_precursor_isotope(\n", - " self.precursor_df\n", - " )\n", - "\n", - " def calc_fragment_mz_df(self):\n", - " \"\"\"\n", - " TODO: use multiprocessing here or in the\n", - " `create_fragment_mz_dataframe` function.\n", - " \"\"\"\n", - " if 'frag_start_idx' in self.precursor_df.columns:\n", - " return\n", - " if (\n", - " self.charged_frag_types is not None \n", - " or len(self.charged_frag_types)\n", - " ):\n", - " (\n", - " self._fragment_mz_df\n", - " ) = fragment.create_fragment_mz_dataframe(\n", - " self.precursor_df, self.charged_frag_types,\n", - " )\n", - " else:\n", - " print('Skip fragment calculation as fragment type is None')\n", - "\n", - " def hash_precursor_df(self):\n", - " \"\"\"Insert hash codes for peptides and precursors\"\"\"\n", - " precursor.hash_precursor_df(\n", - " self._precursor_df\n", - " )\n", - "\n", - " def _get_hdf_to_save(self, \n", - " hdf_file, \n", - " delete_existing=False\n", - " ):\n", - " \"\"\"Internal function to get a HDF group to write\"\"\"\n", - " _hdf = HDF_File(\n", - " hdf_file, \n", - " read_only=False, \n", - " truncate=True,\n", - " delete_existing=delete_existing\n", - " )\n", - " return _hdf.library\n", - "\n", - " def _get_hdf_to_load(self,\n", - " hdf_file, \n", - " ):\n", - " \"\"\"Internal function to get a HDF group to read\"\"\"\n", - " _hdf = HDF_File(\n", - " hdf_file,\n", - " )\n", - " return _hdf.library\n", - "\n", - " def save_df_to_hdf(self, \n", - " hdf_file:str, \n", - " df_key: str,\n", - " df: pd.DataFrame,\n", - " delete_existing=False\n", - " ):\n", - " \"\"\"Save a new HDF group or dataset into existing HDF file\"\"\"\n", - " self._get_hdf_to_save(\n", - " hdf_file, \n", - " delete_existing=delete_existing\n", - " ).add_group(df_key, df)\n", - "\n", - " def load_df_from_hdf(self, \n", - " hdf_file:str, \n", - " df_name: str\n", - " )->pd.DataFrame:\n", - " \"\"\"Load specific dataset (dataframe) from hdf_file.\n", - "\n", - " Parameters\n", - " ----------\n", - " hdf_file : str\n", - " The hdf file name\n", - "\n", - " df_name : str\n", - " The dataset/dataframe name in the hdf file\n", - "\n", - " Returns\n", - " -------\n", - " pd.DataFrame\n", - " Loaded dataframe\n", - " \"\"\"\n", - " return self._get_hdf_to_load(\n", - " hdf_file\n", - " ).__getattribute__(df_name).values\n", - "\n", - " def save_hdf(self, hdf_file:str):\n", - " \"\"\"Save library dataframes into hdf_file.\n", - " For `self.precursor_df`, this method will save it into two hdf groups:\n", - " hdf_file: `library/precursor_df` and `library/mod_seq_df`.\n", - "\n", - " `library/precursor_df` contains all essential numberic columns those \n", - " can be loaded faster from hdf file into memory:\n", - " 'precursor_mz', 'charge', 'mod_seq_hash', 'mod_seq_charge_hash',\n", - " 'frag_start_idx', 'frag_end_idx', 'decoy', 'rt_pred', 'ccs_pred',\n", - " 'mobility_pred', 'miss_cleave', 'nAA', \n", - " ['isotope_mz_m1', 'isotope_intensity_m1'], ...\n", - "\n", - " `library/mod_seq_df` contains all string columns and the other \n", - " not essential columns:\n", - " 'sequence','mods','mod_sites', ['proteins', 'genes']...\n", - " as well as 'mod_seq_hash', 'mod_seq_charge_hash' columns to map \n", - " back to `precursor_df`\n", - "\n", - " Parameters\n", - " ----------\n", - " hdf_file : str\n", - " the hdf file path to save\n", - " \n", - " \"\"\"\n", - " _hdf = HDF_File(\n", - " hdf_file, \n", - " read_only=False, \n", - " truncate=True,\n", - " delete_existing=True\n", - " )\n", - " if 'mod_seq_charge_hash' not in self._precursor_df.columns:\n", - " self.hash_precursor_df()\n", - "\n", - " key_columns = self.key_numeric_columns+[\n", - " 'mod_seq_hash', 'mod_seq_charge_hash'\n", - " ]\n", - "\n", - " _hdf.library = {\n", - " 'mod_seq_df': self._precursor_df[\n", - " [\n", - " col for col in self._precursor_df.columns \n", - " if col not in self.key_numeric_columns\n", - " ]\n", - " ],\n", - " 'precursor_df': self._precursor_df[\n", - " [\n", - " col for col in self._precursor_df.columns \n", - " if col in key_columns\n", - " ]\n", - " ],\n", - " 'fragment_mz_df': self._fragment_mz_df,\n", - " 'fragment_intensity_df': self._fragment_intensity_df,\n", - " }\n", - " \n", - " def load_hdf(self, hdf_file:str, load_mod_seq:bool=False):\n", - " \"\"\"Load the hdf library from hdf_file\n", - "\n", - " Parameters\n", - " ----------\n", - " hdf_file : str\n", - " hdf library path to load\n", - "\n", - " load_mod_seq : bool, optional\n", - " if also load mod_seq_df. \n", - " Defaults to False.\n", - " \n", - " \"\"\"\n", - " _hdf = HDF_File(\n", - " hdf_file,\n", - " )\n", - " self._precursor_df:pd.DataFrame = _hdf.library.precursor_df.values\n", - " if load_mod_seq:\n", - " key_columns = self.key_numeric_columns+[\n", - " 'mod_seq_hash', 'mod_seq_charge_hash'\n", - " ]\n", - " mod_seq_df = _hdf.library.mod_seq_df.values\n", - " cols = [\n", - " col for col in mod_seq_df.columns \n", - " if col not in key_columns\n", - " ]\n", - " self._precursor_df[cols] = mod_seq_df[cols]\n", - " \n", - " self._fragment_mz_df = _hdf.library.fragment_mz_df.values\n", - " self._fragment_intensity_df = _hdf.library.fragment_intensity_df.values\n", - "\n", - " self._fragment_mz_df = self._fragment_mz_df[\n", - " [\n", - " frag for frag in self.charged_frag_types \n", - " if frag in self._fragment_mz_df.columns\n", - " ]\n", - " ]\n", - " self._fragment_intensity_df = self._fragment_intensity_df[\n", - " [\n", - " frag for frag in self.charged_frag_types \n", - " if frag in self._fragment_intensity_df.columns\n", - " ]\n", - " ]\n", - " " + "from alphabase.spectral_library.base import *" ] }, { @@ -487,8 +45,6 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L149){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", "### SpecLibBase.append_decoy_sequence\n", "\n", "> SpecLibBase.append_decoy_sequence ()\n", @@ -496,20 +52,14 @@ "Append decoy sequence into precursor_df.\n", "Decoy method is based on self.decoy(str).\n", "```\n", - "decoy_lib = (\n", - " decoy_lib_provider.get_decoy_lib(\n", - " self.decoy, self\n", - " )\n", - ")\n", - "decoy_lib.decoy_sequence()\n", + ">>> decoy_lib = (decoy_lib_provider.get_decoy_lib( self.decoy, self))\n", + ">>> decoy_lib.decoy_sequence()\n", "...\n", "```" ], "text/plain": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L149){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", "### SpecLibBase.append_decoy_sequence\n", "\n", "> SpecLibBase.append_decoy_sequence ()\n", @@ -517,12 +67,8 @@ "Append decoy sequence into precursor_df.\n", "Decoy method is based on self.decoy(str).\n", "```\n", - "decoy_lib = (\n", - " decoy_lib_provider.get_decoy_lib(\n", - " self.decoy, self\n", - " )\n", - ")\n", - "decoy_lib.decoy_sequence()\n", + ">>> decoy_lib = (decoy_lib_provider.get_decoy_lib( self.decoy, self))\n", + ">>> decoy_lib.decoy_sequence()\n", "...\n", "```" ] @@ -546,8 +92,6 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L280){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", "### SpecLibBase.hash_precursor_df\n", "\n", "> SpecLibBase.hash_precursor_df ()\n", @@ -557,8 +101,6 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L280){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", "### SpecLibBase.hash_precursor_df\n", "\n", "> SpecLibBase.hash_precursor_df ()\n", @@ -585,32 +127,22 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L233){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "### SpecLibBase.remove_unused_fragments\n", "\n", - "### SpecLibBase.calc_precursor_isotope\n", + "> SpecLibBase.remove_unused_fragments ()\n", "\n", - "> SpecLibBase.calc_precursor_isotope (multiprocessing:bool=True,\n", - "> mp_process_num:int=8,\n", - "> mp_process_bar=None,\n", - "> min_num_for_mp:int=1000)\n", - "\n", - "Append isotope columns into self.precursor_df.\n", - "See `alphabase.peptide.precursor.calc_precursor_isotope` for details." + "Remove unused fragments from self._fragment_mz_df and self._fragment_intensity_df.\n", + "Fragment dataframes are updated inplace and overwritten." ], "text/plain": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L233){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### SpecLibBase.calc_precursor_isotope\n", + "### SpecLibBase.remove_unused_fragments\n", "\n", - "> SpecLibBase.calc_precursor_isotope (multiprocessing:bool=True,\n", - "> mp_process_num:int=8,\n", - "> mp_process_bar=None,\n", - "> min_num_for_mp:int=1000)\n", + "> SpecLibBase.remove_unused_fragments ()\n", "\n", - "Append isotope columns into self.precursor_df.\n", - "See `alphabase.peptide.precursor.calc_precursor_isotope` for details." + "Remove unused fragments from self._fragment_mz_df and self._fragment_intensity_df.\n", + "Fragment dataframes are updated inplace and overwritten." ] }, "execution_count": null, @@ -619,7 +151,7 @@ } ], "source": [ - "show_doc(SpecLibBase.calc_precursor_isotope)" + "show_doc(SpecLibBase.remove_unused_fragments)" ] }, { @@ -632,36 +164,28 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L193){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### SpecLibBase.flatten_fragment_data\n", + "### SpecLibBase.calc_precursor_isotope\n", "\n", - "> SpecLibBase.flatten_fragment_data ()\n", + "> SpecLibBase.calc_precursor_isotope (multiprocessing:bool=True,\n", + "> mp_process_num:int=8,\n", + "> mp_process_bar=None,\n", + "> min_precursor_num_to_run_mp:int=1000)\n", "\n", - "Create flattened (1-D) np.ndarray for fragment mz and intensity \n", - "dataframes, respectively. The arrays are references to \n", - "original data, that means: \n", - " 1. This method is fast; \n", - " 2. Changing the array values will change the df values. \n", - "They can be unraveled back using:\n", - " `array.reshape(len(self._fragment_mz_df.columns), -1)`" + "Append isotope columns into self.precursor_df.\n", + "See `alphabase.peptide.precursor.calc_precursor_isotope` for details." ], "text/plain": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L193){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", - "### SpecLibBase.flatten_fragment_data\n", + "### SpecLibBase.calc_precursor_isotope\n", "\n", - "> SpecLibBase.flatten_fragment_data ()\n", + "> SpecLibBase.calc_precursor_isotope (multiprocessing:bool=True,\n", + "> mp_process_num:int=8,\n", + "> mp_process_bar=None,\n", + "> min_precursor_num_to_run_mp:int=1000)\n", "\n", - "Create flattened (1-D) np.ndarray for fragment mz and intensity \n", - "dataframes, respectively. The arrays are references to \n", - "original data, that means: \n", - " 1. This method is fast; \n", - " 2. Changing the array values will change the df values. \n", - "They can be unraveled back using:\n", - " `array.reshape(len(self._fragment_mz_df.columns), -1)`" + "Append isotope columns into self.precursor_df.\n", + "See `alphabase.peptide.precursor.calc_precursor_isotope` for details." ] }, "execution_count": null, @@ -670,7 +194,7 @@ } ], "source": [ - "show_doc(SpecLibBase.flatten_fragment_data)" + "show_doc(SpecLibBase.calc_precursor_isotope)" ] }, { @@ -683,8 +207,6 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L218){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", "### SpecLibBase.calc_precursor_mz\n", "\n", "> SpecLibBase.calc_precursor_mz ()\n", @@ -695,8 +217,6 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L218){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", "### SpecLibBase.calc_precursor_mz\n", "\n", "> SpecLibBase.calc_precursor_mz ()\n", @@ -724,8 +244,6 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L180){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", "### SpecLibBase.clip_by_precursor_mz_\n", "\n", "> SpecLibBase.clip_by_precursor_mz_ ()\n", @@ -735,8 +253,6 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L180){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", "### SpecLibBase.clip_by_precursor_mz_\n", "\n", "> SpecLibBase.clip_by_precursor_mz_ ()\n", @@ -763,8 +279,6 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L397){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", "### SpecLibBase.load_hdf\n", "\n", "> SpecLibBase.load_hdf (hdf_file:str, load_mod_seq:bool=False)\n", @@ -779,8 +293,6 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L397){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", "### SpecLibBase.load_hdf\n", "\n", "> SpecLibBase.load_hdf (hdf_file:str, load_mod_seq:bool=False)\n", @@ -812,8 +324,6 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L320){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", "### SpecLibBase.load_df_from_hdf\n", "\n", "> SpecLibBase.load_df_from_hdf (hdf_file:str, df_name:str)\n", @@ -829,8 +339,6 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L320){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", "### SpecLibBase.load_df_from_hdf\n", "\n", "> SpecLibBase.load_df_from_hdf (hdf_file:str, df_name:str)\n", @@ -863,26 +371,25 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L343){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", "### SpecLibBase.save_hdf\n", "\n", "> SpecLibBase.save_hdf (hdf_file:str)\n", "\n", "Save library dataframes into hdf_file.\n", - "For `self.precursor_df`, this method will save it into two hdf groups:\n", - " hdf_file: `library/precursor_df` and `library/mod_seq_df`.\n", + "For `self.precursor_df`, this method will save it into two hdf groups in hdf_file:\n", + "`library/precursor_df` and `library/mod_seq_df`.\n", "\n", "`library/precursor_df` contains all essential numberic columns those \n", "can be loaded faster from hdf file into memory:\n", - " 'precursor_mz', 'charge', 'mod_seq_hash', 'mod_seq_charge_hash',\n", - " 'frag_start_idx', 'frag_end_idx', 'decoy', 'rt_pred', 'ccs_pred',\n", - " 'mobility_pred', 'miss_cleave', 'nAA', \n", - " ['isotope_mz_m1', 'isotope_intensity_m1'], ...\n", + "\n", + "'precursor_mz', 'charge', 'mod_seq_hash', 'mod_seq_charge_hash',\n", + "'frag_start_idx', 'frag_end_idx', 'decoy', 'rt_pred', 'ccs_pred',\n", + "'mobility_pred', 'miss_cleave', 'nAA', \n", + "['isotope_mz_m1', 'isotope_intensity_m1'], ...\n", "\n", "`library/mod_seq_df` contains all string columns and the other \n", "not essential columns:\n", - " 'sequence','mods','mod_sites', ['proteins', 'genes']...\n", + "'sequence','mods','mod_sites', ['proteins', 'genes']...\n", "as well as 'mod_seq_hash', 'mod_seq_charge_hash' columns to map \n", "back to `precursor_df`\n", "\n", @@ -893,26 +400,25 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L343){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", "### SpecLibBase.save_hdf\n", "\n", "> SpecLibBase.save_hdf (hdf_file:str)\n", "\n", "Save library dataframes into hdf_file.\n", - "For `self.precursor_df`, this method will save it into two hdf groups:\n", - " hdf_file: `library/precursor_df` and `library/mod_seq_df`.\n", + "For `self.precursor_df`, this method will save it into two hdf groups in hdf_file:\n", + "`library/precursor_df` and `library/mod_seq_df`.\n", "\n", "`library/precursor_df` contains all essential numberic columns those \n", "can be loaded faster from hdf file into memory:\n", - " 'precursor_mz', 'charge', 'mod_seq_hash', 'mod_seq_charge_hash',\n", - " 'frag_start_idx', 'frag_end_idx', 'decoy', 'rt_pred', 'ccs_pred',\n", - " 'mobility_pred', 'miss_cleave', 'nAA', \n", - " ['isotope_mz_m1', 'isotope_intensity_m1'], ...\n", + "\n", + "'precursor_mz', 'charge', 'mod_seq_hash', 'mod_seq_charge_hash',\n", + "'frag_start_idx', 'frag_end_idx', 'decoy', 'rt_pred', 'ccs_pred',\n", + "'mobility_pred', 'miss_cleave', 'nAA', \n", + "['isotope_mz_m1', 'isotope_intensity_m1'], ...\n", "\n", "`library/mod_seq_df` contains all string columns and the other \n", "not essential columns:\n", - " 'sequence','mods','mod_sites', ['proteins', 'genes']...\n", + "'sequence','mods','mod_sites', ['proteins', 'genes']...\n", "as well as 'mod_seq_hash', 'mod_seq_charge_hash' columns to map \n", "back to `precursor_df`\n", "\n", @@ -940,8 +446,6 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L308){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", "### SpecLibBase.save_df_to_hdf\n", "\n", "> SpecLibBase.save_df_to_hdf (hdf_file:str, df_key:str,\n", @@ -953,8 +457,6 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L308){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", "### SpecLibBase.save_df_to_hdf\n", "\n", "> SpecLibBase.save_df_to_hdf (hdf_file:str, df_key:str,\n", @@ -983,8 +485,6 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L142){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", "### SpecLibBase.refine_df\n", "\n", "> SpecLibBase.refine_df ()\n", @@ -994,8 +494,6 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L142){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", "### SpecLibBase.refine_df\n", "\n", "> SpecLibBase.refine_df ()\n", @@ -1022,14 +520,12 @@ "text/markdown": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L233){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", "### SpecLibBase.calc_precursor_isotope\n", "\n", "> SpecLibBase.calc_precursor_isotope (multiprocessing:bool=True,\n", "> mp_process_num:int=8,\n", "> mp_process_bar=None,\n", - "> min_num_for_mp:int=1000)\n", + "> min_precursor_num_to_run_mp:int=1000)\n", "\n", "Append isotope columns into self.precursor_df.\n", "See `alphabase.peptide.precursor.calc_precursor_isotope` for details." @@ -1037,14 +533,12 @@ "text/plain": [ "---\n", "\n", - "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/spectral_library/library_base.py#L233){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", - "\n", "### SpecLibBase.calc_precursor_isotope\n", "\n", "> SpecLibBase.calc_precursor_isotope (multiprocessing:bool=True,\n", "> mp_process_num:int=8,\n", "> mp_process_bar=None,\n", - "> min_num_for_mp:int=1000)\n", + "> min_precursor_num_to_run_mp:int=1000)\n", "\n", "Append isotope columns into self.precursor_df.\n", "See `alphabase.peptide.precursor.calc_precursor_isotope` for details." @@ -1286,7 +780,7 @@ "assert len(precursor_df)==len(df)\n", "df = target_lib.load_df_from_hdf('sandbox/test_lib.hdf', 'protein_df')\n", "assert len(df)==2\n", - "os.remove('sandbox/test_lib.hdf')\n", + "#os.remove('sandbox/test_lib.hdf')\n", "precursor_df" ] }, @@ -1679,13 +1173,118 @@ "cell_type": "code", "execution_count": null, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2022-12-21 13:45:10> Speclib with 4 precursors will be reannotated with speclib with 12 precursors and 504 fragments\n", + "2022-12-21 13:45:11> A total of 4 precursors were succesfully annotated, 0 precursors were not matched\n", + "2022-12-21 13:45:11> Speclib with 4 precursors will be reannotated with speclib with 12 precursors and 504 fragments\n", + "2022-12-21 13:45:11> A total of 4 precursors were succesfully annotated, 0 precursors were not matched\n" + ] + } + ], + "source": [ + "\n", + "repeat = 3\n", + "peptides = ['AGHCEWQMK']*repeat\n", + "mods = ['Acetyl@Protein N-term;Carbamidomethyl@C;Oxidation@M']*repeat\n", + "sites = ['0;4;8']*repeat\n", + "peptides += ['AGHCEWQMKAADER']*repeat\n", + "mods += ['']*repeat\n", + "sites += ['']*repeat\n", + "\n", + "precursor_df = pd.DataFrame({\n", + " 'sequence': peptides,\n", + " 'mods': mods,\n", + " 'mod_sites': sites\n", + "})\n", + "precursor_df['nAA'] = precursor_df['sequence'].str.len()\n", + "precursor_df['charge'] = 2\n", + "empty_lib = SpecLibBase(\n", + " ['b_z1','b_z2','y_z1','y_z2'],\n", + " decoy='pseudo_reverse'\n", + ")\n", + "empty_lib._precursor_df = precursor_df\n", + "empty_lib.calc_precursor_mz()\n", + "empty_lib.append_decoy_sequence()\n", + "\n", + "\n", + "# annotate only fragment mz\n", + "fragment_lib = SpecLibBase()\n", + "fragment_lib._precursor_df = empty_lib.precursor_df.copy()\n", + "fragment_lib.calc_fragment_mz_df()\n", + "\n", + "empty_lib._precursor_df = empty_lib._precursor_df.sample(4)\n", + "empty_lib.annotate_fragments_from_speclib(fragment_lib, verbose=True)\n", + "\n", + "size_before = len(empty_lib.fragment_mz_df)\n", + "empty_lib.remove_unused_fragments()\n", + "assert(size_before > len(empty_lib.fragment_mz_df))\n", + "\n", + "# annotate both fragment mz and fragment intensity \n", + "fragment_lib._fragment_intensity_df = pd.DataFrame(0, index=np.arange(len(fragment_lib.fragment_mz_df)), columns=fragment_lib.fragment_mz_df.columns)\n", + "\n", + "empty_lib.annotate_fragments_from_speclib(fragment_lib, verbose=True)\n", + "size_before_mz = len(empty_lib.fragment_mz_df)\n", + "size_before_intensity = len(empty_lib.fragment_intensity_df)\n", + "\n", + "empty_lib.remove_unused_fragments()\n", + "assert(size_before_mz > len(empty_lib.fragment_mz_df))\n", + "assert(size_before_intensity > len(empty_lib.fragment_intensity_df))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2022-12-21 13:45:11> Speclib with 12 precursors will be reannotated with speclib with 12 precursors and 504 fragments\n", + "2022-12-21 13:45:11> A total of 12 precursors were succesfully annotated, 0 precursors were not matched\n" + ] + } + ], + "source": [ + "\n", + "repeat = 3\n", + "peptides = ['AGHCEWQMK']*repeat\n", + "mods = ['Acetyl@Protein N-term;Carbamidomethyl@C;Oxidation@M']*repeat\n", + "sites = ['0;4;8']*repeat\n", + "peptides += ['AGHCEWQMKAADER']*repeat\n", + "mods += ['']*repeat\n", + "sites += ['']*repeat\n", + "\n", + "precursor_df = pd.DataFrame({\n", + " 'sequence': peptides,\n", + " 'mods': mods,\n", + " 'mod_sites': sites\n", + "})\n", + "precursor_df['nAA'] = precursor_df['sequence'].str.len()\n", + "precursor_df['charge'] = 2\n", + "empty_lib = SpecLibBase(\n", + " ['b_z1','b_z2','y_z1','y_z2'],\n", + " decoy='pseudo_reverse'\n", + ")\n", + "empty_lib._precursor_df = precursor_df\n", + "empty_lib.calc_precursor_mz()\n", + "empty_lib.append_decoy_sequence()\n", + "\n", + "fragment_lib = SpecLibBase()\n", + "fragment_lib._precursor_df = empty_lib.precursor_df\n", + "fragment_lib.calc_fragment_mz_df()\n", + "\n", + "empty_lib = annotate_fragments_from_speclib(empty_lib, fragment_lib)" + ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3.8.3 ('base')", + "display_name": "alpha", "language": "python", "name": "python3" } diff --git a/nbdev_nbs/spectral_library/library_reader.ipynb b/nbdev_nbs/spectral_library/library_reader.ipynb new file mode 100644 index 00000000..c2b085d5 --- /dev/null +++ b/nbdev_nbs/spectral_library/library_reader.ipynb @@ -0,0 +1,2331 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#---#| default_exp spectral_library.reader" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Library Reader" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "SWATH/Spectronaut TSV library reader (`SWATHLibraryReader`)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from alphabase.spectral_library.reader import *" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#|hide\n", + "from io import StringIO" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sequencechargertmobilitymodsmod_sitesnAAfrag_start_idxfrag_end_idxrt_normprecursor_mzccs
0AVVVSPK2-22.8497400.9Phospho@S57060.075327390.206780366.858877
1DPLAVDK2-15.0871000.976120.199375379.208161367.043100
2MGSLDSK2-27.5635000.9Phospho@S3712180.000000409.161712366.564438
3SVSFSLK135.0141100.9Phospho@S3718241.000000847.396112183.178171
4VSVSPGR2-23.9308500.9Phospho@S;Phospho@S2;4724300.058050431.167001366.254833
5YSLSPSK2-6.4281980.9Phospho@S4730360.337745431.191327366.254509
\n", + "
" + ], + "text/plain": [ + " sequence charge rt mobility mods mod_sites nAA \\\n", + "0 AVVVSPK 2 -22.849740 0.9 Phospho@S 5 7 \n", + "1 DPLAVDK 2 -15.087100 0.9 7 \n", + "2 MGSLDSK 2 -27.563500 0.9 Phospho@S 3 7 \n", + "3 SVSFSLK 1 35.014110 0.9 Phospho@S 3 7 \n", + "4 VSVSPGR 2 -23.930850 0.9 Phospho@S;Phospho@S 2;4 7 \n", + "5 YSLSPSK 2 -6.428198 0.9 Phospho@S 4 7 \n", + "\n", + " frag_start_idx frag_end_idx rt_norm precursor_mz ccs \n", + "0 0 6 0.075327 390.206780 366.858877 \n", + "1 6 12 0.199375 379.208161 367.043100 \n", + "2 12 18 0.000000 409.161712 366.564438 \n", + "3 18 24 1.000000 847.396112 183.178171 \n", + "4 24 30 0.058050 431.167001 366.254833 \n", + "5 30 36 0.337745 431.191327 366.254509 " + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| hide\n", + "tsv_str = \"\"\"PrecursorCharge\tModifiedPeptide\tStrippedPeptide\tiRT\tLabeledPeptide\tPrecursorMz\tFragmentLossType\tFragmentNumber\tFragmentType\tFragmentCharge\tFragmentMz\tRelativeIntensity\tIonMobility\n", + "2\t_DPLAVDK_\tDPLAVDK\t-15.0871\t_DPLAVDK_\t379.2081611\tnoloss\t3\tb\t1\t326.1710473\t14.37029\t0.9\n", + "2\t_DPLAVDK_\tDPLAVDK\t-15.0871\t_DPLAVDK_\t379.2081611\tnoloss\t3\ty\t1\t361.2081611\t37.7585\t0.9\n", + "2\t_DPLAVDK_\tDPLAVDK\t-15.0871\t_DPLAVDK_\t379.2081611\tnoloss\t4\tb\t1\t397.2081611\t9.488808\t0.9\n", + "2\t_DPLAVDK_\tDPLAVDK\t-15.0871\t_DPLAVDK_\t379.2081611\tnoloss\t4\ty\t1\t432.2452749\t100\t0.9\n", + "2\t_DPLAVDK_\tDPLAVDK\t-15.0871\t_DPLAVDK_\t379.2081611\tnoloss\t5\tb\t1\t496.276575\t5.498003\t0.9\n", + "2\t_DPLAVDK_\tDPLAVDK\t-15.0871\t_DPLAVDK_\t379.2081611\tnoloss\t5\ty\t1\t545.3293389\t74.56643\t0.9\n", + "2\t_DPLAVDK_\tDPLAVDK\t-15.0871\t_DPLAVDK_\t379.2081611\tnoloss\t6\ty\t2\t321.6946896\t51.50719\t0.9\n", + "2\t_AVVVS[Phospho (STY)]PK_\tAVVVSPK\t-22.84974\t_AVVVS[Phospho (STY)]PK_\t390.2067795\tnoloss\t3\ty\t1\t411.1639269\t6.911595\t0.9\n", + "2\t_AVVVS[Phospho (STY)]PK_\tAVVVSPK\t-22.84974\t_AVVVS[Phospho (STY)]PK_\t390.2067795\tH3PO4\t3\ty\t1\t313.1870287\t17.38582\t0.9\n", + "2\t_AVVVS[Phospho (STY)]PK_\tAVVVSPK\t-22.84974\t_AVVVS[Phospho (STY)]PK_\t390.2067795\tnoloss\t4\ty\t1\t510.2323409\t10.65426\t0.9\n", + "2\t_AVVVS[Phospho (STY)]PK_\tAVVVSPK\t-22.84974\t_AVVVS[Phospho (STY)]PK_\t390.2067795\tH3PO4\t4\ty\t1\t412.2554427\t37.41231\t0.9\n", + "2\t_AVVVS[Phospho (STY)]PK_\tAVVVSPK\t-22.84974\t_AVVVS[Phospho (STY)]PK_\t390.2067795\tnoloss\t5\ty\t1\t609.3007548\t45.03617\t0.9\n", + "2\t_AVVVS[Phospho (STY)]PK_\tAVVVSPK\t-22.84974\t_AVVVS[Phospho (STY)]PK_\t390.2067795\tH3PO4\t5\ty\t1\t511.3238566\t100\t0.9\n", + "2\t_MGS[Phospho (STY)]LDSK_\tMGSLDSK\t-27.5635\t_MGS[Phospho (STY)]LDSK_\t409.1617118\tnoloss\t3\ty\t1\t349.1717756\t9.20575\t0.9\n", + "2\t_MGS[Phospho (STY)]LDSK_\tMGSLDSK\t-27.5635\t_MGS[Phospho (STY)]LDSK_\t409.1617118\tnoloss\t6\ty\t1\t686.2756622\t10.37339\t0.9\n", + "2\t_MGS[Phospho (STY)]LDSK_\tMGSLDSK\t-27.5635\t_MGS[Phospho (STY)]LDSK_\t409.1617118\tH3PO4\t6\ty\t1\t588.298764\t100\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tnoloss\t3\ty\t1\t347.2288965\t88.27327\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tH3PO4\t3\tb\t1\t256.1291795\t64.97146\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tnoloss\t4\ty\t1\t494.2973105\t100\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tH3PO4\t4\tb\t1\t403.1975934\t35.17805\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tnoloss\t5\ty\t1\t661.2956694\t19.89741\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tH3PO4\t5\tb\t1\t490.2296218\t40.04738\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tH3PO4\t5\ty\t1\t563.3187712\t77.43164\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tnoloss\t6\tb\t1\t701.290584\t24.43497\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\tH3PO4\t6\tb\t1\t603.3136858\t63.09999\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\t1(+H2+O)1(+H3+O4+P)\t3\tb\t1\t238.1186147\t62.60851\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\t1(+H2+O)1(+H3+O4+P)\t5\tb\t1\t472.219057\t22.99903\t0.9\n", + "1\t_SVS[Phospho (STY)]FSLK_\tSVSFSLK\t35.01411\t_SVS[Phospho (STY)]FSLK_\t847.3961117\t1(+H2+O)1(+H3+O4+P)\t6\tb\t1\t585.303121\t66.30389\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tnoloss\t3\ty\t1\t329.1931797\t100\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tH3PO4\t3\tb\t1\t268.165565\t5.755442\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tnoloss\t4\tb\t2\t267.0740493\t8.743931\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tnoloss\t4\ty\t1\t496.1915387\t27.69686\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tH3PO4\t4\tb\t1\t435.1639239\t6.162673\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\t2(+H3+O4+P)\t4\tb\t1\t337.1870258\t10.84257\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tH3PO4\t4\ty\t1\t398.2146405\t26.28527\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tH3PO4\t5\ty\t1\t497.2830544\t28.41294\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tnoloss\t6\ty\t1\t762.2583115\t8.490795\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\tH3PO4\t6\ty\t1\t664.2814133\t32.87384\t0.9\n", + "2\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\tVSVSPGR\t-23.93085\t_VS[Phospho (STY)]VS[Phospho (STY)]PGR_\t431.1670009\t2(+H3+O4+P)\t6\ty\t1\t566.3045151\t35.87218\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\tnoloss\t3\ty\t1\t331.1975964\t49.20179\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\tnoloss\t4\ty\t1\t498.1959553\t10.89141\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\tH3PO4\t4\ty\t1\t400.2190571\t27.99594\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\tnoloss\t5\ty\t1\t611.2800193\t14.11057\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\tH3PO4\t5\ty\t1\t513.3031211\t70.5295\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\tnoloss\t6\ty\t1\t698.3120477\t60.23455\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\tH3PO4\t6\ty\t1\t600.3351495\t100\t0.9\n", + "2\t_YSLS[Phospho (STY)]PSK_\tYSLSPSK\t-6.428198\t_YSLS[Phospho (STY)]PSK_\t431.1913264\t1(+H2+O)1(+H3+O4+P)\t6\ty\t1\t582.3245847\t5.233977\t0.9\n", + "\"\"\"\n", + "\n", + "reader = SWATHLibraryReader()\n", + "psm_df = reader.import_file(StringIO(tsv_str))\n", + "for col in ['sequence','charge','rt','rt_norm','mods','mod_sites','nAA','frag_start_idx','frag_end_idx']:\n", + " assert col in psm_df.columns\n", + "reader.psm_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
b_z1b_z2y_z1y_z2b_modloss_z1b_modloss_z2y_modloss_z1y_modloss_z2
00.0000000.0000000.0000000.0000000.0000000.00.0000000.0
10.0000000.0000000.4503620.0000000.0000000.01.0000000.0
20.0000000.0000000.1065430.0000000.0000000.00.3741230.0
30.0000000.0000000.0691160.0000000.0000000.00.1738580.0
40.0000000.0000000.0000000.0000000.0000000.00.0000000.0
50.0000000.0000000.0000000.0000000.0000000.00.0000000.0
60.0000000.0000000.0000000.5150720.0000000.00.0000000.0
70.0000000.0000000.7456640.0000000.0000000.00.0000000.0
80.1437030.0000001.0000000.0000000.0000000.00.0000000.0
90.0948880.0000000.3775850.0000000.0000000.00.0000000.0
100.0549800.0000000.0000000.0000000.0000000.00.0000000.0
110.0000000.0000000.0000000.0000000.0000000.00.0000000.0
120.0000000.0000000.1037340.0000000.0000000.01.0000000.0
130.0000000.0000000.0000000.0000000.0000000.00.0000000.0
140.0000000.0000000.0000000.0000000.0000000.00.0000000.0
150.0000000.0000000.0920580.0000000.0000000.00.0000000.0
160.0000000.0000000.0000000.0000000.0000000.00.0000000.0
170.0000000.0000000.0000000.0000000.0000000.00.0000000.0
180.0000000.0000000.0000000.0000000.0000000.00.0000000.0
190.0000000.0000000.1989740.0000000.0000000.00.7743160.0
200.0000000.0000001.0000000.0000000.6497150.00.0000000.0
210.0000000.0000000.8827330.0000000.3517810.00.0000000.0
220.0000000.0000000.0000000.0000000.4004740.00.0000000.0
230.2443500.0000000.0000000.0000000.6310000.00.0000000.0
240.0000000.0000000.0849080.0000000.0000000.00.3287380.0
250.0000000.0000000.0000000.0000000.0000000.00.2841290.0
260.0000000.0000000.2769690.0000000.0575540.00.2628530.0
270.0000000.0874391.0000000.0000000.0616270.00.0000000.0
280.0000000.0000000.0000000.0000000.0000000.00.0000000.0
290.0000000.0000000.0000000.0000000.0000000.00.0000000.0
300.0000000.0000000.6023460.0000000.0000000.01.0000000.0
310.0000000.0000000.1411060.0000000.0000000.00.7052950.0
320.0000000.0000000.1089140.0000000.0000000.00.2799590.0
330.0000000.0000000.4920180.0000000.0000000.00.0000000.0
340.0000000.0000000.0000000.0000000.0000000.00.0000000.0
350.0000000.0000000.0000000.0000000.0000000.00.0000000.0
\n", + "
" + ], + "text/plain": [ + " b_z1 b_z2 y_z1 y_z2 b_modloss_z1 b_modloss_z2 \\\n", + "0 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "1 0.000000 0.000000 0.450362 0.000000 0.000000 0.0 \n", + "2 0.000000 0.000000 0.106543 0.000000 0.000000 0.0 \n", + "3 0.000000 0.000000 0.069116 0.000000 0.000000 0.0 \n", + "4 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "5 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "6 0.000000 0.000000 0.000000 0.515072 0.000000 0.0 \n", + "7 0.000000 0.000000 0.745664 0.000000 0.000000 0.0 \n", + "8 0.143703 0.000000 1.000000 0.000000 0.000000 0.0 \n", + "9 0.094888 0.000000 0.377585 0.000000 0.000000 0.0 \n", + "10 0.054980 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "11 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "12 0.000000 0.000000 0.103734 0.000000 0.000000 0.0 \n", + "13 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "14 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "15 0.000000 0.000000 0.092058 0.000000 0.000000 0.0 \n", + "16 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "17 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "18 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "19 0.000000 0.000000 0.198974 0.000000 0.000000 0.0 \n", + "20 0.000000 0.000000 1.000000 0.000000 0.649715 0.0 \n", + "21 0.000000 0.000000 0.882733 0.000000 0.351781 0.0 \n", + "22 0.000000 0.000000 0.000000 0.000000 0.400474 0.0 \n", + "23 0.244350 0.000000 0.000000 0.000000 0.631000 0.0 \n", + "24 0.000000 0.000000 0.084908 0.000000 0.000000 0.0 \n", + "25 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "26 0.000000 0.000000 0.276969 0.000000 0.057554 0.0 \n", + "27 0.000000 0.087439 1.000000 0.000000 0.061627 0.0 \n", + "28 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "29 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "30 0.000000 0.000000 0.602346 0.000000 0.000000 0.0 \n", + "31 0.000000 0.000000 0.141106 0.000000 0.000000 0.0 \n", + "32 0.000000 0.000000 0.108914 0.000000 0.000000 0.0 \n", + "33 0.000000 0.000000 0.492018 0.000000 0.000000 0.0 \n", + "34 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "35 0.000000 0.000000 0.000000 0.000000 0.000000 0.0 \n", + "\n", + " y_modloss_z1 y_modloss_z2 \n", + "0 0.000000 0.0 \n", + "1 1.000000 0.0 \n", + "2 0.374123 0.0 \n", + "3 0.173858 0.0 \n", + "4 0.000000 0.0 \n", + "5 0.000000 0.0 \n", + "6 0.000000 0.0 \n", + "7 0.000000 0.0 \n", + "8 0.000000 0.0 \n", + "9 0.000000 0.0 \n", + "10 0.000000 0.0 \n", + "11 0.000000 0.0 \n", + "12 1.000000 0.0 \n", + "13 0.000000 0.0 \n", + "14 0.000000 0.0 \n", + "15 0.000000 0.0 \n", + "16 0.000000 0.0 \n", + "17 0.000000 0.0 \n", + "18 0.000000 0.0 \n", + "19 0.774316 0.0 \n", + "20 0.000000 0.0 \n", + "21 0.000000 0.0 \n", + "22 0.000000 0.0 \n", + "23 0.000000 0.0 \n", + "24 0.328738 0.0 \n", + "25 0.284129 0.0 \n", + "26 0.262853 0.0 \n", + "27 0.000000 0.0 \n", + "28 0.000000 0.0 \n", + "29 0.000000 0.0 \n", + "30 1.000000 0.0 \n", + "31 0.705295 0.0 \n", + "32 0.279959 0.0 \n", + "33 0.000000 0.0 \n", + "34 0.000000 0.0 \n", + "35 0.000000 0.0 " + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| hide\n", + "reader.fragment_intensity_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
b_z1b_z2y_z1y_z2b_modloss_z1b_modloss_z2y_modloss_z1y_modloss_z2
072.04439036.525833708.369169354.6882230.0000000.000000610.392273305.699775
1171.11280486.060040609.300755305.1540160.0000000.000000511.323860256.165568
2270.181218135.594247510.232341255.6198090.0000000.000000412.255446206.631361
3369.249632185.128454411.163927206.0856020.0000000.000000313.187032157.097154
4536.247991268.627634244.165568122.586422438.271096219.6391860.0000000.000000
5633.300755317.154016147.11280474.060040535.323860268.1655680.0000000.000000
6116.03421958.520748642.382103321.6946900.0000000.0000000.0000000.000000
7213.086983107.047130545.329339273.1683080.0000000.0000000.0000000.000000
8326.171047163.589162432.245275216.6262760.0000000.0000000.0000000.000000
9397.208161199.107719361.208161181.1077190.0000000.0000000.0000000.000000
10496.276575248.641926262.139747131.5735120.0000000.0000000.0000000.000000
11611.303518306.155397147.11280474.0600400.0000000.0000000.0000000.000000
12132.04776266.527519686.275663343.6414700.0000000.000000588.298767294.653022
13189.06922595.038251629.254199315.1307380.0000000.000000531.277303266.142290
14356.067585178.537431462.255840231.631558258.090689129.5489830.0000000.000000
15469.151649235.079463349.171776175.089526371.174753186.0910150.0000000.000000
16584.178592292.592934234.144833117.576055486.201696243.6044860.0000000.000000
17671.210620336.108948147.11280474.060040573.233724287.1205000.0000000.000000
1888.0393050.000000760.3640840.0000000.0000000.000000662.3871880.000000
19187.1077190.000000661.2956700.0000000.0000000.000000563.3187740.000000
20354.1060780.000000494.2973100.000000256.1291830.0000000.0000000.000000
21501.1744920.000000347.2288970.000000403.1975960.0000000.0000000.000000
22588.2065200.000000260.1968680.000000490.2296250.0000000.0000000.000000
23701.2905840.000000147.1128040.000000603.3136890.0000000.0000000.000000
24100.07569050.541483762.258312381.6327940.0000000.000000664.281417332.644347
25267.074050134.040663595.259953298.133615169.09715485.052215497.283057249.145167
26366.142464183.574870496.191539248.599408268.165568134.586422398.214643199.610960
27533.140823267.074050329.193180165.100228435.163927218.0856020.0000000.000000
28630.193587315.600432232.140416116.573846532.216691266.6119840.0000000.000000
29687.215050344.111163175.11895288.063114589.238155295.1227160.0000000.000000
30164.07060582.538941698.312048349.6596620.0000000.000000600.335153300.671214
31251.102633126.054955611.280020306.1436480.0000000.000000513.303124257.155200
32364.186697182.596987498.195956249.6016160.0000000.000000400.219060200.613168
33531.185057266.096167331.197596166.102436433.208161217.1077190.0000000.000000
34628.237821314.622548234.144833117.576055530.260925265.6341010.0000000.000000
35715.269849358.138563147.11280474.060040617.292953309.1501150.0000000.000000
\n", + "
" + ], + "text/plain": [ + " b_z1 b_z2 y_z1 y_z2 b_modloss_z1 \\\n", + "0 72.044390 36.525833 708.369169 354.688223 0.000000 \n", + "1 171.112804 86.060040 609.300755 305.154016 0.000000 \n", + "2 270.181218 135.594247 510.232341 255.619809 0.000000 \n", + "3 369.249632 185.128454 411.163927 206.085602 0.000000 \n", + "4 536.247991 268.627634 244.165568 122.586422 438.271096 \n", + "5 633.300755 317.154016 147.112804 74.060040 535.323860 \n", + "6 116.034219 58.520748 642.382103 321.694690 0.000000 \n", + "7 213.086983 107.047130 545.329339 273.168308 0.000000 \n", + "8 326.171047 163.589162 432.245275 216.626276 0.000000 \n", + "9 397.208161 199.107719 361.208161 181.107719 0.000000 \n", + "10 496.276575 248.641926 262.139747 131.573512 0.000000 \n", + "11 611.303518 306.155397 147.112804 74.060040 0.000000 \n", + "12 132.047762 66.527519 686.275663 343.641470 0.000000 \n", + "13 189.069225 95.038251 629.254199 315.130738 0.000000 \n", + "14 356.067585 178.537431 462.255840 231.631558 258.090689 \n", + "15 469.151649 235.079463 349.171776 175.089526 371.174753 \n", + "16 584.178592 292.592934 234.144833 117.576055 486.201696 \n", + "17 671.210620 336.108948 147.112804 74.060040 573.233724 \n", + "18 88.039305 0.000000 760.364084 0.000000 0.000000 \n", + "19 187.107719 0.000000 661.295670 0.000000 0.000000 \n", + "20 354.106078 0.000000 494.297310 0.000000 256.129183 \n", + "21 501.174492 0.000000 347.228897 0.000000 403.197596 \n", + "22 588.206520 0.000000 260.196868 0.000000 490.229625 \n", + "23 701.290584 0.000000 147.112804 0.000000 603.313689 \n", + "24 100.075690 50.541483 762.258312 381.632794 0.000000 \n", + "25 267.074050 134.040663 595.259953 298.133615 169.097154 \n", + "26 366.142464 183.574870 496.191539 248.599408 268.165568 \n", + "27 533.140823 267.074050 329.193180 165.100228 435.163927 \n", + "28 630.193587 315.600432 232.140416 116.573846 532.216691 \n", + "29 687.215050 344.111163 175.118952 88.063114 589.238155 \n", + "30 164.070605 82.538941 698.312048 349.659662 0.000000 \n", + "31 251.102633 126.054955 611.280020 306.143648 0.000000 \n", + "32 364.186697 182.596987 498.195956 249.601616 0.000000 \n", + "33 531.185057 266.096167 331.197596 166.102436 433.208161 \n", + "34 628.237821 314.622548 234.144833 117.576055 530.260925 \n", + "35 715.269849 358.138563 147.112804 74.060040 617.292953 \n", + "\n", + " b_modloss_z2 y_modloss_z1 y_modloss_z2 \n", + "0 0.000000 610.392273 305.699775 \n", + "1 0.000000 511.323860 256.165568 \n", + "2 0.000000 412.255446 206.631361 \n", + "3 0.000000 313.187032 157.097154 \n", + "4 219.639186 0.000000 0.000000 \n", + "5 268.165568 0.000000 0.000000 \n", + "6 0.000000 0.000000 0.000000 \n", + "7 0.000000 0.000000 0.000000 \n", + "8 0.000000 0.000000 0.000000 \n", + "9 0.000000 0.000000 0.000000 \n", + "10 0.000000 0.000000 0.000000 \n", + "11 0.000000 0.000000 0.000000 \n", + "12 0.000000 588.298767 294.653022 \n", + "13 0.000000 531.277303 266.142290 \n", + "14 129.548983 0.000000 0.000000 \n", + "15 186.091015 0.000000 0.000000 \n", + "16 243.604486 0.000000 0.000000 \n", + "17 287.120500 0.000000 0.000000 \n", + "18 0.000000 662.387188 0.000000 \n", + "19 0.000000 563.318774 0.000000 \n", + "20 0.000000 0.000000 0.000000 \n", + "21 0.000000 0.000000 0.000000 \n", + "22 0.000000 0.000000 0.000000 \n", + "23 0.000000 0.000000 0.000000 \n", + "24 0.000000 664.281417 332.644347 \n", + "25 85.052215 497.283057 249.145167 \n", + "26 134.586422 398.214643 199.610960 \n", + "27 218.085602 0.000000 0.000000 \n", + "28 266.611984 0.000000 0.000000 \n", + "29 295.122716 0.000000 0.000000 \n", + "30 0.000000 600.335153 300.671214 \n", + "31 0.000000 513.303124 257.155200 \n", + "32 0.000000 400.219060 200.613168 \n", + "33 217.107719 0.000000 0.000000 \n", + "34 265.634101 0.000000 0.000000 \n", + "35 309.150115 0.000000 0.000000 " + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| hide\n", + "reader.fragment_mz_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| hide\n", + "df = pd.read_csv(StringIO(tsv_str), sep='\\t')\n", + "seq = 'YSLSPSK'\n", + "seq,start,end = psm_df.loc[psm_df.sequence==seq,['sequence','frag_start_idx','frag_end_idx']].values[0]\n", + "y_df = df[(df['StrippedPeptide']==seq)&(df['FragmentLossType']=='noloss')&(df['FragmentType']=='y')]\n", + "y_ions = np.zeros(len(seq)-1)\n", + "y_ions[len(seq)-y_df.FragmentNumber-1] = y_df.RelativeIntensity.values / 100\n", + "assert np.allclose(\n", + " reader.fragment_intensity_df.loc[start:end+1,'y_z1'].values,\n", + " y_ions\n", + ")\n", + "y_df = df[(df['StrippedPeptide']==seq)&(df['FragmentLossType']=='H3PO4')&(df['FragmentType']=='y')]\n", + "y_ions = np.zeros(len(seq)-1)\n", + "y_ions[len(seq)-y_df.FragmentNumber-1] = y_df.RelativeIntensity.values / 100\n", + "assert np.allclose(\n", + " reader.fragment_intensity_df.loc[start:end+1,'y_modloss_z1'].values,\n", + " y_ions\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
raw_namesequencechargertmobilitymodsmod_sitesnAAfrag_start_idxfrag_end_idxrt_normprecursor_mzccs
0202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph...AGSPDVLR2-0.7970190.780Phospho@S38070.344252447.707675317.236399
1202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph...ALVATPGK2-5.0327030.758Phospho@T587140.261972418.717512308.612143
2202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph...ELIQEYGAQSGGLEK239.0846101.081Phospho@S101514281.000000851.390200436.485165
3202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph...GGSPDLWK230.2007200.775Phospho@S3828350.946396470.202226314.974129
4202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph...NLTEDNSQNQDLIAK212.6500001.0921535490.541092851.915755440.924535
5202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph...SSPLSWR232.9602100.806Phospho@S1749551.000000456.702393327.713047
6202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph...TLTPPLR227.7165900.818Phospho@T3755610.898140439.230786332.788837
7202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph...TRLSPPR2-18.5187200.785Phospho@S4761670.000000453.731485319.205696
\n", + "
" + ], + "text/plain": [ + " raw_name sequence charge \\\n", + "0 202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph... AGSPDVLR 2 \n", + "1 202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph... ALVATPGK 2 \n", + "2 202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph... ELIQEYGAQSGGLEK 2 \n", + "3 202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph... GGSPDLWK 2 \n", + "4 202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph... NLTEDNSQNQDLIAK 2 \n", + "5 202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph... SSPLSWR 2 \n", + "6 202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph... TLTPPLR 2 \n", + "7 202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phosph... TRLSPPR 2 \n", + "\n", + " rt mobility mods mod_sites nAA frag_start_idx \\\n", + "0 -0.797019 0.780 Phospho@S 3 8 0 \n", + "1 -5.032703 0.758 Phospho@T 5 8 7 \n", + "2 39.084610 1.081 Phospho@S 10 15 14 \n", + "3 30.200720 0.775 Phospho@S 3 8 28 \n", + "4 12.650000 1.092 15 35 \n", + "5 32.960210 0.806 Phospho@S 1 7 49 \n", + "6 27.716590 0.818 Phospho@T 3 7 55 \n", + "7 -18.518720 0.785 Phospho@S 4 7 61 \n", + "\n", + " frag_end_idx rt_norm precursor_mz ccs \n", + "0 7 0.344252 447.707675 317.236399 \n", + "1 14 0.261972 418.717512 308.612143 \n", + "2 28 1.000000 851.390200 436.485165 \n", + "3 35 0.946396 470.202226 314.974129 \n", + "4 49 0.541092 851.915755 440.924535 \n", + "5 55 1.000000 456.702393 327.713047 \n", + "6 61 0.898140 439.230786 332.788837 \n", + "7 67 0.000000 453.731485 319.205696 " + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| hide\n", + "tsv_str = \"\"\"ReferenceRun\tPrecursorCharge\tWorkflow\tIntModifiedPeptide\tCV\tAllowForNormalization\tModifiedPeptide\tStrippedPeptide\tiRT\tIonMobility\tiRTSourceSpecific\tBGSInferenceId\tIsProteotypic\tIntLabeledPeptide\tLabeledPeptide\tPrecursorMz\tReferenceRunQvalue\tReferenceRunMS1Response\tFragmentLossType\tFragmentNumber\tFragmentType\tFragmentCharge\tFragmentMz\tRelativeIntensity\tExcludeFromAssay\tDatabase\tProteinGroups\tUniProtIds\tProtein Name\tProteinDescription\tOrganisms\tOrganismId\tGenes\tProtein Existence\tSequence Version\tFASTAName\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_ALVAT[+80]PGK_\t\tTrue\t_ALVAT[Phospho (STY)]PGK_\tALVATPGK\t-5.032703\t0.758\t-5.032703\tP19338\tFalse\t_ALVAT[+80]PGK_\t_ALVAT[Phospho (STY)]PGK_\t418.717511324722\t0\t10352\tnoloss\t3\ty\t1\t301.187031733932\t53.1991\tFalse\tsp\tP19338\tP19338\tNUCL_HUMAN\tNucleolin\tHomo sapiens\t\tNCL\t1\t3\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_ALVAT[+80]PGK_\t\tTrue\t_ALVAT[Phospho (STY)]PGK_\tALVATPGK\t-5.032703\t0.758\t-5.032703\tP19338\tFalse\t_ALVAT[+80]PGK_\t_ALVAT[Phospho (STY)]PGK_\t418.717511324722\t0\t10352\tH3PO4\t4\ty\t1\t384.224142529733\t26.31595\tFalse\tsp\tP19338\tP19338\tNUCL_HUMAN\tNucleolin\tHomo sapiens\t\tNCL\t1\t3\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_ALVAT[+80]PGK_\t\tTrue\t_ALVAT[Phospho (STY)]PGK_\tALVATPGK\t-5.032703\t0.758\t-5.032703\tP19338\tFalse\t_ALVAT[+80]PGK_\t_ALVAT[Phospho (STY)]PGK_\t418.717511324722\t0\t10352\tnoloss\t5\ty\t1\t553.238154507802\t54.60104\tFalse\tsp\tP19338\tP19338\tNUCL_HUMAN\tNucleolin\tHomo sapiens\t\tNCL\t1\t3\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_ALVAT[+80]PGK_\t\tTrue\t_ALVAT[Phospho (STY)]PGK_\tALVATPGK\t-5.032703\t0.758\t-5.032703\tP19338\tFalse\t_ALVAT[+80]PGK_\t_ALVAT[Phospho (STY)]PGK_\t418.717511324722\t0\t10352\tH3PO4\t5\ty\t1\t455.261256314443\t46.09977\tFalse\tsp\tP19338\tP19338\tNUCL_HUMAN\tNucleolin\tHomo sapiens\t\tNCL\t1\t3\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_ALVAT[+80]PGK_\t\tTrue\t_ALVAT[Phospho (STY)]PGK_\tALVATPGK\t-5.032703\t0.758\t-5.032703\tP19338\tFalse\t_ALVAT[+80]PGK_\t_ALVAT[Phospho (STY)]PGK_\t418.717511324722\t0\t10352\tnoloss\t6\ty\t1\t652.306568420792\t100\tFalse\tsp\tP19338\tP19338\tNUCL_HUMAN\tNucleolin\tHomo sapiens\t\tNCL\t1\t3\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_ALVAT[+80]PGK_\t\tTrue\t_ALVAT[Phospho (STY)]PGK_\tALVATPGK\t-5.032703\t0.758\t-5.032703\tP19338\tFalse\t_ALVAT[+80]PGK_\t_ALVAT[Phospho (STY)]PGK_\t418.717511324722\t0\t10352\tH3PO4\t6\ty\t1\t554.329670227433\t50.4698\tFalse\tsp\tP19338\tP19338\tNUCL_HUMAN\tNucleolin\tHomo sapiens\t\tNCL\t1\t3\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TLT[+80]PPLR_\t\tTrue\t_TLT[Phospho (STY)]PPLR_\tTLTPPLR\t27.71659\t0.818\t27.71659\tQ5T200\tFalse\t_TLT[+80]PPLR_\t_TLT[Phospho (STY)]PPLR_\t439.230785875227\t0.000138389150379226\t23117\tnoloss\t3\tb\t1\t396.153027901512\t6.3264\tFalse\tsp\tQ5T200\tQ5T200\tZC3HD_HUMAN\tZinc finger CCCH domain-containing protein 13\tHomo sapiens\t\tZC3H13\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TLT[+80]PPLR_\t\tTrue\t_TLT[Phospho (STY)]PPLR_\tTLTPPLR\t27.71659\t0.818\t27.71659\tQ5T200\tFalse\t_TLT[+80]PPLR_\t_TLT[Phospho (STY)]PPLR_\t439.230785875227\t0.000138389150379226\t23117\tnoloss\t3\ty\t1\t385.255780000092\t29.70625\tFalse\tsp\tQ5T200\tQ5T200\tZC3HD_HUMAN\tZinc finger CCCH domain-containing protein 13\tHomo sapiens\t\tZC3H13\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TLT[+80]PPLR_\t\tTrue\t_TLT[Phospho (STY)]PPLR_\tTLTPPLR\t27.71659\t0.818\t27.71659\tQ5T200\tFalse\t_TLT[+80]PPLR_\t_TLT[Phospho (STY)]PPLR_\t439.230785875227\t0.000138389150379226\t23117\tnoloss\t4\ty\t1\t482.308543848942\t100\tFalse\tsp\tQ5T200\tQ5T200\tZC3HD_HUMAN\tZinc finger CCCH domain-containing protein 13\tHomo sapiens\t\tZC3H13\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TLT[+80]PPLR_\t\tTrue\t_TLT[Phospho (STY)]PPLR_\tTLTPPLR\t27.71659\t0.818\t27.71659\tQ5T200\tFalse\t_TLT[+80]PPLR_\t_TLT[Phospho (STY)]PPLR_\t439.230785875227\t0.000138389150379226\t23117\tnoloss\t5\ty\t1\t663.322552838102\t15.22549\tFalse\tsp\tQ5T200\tQ5T200\tZC3HD_HUMAN\tZinc finger CCCH domain-containing protein 13\tHomo sapiens\t\tZC3H13\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TLT[+80]PPLR_\t\tTrue\t_TLT[Phospho (STY)]PPLR_\tTLTPPLR\t27.71659\t0.818\t27.71659\tQ5T200\tFalse\t_TLT[+80]PPLR_\t_TLT[Phospho (STY)]PPLR_\t439.230785875227\t0.000138389150379226\t23117\tH3PO4\t5\ty\t1\t565.345654644743\t78.98973\tFalse\tsp\tQ5T200\tQ5T200\tZC3HD_HUMAN\tZinc finger CCCH domain-containing protein 13\tHomo sapiens\t\tZC3H13\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TLT[+80]PPLR_\t\tTrue\t_TLT[Phospho (STY)]PPLR_\tTLTPPLR\t27.71659\t0.818\t27.71659\tQ5T200\tFalse\t_TLT[+80]PPLR_\t_TLT[Phospho (STY)]PPLR_\t439.230785875227\t0.000138389150379226\t23117\tH3PO4\t6\ty\t1\t678.429718621873\t7.326889\tFalse\tsp\tQ5T200\tQ5T200\tZC3HD_HUMAN\tZinc finger CCCH domain-containing protein 13\tHomo sapiens\t\tZC3H13\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TLT[+80]PPLR_\t\tTrue\t_TLT[Phospho (STY)]PPLR_\tTLTPPLR\t27.71659\t0.818\t27.71659\tQ5T200\tFalse\t_TLT[+80]PPLR_\t_TLT[Phospho (STY)]PPLR_\t439.230785875227\t0.000138389150379226\t23117\tNH3\t3\ty\t1\t368.229231614472\t5.478241\tFalse\tsp\tQ5T200\tQ5T200\tZC3HD_HUMAN\tZinc finger CCCH domain-containing protein 13\tHomo sapiens\t\tZC3H13\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TLT[+80]PPLR_\t\tTrue\t_TLT[Phospho (STY)]PPLR_\tTLTPPLR\t27.71659\t0.818\t27.71659\tQ5T200\tFalse\t_TLT[+80]PPLR_\t_TLT[Phospho (STY)]PPLR_\t439.230785875227\t0.000138389150379226\t23117\tnoloss\t6\ty\t2\t388.706946641022\t5.111521\tFalse\tsp\tQ5T200\tQ5T200\tZC3HD_HUMAN\tZinc finger CCCH domain-containing protein 13\tHomo sapiens\t\tZC3H13\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_AGS[+80]PDVLR_\t\tTrue\t_AGS[Phospho (STY)]PDVLR_\tAGSPDVLR\t-0.7970191\t0.78\t-0.7970191\tQ8NDX6\tTrue\t_AGS[+80]PDVLR_\t_AGS[Phospho (STY)]PDVLR_\t447.707674917012\t0\t20561\tnoloss\t3\ty\t1\t387.271430064232\t52.42308\tFalse\tsp\tQ8NDX6\tQ8NDX6\tZN740_HUMAN\tZinc finger protein 740\tHomo sapiens\t\tZNF740\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_AGS[+80]PDVLR_\t\tTrue\t_AGS[Phospho (STY)]PDVLR_\tAGSPDVLR\t-0.7970191\t0.78\t-0.7970191\tQ8NDX6\tTrue\t_AGS[+80]PDVLR_\t_AGS[Phospho (STY)]PDVLR_\t447.707674917012\t0\t20561\tnoloss\t4\ty\t1\t502.298373088062\t9.560875\tFalse\tsp\tQ8NDX6\tQ8NDX6\tZN740_HUMAN\tZinc finger protein 740\tHomo sapiens\t\tZNF740\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_AGS[+80]PDVLR_\t\tTrue\t_AGS[Phospho (STY)]PDVLR_\tAGSPDVLR\t-0.7970191\t0.78\t-0.7970191\tQ8NDX6\tTrue\t_AGS[+80]PDVLR_\t_AGS[Phospho (STY)]PDVLR_\t447.707674917012\t0\t20561\tnoloss\t5\ty\t1\t599.351136936912\t100\tFalse\tsp\tQ8NDX6\tQ8NDX6\tZN740_HUMAN\tZinc finger protein 740\tHomo sapiens\t\tZNF740\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_AGS[+80]PDVLR_\t\tTrue\t_AGS[Phospho (STY)]PDVLR_\tAGSPDVLR\t-0.7970191\t0.78\t-0.7970191\tQ8NDX6\tTrue\t_AGS[+80]PDVLR_\t_AGS[Phospho (STY)]PDVLR_\t447.707674917012\t0\t20561\tH3PO4\t6\ty\t2\t334.689937067692\t68.40089\tFalse\tsp\tQ8NDX6\tQ8NDX6\tZN740_HUMAN\tZinc finger protein 740\tHomo sapiens\t\tZNF740\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_AGS[+80]PDVLR_\t\tTrue\t_AGS[Phospho (STY)]PDVLR_\tAGSPDVLR\t-0.7970191\t0.78\t-0.7970191\tQ8NDX6\tTrue\t_AGS[+80]PDVLR_\t_AGS[Phospho (STY)]PDVLR_\t447.707674917012\t0\t20561\tH3PO4\t7\ty\t2\t363.200668927977\t27.03024\tFalse\tsp\tQ8NDX6\tQ8NDX6\tZN740_HUMAN\tZinc finger protein 740\tHomo sapiens\t\tZNF740\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TRLS[+80]PPR_\t\tTrue\t_TRLS[Phospho (STY)]PPR_\tTRLSPPR\t-18.51872\t0.785\t-18.51872\tQ96PK6\tTrue\t_TRLS[+80]PPR_\t_TRLS[Phospho (STY)]PPR_\t453.731484366392\t0.000731277163140476\t55003\tnoloss\t3\ty\t1\t369.224479871812\t97.64322\tFalse\tsp\tQ96PK6\tQ96PK6\tRBM14_HUMAN\tRNA-binding protein 14\tHomo sapiens\t\tRBM14\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TRLS[+80]PPR_\t\tTrue\t_TRLS[Phospho (STY)]PPR_\tTRLSPPR\t-18.51872\t0.785\t-18.51872\tQ96PK6\tTrue\t_TRLS[+80]PPR_\t_TRLS[Phospho (STY)]PPR_\t453.731484366392\t0.000731277163140476\t55003\tnoloss\t4\tb\t1\t538.238488860972\t17.74173\tFalse\tsp\tQ96PK6\tQ96PK6\tRBM14_HUMAN\tRNA-binding protein 14\tHomo sapiens\t\tRBM14\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TRLS[+80]PPR_\t\tTrue\t_TRLS[Phospho (STY)]PPR_\tTRLSPPR\t-18.51872\t0.785\t-18.51872\tQ96PK6\tTrue\t_TRLS[+80]PPR_\t_TRLS[Phospho (STY)]PPR_\t453.731484366392\t0.000731277163140476\t55003\tH3PO4\t4\tb\t1\t440.261590667613\t100\tFalse\tsp\tQ96PK6\tQ96PK6\tRBM14_HUMAN\tRNA-binding protein 14\tHomo sapiens\t\tRBM14\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TRLS[+80]PPR_\t\tTrue\t_TRLS[Phospho (STY)]PPR_\tTRLSPPR\t-18.51872\t0.785\t-18.51872\tQ96PK6\tTrue\t_TRLS[+80]PPR_\t_TRLS[Phospho (STY)]PPR_\t453.731484366392\t0.000731277163140476\t55003\tH3PO4\t4\ty\t1\t438.245940603473\t7.038487\tFalse\tsp\tQ96PK6\tQ96PK6\tRBM14_HUMAN\tRNA-binding protein 14\tHomo sapiens\t\tRBM14\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TRLS[+80]PPR_\t\tTrue\t_TRLS[Phospho (STY)]PPR_\tTRLSPPR\t-18.51872\t0.785\t-18.51872\tQ96PK6\tTrue\t_TRLS[+80]PPR_\t_TRLS[Phospho (STY)]PPR_\t453.731484366392\t0.000731277163140476\t55003\tnoloss\t5\ty\t1\t649.306902773962\t6.46876\tFalse\tsp\tQ96PK6\tQ96PK6\tRBM14_HUMAN\tRNA-binding protein 14\tHomo sapiens\t\tRBM14\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TRLS[+80]PPR_\t\tTrue\t_TRLS[Phospho (STY)]PPR_\tTRLSPPR\t-18.51872\t0.785\t-18.51872\tQ96PK6\tTrue\t_TRLS[+80]PPR_\t_TRLS[Phospho (STY)]PPR_\t453.731484366392\t0.000731277163140476\t55003\tH3PO4\t5\tb\t1\t537.314354516463\t10.4885\tFalse\tsp\tQ96PK6\tQ96PK6\tRBM14_HUMAN\tRNA-binding protein 14\tHomo sapiens\t\tRBM14\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TRLS[+80]PPR_\t\tTrue\t_TRLS[Phospho (STY)]PPR_\tTRLSPPR\t-18.51872\t0.785\t-18.51872\tQ96PK6\tTrue\t_TRLS[+80]PPR_\t_TRLS[Phospho (STY)]PPR_\t453.731484366392\t0.000731277163140476\t55003\tH3PO4\t5\ty\t1\t551.330004580603\t20.62304\tFalse\tsp\tQ96PK6\tQ96PK6\tRBM14_HUMAN\tRNA-binding protein 14\tHomo sapiens\t\tRBM14\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_TRLS[+80]PPR_\t\tTrue\t_TRLS[Phospho (STY)]PPR_\tTRLSPPR\t-18.51872\t0.785\t-18.51872\tQ96PK6\tTrue\t_TRLS[+80]PPR_\t_TRLS[Phospho (STY)]PPR_\t453.731484366392\t0.000731277163140476\t55003\t1(+H3+N)1(+H3+O4+P)\t4\tb\t1\t423.235042281993\t8.850685\tFalse\tsp\tQ96PK6\tQ96PK6\tRBM14_HUMAN\tRNA-binding protein 14\tHomo sapiens\t\tRBM14\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_S[+80]SPLSWR_\t\tTrue\t_S[Phospho (STY)]SPLSWR_\tSSPLSWR\t32.96021\t0.806\t32.96021\tQ8NEY1;Q8NEY1-3\tFalse\t_S[+80]SPLSWR_\t_S[Phospho (STY)]SPLSWR_\t456.702392575162\t0.00218558823689818\t6996\tnoloss\t3\ty\t1\t448.230293528242\t74.2921\tFalse\tsp\tQ8NEY1;Q8NEY1-3\tQ8NEY1;Q8NEY1-3\tNAV1_HUMAN\tNeuron navigator 1;Isoform of Q8NEY1, Isoform 3 of Neuron navigator 1\tHomo sapiens\t\tNAV1\t1;\t2;\tMCT_human_UP000005640_9606;MCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_S[+80]SPLSWR_\t\tTrue\t_S[Phospho (STY)]SPLSWR_\tSSPLSWR\t32.96021\t0.806\t32.96021\tQ8NEY1;Q8NEY1-3\tFalse\t_S[+80]SPLSWR_\t_S[Phospho (STY)]SPLSWR_\t456.702392575162\t0.00218558823689818\t6996\tnoloss\t4\ty\t1\t561.314357505372\t100\tFalse\tsp\tQ8NEY1;Q8NEY1-3\tQ8NEY1;Q8NEY1-3\tNAV1_HUMAN\tNeuron navigator 1;Isoform of Q8NEY1, Isoform 3 of Neuron navigator 1\tHomo sapiens\t\tNAV1\t1;\t2;\tMCT_human_UP000005640_9606;MCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_S[+80]SPLSWR_\t\tTrue\t_S[Phospho (STY)]SPLSWR_\tSSPLSWR\t32.96021\t0.806\t32.96021\tQ8NEY1;Q8NEY1-3\tFalse\t_S[+80]SPLSWR_\t_S[Phospho (STY)]SPLSWR_\t456.702392575162\t0.00218558823689818\t6996\tnoloss\t5\ty\t1\t658.367121354222\t53.05514\tFalse\tsp\tQ8NEY1;Q8NEY1-3\tQ8NEY1;Q8NEY1-3\tNAV1_HUMAN\tNeuron navigator 1;Isoform of Q8NEY1, Isoform 3 of Neuron navigator 1\tHomo sapiens\t\tNAV1\t1;\t2;\tMCT_human_UP000005640_9606;MCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_S[+80]SPLSWR_\t\tTrue\t_S[Phospho (STY)]SPLSWR_\tSSPLSWR\t32.96021\t0.806\t32.96021\tQ8NEY1;Q8NEY1-3\tFalse\t_S[+80]SPLSWR_\t_S[Phospho (STY)]SPLSWR_\t456.702392575162\t0.00218558823689818\t6996\tH2O\t4\ty\t1\t543.303792701295\t8.122206\tFalse\tsp\tQ8NEY1;Q8NEY1-3\tQ8NEY1;Q8NEY1-3\tNAV1_HUMAN\tNeuron navigator 1;Isoform of Q8NEY1, Isoform 3 of Neuron navigator 1\tHomo sapiens\t\tNAV1\t1;\t2;\tMCT_human_UP000005640_9606;MCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_S[+80]SPLSWR_\t\tTrue\t_S[Phospho (STY)]SPLSWR_\tSSPLSWR\t32.96021\t0.806\t32.96021\tQ8NEY1;Q8NEY1-3\tFalse\t_S[+80]SPLSWR_\t_S[Phospho (STY)]SPLSWR_\t456.702392575162\t0.00218558823689818\t6996\tNH3\t4\ty\t1\t544.287809119752\t11.54993\tFalse\tsp\tQ8NEY1;Q8NEY1-3\tQ8NEY1;Q8NEY1-3\tNAV1_HUMAN\tNeuron navigator 1;Isoform of Q8NEY1, Isoform 3 of Neuron navigator 1\tHomo sapiens\t\tNAV1\t1;\t2;\tMCT_human_UP000005640_9606;MCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_GGS[+80]PDLWK_\t\tTrue\t_GGS[Phospho (STY)]PDLWK_\tGGSPDLWK\t30.20072\t0.775\t30.20072\tQ96JM3\tTrue\t_GGS[+80]PDLWK_\t_GGS[Phospho (STY)]PDLWK_\t470.202225398577\t0\t14524\tnoloss\t3\ty\t1\t446.276181091502\t14.71406\tFalse\tsp\tQ96JM3\tQ96JM3\tCHAP1_HUMAN\tChromosome alignment-maintaining phosphoprotein 1\tHomo sapiens\t\tCHAMP1\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_GGS[+80]PDLWK_\t\tTrue\t_GGS[Phospho (STY)]PDLWK_\tGGSPDLWK\t30.20072\t0.775\t30.20072\tQ96JM3\tTrue\t_GGS[+80]PDLWK_\t_GGS[Phospho (STY)]PDLWK_\t470.202225398577\t0\t14524\tnoloss\t4\ty\t1\t561.303124115332\t33.08263\tFalse\tsp\tQ96JM3\tQ96JM3\tCHAP1_HUMAN\tChromosome alignment-maintaining phosphoprotein 1\tHomo sapiens\t\tCHAMP1\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_GGS[+80]PDLWK_\t\tTrue\t_GGS[Phospho (STY)]PDLWK_\tGGSPDLWK\t30.20072\t0.775\t30.20072\tQ96JM3\tTrue\t_GGS[+80]PDLWK_\t_GGS[Phospho (STY)]PDLWK_\t470.202225398577\t0\t14524\tnoloss\t5\tb\t1\t494.128269705652\t6.559356\tFalse\tsp\tQ96JM3\tQ96JM3\tCHAP1_HUMAN\tChromosome alignment-maintaining phosphoprotein 1\tHomo sapiens\t\tCHAMP1\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_GGS[+80]PDLWK_\t\tTrue\t_GGS[Phospho (STY)]PDLWK_\tGGSPDLWK\t30.20072\t0.775\t30.20072\tQ96JM3\tTrue\t_GGS[+80]PDLWK_\t_GGS[Phospho (STY)]PDLWK_\t470.202225398577\t0\t14524\tnoloss\t5\ty\t1\t658.355887964182\t100\tFalse\tsp\tQ96JM3\tQ96JM3\tCHAP1_HUMAN\tChromosome alignment-maintaining phosphoprotein 1\tHomo sapiens\t\tCHAMP1\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_GGS[+80]PDLWK_\t\tTrue\t_GGS[Phospho (STY)]PDLWK_\tGGSPDLWK\t30.20072\t0.775\t30.20072\tQ96JM3\tTrue\t_GGS[+80]PDLWK_\t_GGS[Phospho (STY)]PDLWK_\t470.202225398577\t0\t14524\tH3PO4\t5\tb\t1\t396.151371512293\t6.920845\tFalse\tsp\tQ96JM3\tQ96JM3\tCHAP1_HUMAN\tChromosome alignment-maintaining phosphoprotein 1\tHomo sapiens\t\tCHAMP1\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_GGS[+80]PDLWK_\t\tTrue\t_GGS[Phospho (STY)]PDLWK_\tGGSPDLWK\t30.20072\t0.775\t30.20072\tQ96JM3\tTrue\t_GGS[+80]PDLWK_\t_GGS[Phospho (STY)]PDLWK_\t470.202225398577\t0\t14524\tnoloss\t6\tb\t1\t607.212333682782\t6.388004\tFalse\tsp\tQ96JM3\tQ96JM3\tCHAP1_HUMAN\tChromosome alignment-maintaining phosphoprotein 1\tHomo sapiens\t\tCHAMP1\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_GGS[+80]PDLWK_\t\tTrue\t_GGS[Phospho (STY)]PDLWK_\tGGSPDLWK\t30.20072\t0.775\t30.20072\tQ96JM3\tTrue\t_GGS[+80]PDLWK_\t_GGS[Phospho (STY)]PDLWK_\t470.202225398577\t0\t14524\tH3PO4\t6\tb\t1\t509.235435489423\t19.9082\tFalse\tsp\tQ96JM3\tQ96JM3\tCHAP1_HUMAN\tChromosome alignment-maintaining phosphoprotein 1\tHomo sapiens\t\tCHAMP1\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_GGS[+80]PDLWK_\t\tTrue\t_GGS[Phospho (STY)]PDLWK_\tGGSPDLWK\t30.20072\t0.775\t30.20072\tQ96JM3\tTrue\t_GGS[+80]PDLWK_\t_GGS[Phospho (STY)]PDLWK_\t470.202225398577\t0\t14524\tH3PO4\t6\ty\t2\t364.192312581327\t80.62402\tFalse\tsp\tQ96JM3\tQ96JM3\tCHAP1_HUMAN\tChromosome alignment-maintaining phosphoprotein 1\tHomo sapiens\t\tCHAMP1\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_GGS[+80]PDLWK_\t\tTrue\t_GGS[Phospho (STY)]PDLWK_\tGGSPDLWK\t30.20072\t0.775\t30.20072\tQ96JM3\tTrue\t_GGS[+80]PDLWK_\t_GGS[Phospho (STY)]PDLWK_\t470.202225398577\t0\t14524\tH3PO4\t7\tb\t1\t695.314748439283\t16.95742\tFalse\tsp\tQ96JM3\tQ96JM3\tCHAP1_HUMAN\tChromosome alignment-maintaining phosphoprotein 1\tHomo sapiens\t\tCHAMP1\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_GGS[+80]PDLWK_\t\tTrue\t_GGS[Phospho (STY)]PDLWK_\tGGSPDLWK\t30.20072\t0.775\t30.20072\tQ96JM3\tTrue\t_GGS[+80]PDLWK_\t_GGS[Phospho (STY)]PDLWK_\t470.202225398577\t0\t14524\tH3PO4\t7\ty\t2\t392.703044441612\t23.94268\tFalse\tsp\tQ96JM3\tQ96JM3\tCHAP1_HUMAN\tChromosome alignment-maintaining phosphoprotein 1\tHomo sapiens\t\tCHAMP1\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_100ug_test_S4-A1_1_25843\t2\t\t_GGS[+80]PDLWK_\t\tTrue\t_GGS[Phospho (STY)]PDLWK_\tGGSPDLWK\t30.20072\t0.775\t30.20072\tQ96JM3\tTrue\t_GGS[+80]PDLWK_\t_GGS[Phospho (STY)]PDLWK_\t470.202225398577\t0\t14524\t1(+H2+O)1(+H3+O4+P)\t6\tb\t1\t491.224876407391\t7.7026\tFalse\tsp\tQ96JM3\tQ96JM3\tCHAP1_HUMAN\tChromosome alignment-maintaining phosphoprotein 1\tHomo sapiens\t\tCHAMP1\t1\t2\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tnoloss\t8\tb\t1\t904.441074140122\t13.24587\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tnoloss\t8\ty\t1\t869.376438885762\t9.73339\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tH3PO4\t8\ty\t1\t771.399540692403\t15.5311\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tnoloss\t9\ty\t1\t926.397902606332\t62.03978\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tH3PO4\t9\ty\t1\t828.421004412973\t100\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tnoloss\t10\ty\t1\t1089.46123113888\t27.16885\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tH3PO4\t10\ty\t1\t991.484332945523\t37.66399\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tnoloss\t11\ty\t1\t1218.50382422685\t11.55311\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tH3PO4\t11\ty\t1\t1120.52692603349\t14.68472\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tnoloss\t12\ty\t2\t673.784839099472\t19.2975\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tH3PO4\t13\ty\t2\t681.338421991357\t5.416843\tTrue\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tH2O\t3\tb\t1\t338.207432704965\t52.51799\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tH2O\t4\tb\t1\t466.266010210245\t11.00296\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tH2O\t5\tb\t1\t595.308603298215\t40.71096\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\t1(+H2+O)1(+H3+O4+P)\t7\ty\t2\t341.679569285214\t6.94033\tTrue\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\t1(+H3+N)1(+H3+O4+P)\t7\ty\t1\t683.335878522073\t9.944985\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\t1(+H3+N)1(+H3+O4+P)\t8\ty\t2\t377.690134386797\t6.051629\tTrue\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\t1(+H2+O)1(+H3+O4+P)\t11\ty\t1\t1102.51636122942\t10.49513\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\t1(+H3+N)1(+H3+O4+P)\t11\ty\t1\t1103.50037764787\t5.966991\tTrue\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tH2O\t12\ty\t2\t664.779556697433\t18.91663\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\tNH3\t12\ty\t2\t665.271564906662\t5.459162\tTrue\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_ELIQEYGAQS[+80]GGLEK_\t\tTrue\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\tELIQEYGAQSGGLEK\t39.08461\t1.081\t39.08461\tA0A075B730\tFalse\t_ELIQEYGAQS[+80]GGLEK_\t_ELIQEYGAQS[Phospho (STY)]GGLEK_\t851.390199620587\t0\t11732\t1(+H2+O)1(+H3+O4+P)\t12\ty\t2\t615.791107600754\t16.20821\tFalse\ttr\tA0A075B730\tA0A075B730\tA0A075B730_HUMAN\tIsoform of P58107, Epiplakin\tHomo sapiens\t\tEPPK1\t1\t2\tMCT_human2_UP000005640_9606_additional\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tnoloss\t3\tb\t1\t329.181946353492\t19.79472\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tnoloss\t3\ty\t1\t331.233981926352\t34.45748\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tnoloss\t4\ty\t1\t444.318045903482\t41.93548\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tnoloss\t5\tb\t1\t573.251482465292\t56.89149\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tnoloss\t5\ty\t1\t559.344988927312\t31.81818\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tnoloss\t6\ty\t1\t687.403566432592\t6.744868\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tnoloss\t7\ty\t1\t801.446493873732\t100\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tnoloss\t8\ty\t1\t929.505071379012\t6.158358\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tnoloss\t9\ty\t1\t1016.53709978328\t16.27566\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tnoloss\t10\ty\t1\t1130.58002722442\t14.07625\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tnoloss\t12\ty\t1\t1374.64956333622\t23.60704\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tH2O\t3\tb\t1\t311.171381549415\t27.56598\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tNH3\t8\ty\t1\t912.478522993392\t5.718475\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tNH3\t9\ty\t1\t999.510551397662\t6.744868\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "202106018_TIMS03_EVO03_PaSk_SA_HeLa_EGF_Phospho_library15_S4-B3_1_25857\t2\t\t_NLTEDNSQNQDLIAK_\t\tTrue\t_NLTEDNSQNQDLIAK_\tNLTEDNSQNQDLIAK\t12.65\t1.092\t12.65\tQ9UBB4\tFalse\t_NLTEDNSQNQDLIAK_\t_NLTEDNSQNQDLIAK_\t851.915754844857\t0.000129324282170273\t6592\tNH3\t12\ty\t1\t1357.6230149506\t10.41056\tFalse\tsp\tQ9UBB4\tQ9UBB4\tATX10_HUMAN\tAtaxin-10\tHomo sapiens\t\tATXN10\t1\t1\tMCT_human_UP000005640_9606\n", + "\"\"\"\n", + "\n", + "reader = SWATHLibraryReader()\n", + "psm_df = reader.import_file(StringIO(tsv_str))\n", + "for col in ['sequence','charge','rt','rt_norm','mods','mod_sites','nAA','frag_start_idx','frag_end_idx']:\n", + " assert col in psm_df.columns\n", + "assert 'raw_name' in psm_df.columns\n", + "psm_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
b_z1b_z2y_z1y_z2b_modloss_z1b_modloss_z2y_modloss_z1y_modloss_z2
00.0000000.00.0000000.00.0000000.00.0000000.270302
10.0000000.00.0000000.00.0000000.00.0000000.684009
20.0000000.01.0000000.00.0000000.00.0000000.000000
30.0000000.00.0956090.00.0000000.00.0000000.000000
40.0000000.00.5242310.00.0000000.00.0000000.000000
...........................
620.0000000.00.0646880.00.0000000.00.2062300.000000
630.0000000.00.0000000.00.0000000.00.0703850.000000
640.1774170.00.9764320.01.0000000.00.0000000.000000
650.0000000.00.0000000.00.1048850.00.0000000.000000
660.0000000.00.0000000.00.0000000.00.0000000.000000
\n", + "

67 rows × 8 columns

\n", + "
" + ], + "text/plain": [ + " b_z1 b_z2 y_z1 y_z2 b_modloss_z1 b_modloss_z2 y_modloss_z1 \\\n", + "0 0.000000 0.0 0.000000 0.0 0.000000 0.0 0.000000 \n", + "1 0.000000 0.0 0.000000 0.0 0.000000 0.0 0.000000 \n", + "2 0.000000 0.0 1.000000 0.0 0.000000 0.0 0.000000 \n", + "3 0.000000 0.0 0.095609 0.0 0.000000 0.0 0.000000 \n", + "4 0.000000 0.0 0.524231 0.0 0.000000 0.0 0.000000 \n", + ".. ... ... ... ... ... ... ... \n", + "62 0.000000 0.0 0.064688 0.0 0.000000 0.0 0.206230 \n", + "63 0.000000 0.0 0.000000 0.0 0.000000 0.0 0.070385 \n", + "64 0.177417 0.0 0.976432 0.0 1.000000 0.0 0.000000 \n", + "65 0.000000 0.0 0.000000 0.0 0.104885 0.0 0.000000 \n", + "66 0.000000 0.0 0.000000 0.0 0.000000 0.0 0.000000 \n", + "\n", + " y_modloss_z2 \n", + "0 0.270302 \n", + "1 0.684009 \n", + "2 0.000000 \n", + "3 0.000000 \n", + "4 0.000000 \n", + ".. ... \n", + "62 0.000000 \n", + "63 0.000000 \n", + "64 0.000000 \n", + "65 0.000000 \n", + "66 0.000000 \n", + "\n", + "[67 rows x 8 columns]" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reader.fragment_intensity_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
b_z1b_z2y_z1y_z2b_modloss_z1b_modloss_z2y_modloss_z1y_modloss_z2
072.04439036.525833823.370960412.1891180.0000000.000000725.394064363.200670
1129.06585465.036565766.349496383.6783860.0000000.000000668.372601334.689939
2296.064213148.535745599.351137300.179207198.08731899.5472970.0000000.000000
3393.116977197.062127502.298373251.652825295.140082148.0736790.0000000.000000
4508.143920254.575598387.271430194.139353410.167025205.5871510.0000000.000000
...........................
62258.156066129.581671649.306903325.1570900.0000000.000000551.330008276.168642
63371.240130186.123703536.222839268.6150580.0000000.000000438.245944219.626610
64538.238489269.622883369.224480185.115878440.261594220.6344350.0000000.000000
65635.291253318.149265272.171716136.589496537.314358269.1608170.0000000.000000
66732.344017366.675647175.11895288.063114634.367121317.6871990.0000000.000000
\n", + "

67 rows × 8 columns

\n", + "
" + ], + "text/plain": [ + " b_z1 b_z2 y_z1 y_z2 b_modloss_z1 \\\n", + "0 72.044390 36.525833 823.370960 412.189118 0.000000 \n", + "1 129.065854 65.036565 766.349496 383.678386 0.000000 \n", + "2 296.064213 148.535745 599.351137 300.179207 198.087318 \n", + "3 393.116977 197.062127 502.298373 251.652825 295.140082 \n", + "4 508.143920 254.575598 387.271430 194.139353 410.167025 \n", + ".. ... ... ... ... ... \n", + "62 258.156066 129.581671 649.306903 325.157090 0.000000 \n", + "63 371.240130 186.123703 536.222839 268.615058 0.000000 \n", + "64 538.238489 269.622883 369.224480 185.115878 440.261594 \n", + "65 635.291253 318.149265 272.171716 136.589496 537.314358 \n", + "66 732.344017 366.675647 175.118952 88.063114 634.367121 \n", + "\n", + " b_modloss_z2 y_modloss_z1 y_modloss_z2 \n", + "0 0.000000 725.394064 363.200670 \n", + "1 0.000000 668.372601 334.689939 \n", + "2 99.547297 0.000000 0.000000 \n", + "3 148.073679 0.000000 0.000000 \n", + "4 205.587151 0.000000 0.000000 \n", + ".. ... ... ... \n", + "62 0.000000 551.330008 276.168642 \n", + "63 0.000000 438.245944 219.626610 \n", + "64 220.634435 0.000000 0.000000 \n", + "65 269.160817 0.000000 0.000000 \n", + "66 317.687199 0.000000 0.000000 \n", + "\n", + "[67 rows x 8 columns]" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| hide\n", + "reader.fragment_mz_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| hide\n", + "# noloss = '' library\n", + "tsv_str = \"\"\"PrecursorMz\tProductMz\tAnnotation\tProteinId\tGeneName\tPeptideSequence\tModifiedPeptideSequence\tPrecursorCharge\tLibraryIntensity\tNormalizedRetentionTime\tPrecursorIonMobility\tFragmentType\tFragmentCharge\tFragmentSeriesNumber\tFragmentLossType\tAverageExperimentalRetentionTime\n", + "300.150371\t144.605147\ty2^2\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t293.82037\t2.957367634819564\t\ty\t2\t2\t\t256.87189917542054\n", + "300.150371\t175.118953\ty1^1\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t6975.805942\t2.957367634819564\t\ty\t1\t1\t\t256.87189917542054\n", + "300.150371\t188.111798\ty4^3\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t699.9488765\t2.957367634819564\t\ty\t3\t4\t\t256.87189917542054\n", + "300.150371\t213.13460299999997\ty3^2\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t3899.8066759999997\t2.957367634819564\t\ty\t2\t3\t\t256.87189917542054\n", + "300.150371\t231.125996\ty5^3\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t557.755905\t2.957367634819564\t\ty\t3\t5\t\t256.87189917542054\n", + "300.150371\t277.13322200000005\tb2^1\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t5213.9476395\t2.957367634819564\t\tb\t1\t2\t\t256.87189917542054\n", + "300.150371\t281.664059\ty4^2\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t8268.719133999999\t2.957367634819564\t\ty\t2\t4\t\t256.87189917542054\n", + "300.150371\t288.203017\ty2^1\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t7783.7707125\t2.957367634819564\t\ty\t1\t2\t\t256.87189917542054\n", + "300.150371\t346.185356\ty5^2\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t892.8047019999998\t2.957367634819564\t\ty\t2\t5\t\t256.87189917542054\n", + "300.150371\t378.180901\tb3^1\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t2861.0433905\t2.957367634819564\t\tb\t1\t3\t\t256.87189917542054\n", + "300.150371\t410.70665299999996\ty6^2\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t1104.4970805\t2.957367634819564\t\ty\t2\t6\t\t256.87189917542054\n", + "300.150371\t425.261929\ty3^1\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t10000.0\t2.957367634819564\t\ty\t1\t3\t\t256.87189917542054\n", + "300.150371\t461.23049299999997\ty7^2\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t658.40723\t2.957367634819564\t\ty\t2\t7\t\t256.87189917542054\n", + "300.150371\t507.223495\tb4^1\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t544.8236215\t2.957367634819564\t\tb\t1\t4\t\t256.87189917542054\n", + "300.150371\t562.320842\ty4^1\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t758.6205095\t2.957367634819564\t\ty\t1\t4\t\t256.87189917542054\n", + "300.150371\t691.363436\ty5^1\tP09651\tHNRNPA1\tEDTEEHHLR\t(UniMod:199)EDTEEHHLR\t4\t386.09158199999996\t2.957367634819564\t\ty\t1\t5\t\t256.87189917542054\n", + "300.851044\t175.118953\ty1^1\tP14618\tPKM\tMQHLIAR\t(UniMod:199)MQHLIAR\t3\t6232.253602000001\t10.90490543435342\t\ty\t1\t1\t\t396.233918513634\n", + "300.851044\t180.123704\ty3^2\tP14618\tPKM\tMQHLIAR\t(UniMod:199)MQHLIAR\t3\t187.126964\t10.90490543435342\t\ty\t2\t3\t\t396.233918513634\n", + "300.851044\t215.11446800000002\tb3^2\tP14618\tPKM\tMQHLIAR\t(UniMod:199)MQHLIAR\t3\t1356.0843869999999\t10.90490543435342\t\tb\t2\t3\t\t396.233918513634\n", + "300.851044\t236.66573599999998\ty4^2\tP14618\tPKM\tMQHLIAR\t(UniMod:199)MQHLIAR\t3\t310.81490499999995\t10.90490543435342\t\ty\t2\t4\t\t396.233918513634\n", + "300.851044\t246.15606699999998\ty2^1\tP14618\tPKM\tMQHLIAR\t(UniMod:199)MQHLIAR\t3\t8887.643795\t10.90490543435342\t\ty\t1\t2\t\t396.233918513634\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
b_z1b_z2y_z1y_z2b_modloss_z1b_modloss_z2y_modloss_z1y_modloss_z2
00.0000000.0000000.0000000.0000000.00.00.00.0
10.5213950.0000000.0000000.0658410.00.00.00.0
20.2861040.0000000.0000000.1104500.00.00.00.0
30.0544820.0000000.0386090.0892800.00.00.00.0
40.0000000.0000000.0758620.8268720.00.00.00.0
50.0000000.0000001.0000000.3899810.00.00.00.0
60.0000000.0000000.7783770.0293820.00.00.00.0
70.0000000.0000000.6975810.0000000.00.00.00.0
80.0000000.0000000.0000000.0000000.00.00.00.0
90.0000000.0000000.0000000.0000000.00.00.00.0
100.0000000.1525810.0000000.0349720.00.00.00.0
110.0000000.0000000.0000000.0210550.00.00.00.0
120.0000000.0000001.0000000.0000000.00.00.00.0
130.0000000.0000000.7012270.0000000.00.00.00.0
\n", + "
" + ], + "text/plain": [ + " b_z1 b_z2 y_z1 y_z2 b_modloss_z1 b_modloss_z2 \\\n", + "0 0.000000 0.000000 0.000000 0.000000 0.0 0.0 \n", + "1 0.521395 0.000000 0.000000 0.065841 0.0 0.0 \n", + "2 0.286104 0.000000 0.000000 0.110450 0.0 0.0 \n", + "3 0.054482 0.000000 0.038609 0.089280 0.0 0.0 \n", + "4 0.000000 0.000000 0.075862 0.826872 0.0 0.0 \n", + "5 0.000000 0.000000 1.000000 0.389981 0.0 0.0 \n", + "6 0.000000 0.000000 0.778377 0.029382 0.0 0.0 \n", + "7 0.000000 0.000000 0.697581 0.000000 0.0 0.0 \n", + "8 0.000000 0.000000 0.000000 0.000000 0.0 0.0 \n", + "9 0.000000 0.000000 0.000000 0.000000 0.0 0.0 \n", + "10 0.000000 0.152581 0.000000 0.034972 0.0 0.0 \n", + "11 0.000000 0.000000 0.000000 0.021055 0.0 0.0 \n", + "12 0.000000 0.000000 1.000000 0.000000 0.0 0.0 \n", + "13 0.000000 0.000000 0.701227 0.000000 0.0 0.0 \n", + "\n", + " y_modloss_z1 y_modloss_z2 \n", + "0 0.0 0.0 \n", + "1 0.0 0.0 \n", + "2 0.0 0.0 \n", + "3 0.0 0.0 \n", + "4 0.0 0.0 \n", + "5 0.0 0.0 \n", + "6 0.0 0.0 \n", + "7 0.0 0.0 \n", + "8 0.0 0.0 \n", + "9 0.0 0.0 \n", + "10 0.0 0.0 \n", + "11 0.0 0.0 \n", + "12 0.0 0.0 \n", + "13 0.0 0.0 " + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| hide\n", + "reader = SWATHLibraryReader()\n", + "reader.import_file(StringIO(tsv_str))\n", + "reader.fragment_intensity_df" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.8.3 ('base')", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/nbdev_nbs/spectral_library/raw_library_generator.ipynb b/nbdev_nbs/spectral_library/raw_library_generator.ipynb new file mode 100644 index 00000000..a6bf8ba6 --- /dev/null +++ b/nbdev_nbs/spectral_library/raw_library_generator.ipynb @@ -0,0 +1,36 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#---#| default_exp spectral_library.raw_library_generator" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Generating Library from PSMs+RAW Files" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load PSMs and extract fragment intensities from RAW files." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.8.3 ('base')", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/nbdev_nbs/spectral_library/translate.ipynb b/nbdev_nbs/spectral_library/translate.ipynb new file mode 100644 index 00000000..96faec34 --- /dev/null +++ b/nbdev_nbs/spectral_library/translate.ipynb @@ -0,0 +1,883 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#---#| default_exp spectral_library.translate" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Translate Spectral Libraries" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Translate peptdeep spectral libraries into other formats (e.g. TSV)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from alphabase.spectral_library.translate import *" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0 _(ModNterm)AC(ModA@C)DEFG(ModB@G)HIK_(ModCterm)\n", + "1 _(ModNterm)AC(ModA@C)DEFG(ModB@G)HIK_(ModCterm)\n", + "2 _(ModNterm)AC(ModA@C)DEFG(ModB@G)HIK_(ModCterm)\n", + "3 _(ModNterm)AC(ModA@C)DEFG(ModB@G)HIK_(ModCterm)\n", + "4 _(ModNterm)AC(ModA@C)DEFG(ModB@G)HIK_(ModCterm)\n", + "5 _(ModNterm)AC(ModA@C)DEFG(ModB@G)HIK_(ModCterm)\n", + "6 _(ModNterm)AC(ModA@C)DEFG(ModB@G)HIK_(ModCterm)\n", + "7 _(ModNterm)AC(ModA@C)DEFG(ModB@G)HIK_(ModCterm)\n", + "8 _(ModNterm)AC(ModA@C)DEFG(ModB@G)HIK_(ModCterm)\n", + "9 _(ModNterm)AC(ModA@C)DEFG(ModB@G)HIK_(ModCterm)\n", + "dtype: object" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = pd.DataFrame()\n", + "df['sequence'] = ['ACDEFGHIK']*10\n", + "df['mods'] = ['ModNterm;ModB@G;ModCterm;ModA@C']*10\n", + "df['mod_sites'] = ['0;6;-1;2']*10\n", + "df[['sequence','mods','mod_sites']].apply(create_modified_sequence, axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "assert create_modified_sequence(('ACDEFGHIK','ModNterm;ModB@G;ModCterm;ModA@C','0;6;-1;2'), mod_sep='[]')=='_[ModNterm]AC[ModA@C]DEFG[ModB@G]HIK_[ModCterm]'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "assert create_modified_sequence(\n", + " ('ACDEFGHIK','ModNterm;ModB@G;ModCterm;ModA@C','0;6;-1;2'),\n", + " {'ModNterm':'Mod(Nterm)', 'ModCterm':'Mod(Cterm)', 'ModA@C':'ModA(C)', 'ModB@G':'ModB(G)'},\n", + " mod_sep='()'\n", + ") == '_(Mod(Nterm))AC(ModA(C))DEFG(ModB(G))HIK_(Mod(Cterm))'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "assert create_modified_sequence(\n", + " ('ACDEFGHIK','ModNterm;ModB@G;ModCterm;ModA@C','0;6;-1;2'),\n", + " {'ModNterm':'Mod(Nterm)', 'ModCterm':'Mod(Cterm)', 'ModA@C':'ModA(C)', 'ModB@G':'ModB(G)'},\n", + " mod_sep='()', nterm='', cterm=''\n", + ") == '(Mod(Nterm))AC(ModA(C))DEFG(ModB(G))HIK(Mod(Cterm))'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from alphabase.peptide.fragment import create_fragment_mz_dataframe" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
b_z1y_z1y_modloss_z1
072.0443901376.5275551278.550659
1239.0427501209.5291950.000000
2296.0642131152.5077320.000000
3433.1231251015.4488200.000000
4536.132310912.4396350.000000
............
105585.208572634.3129780.000000
106771.287885448.2336650.000000
107902.328370317.1931800.000000
108973.365484246.1560660.000000
1091044.402598175.1189520.000000
\n", + "

110 rows × 3 columns

\n", + "
" + ], + "text/plain": [ + " b_z1 y_z1 y_modloss_z1\n", + "0 72.044390 1376.527555 1278.550659\n", + "1 239.042750 1209.529195 0.000000\n", + "2 296.064213 1152.507732 0.000000\n", + "3 433.123125 1015.448820 0.000000\n", + "4 536.132310 912.439635 0.000000\n", + ".. ... ... ...\n", + "105 585.208572 634.312978 0.000000\n", + "106 771.287885 448.233665 0.000000\n", + "107 902.328370 317.193180 0.000000\n", + "108 973.365484 246.156066 0.000000\n", + "109 1044.402598 175.118952 0.000000\n", + "\n", + "[110 rows x 3 columns]" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "repeat = 10\n", + "charged_frag_types = ['b_z1','y_z1','y_modloss_z1']\n", + "precursor_df = pd.DataFrame({\n", + " 'sequence': ['ASGHCEWMKYR']*repeat+['ASGHCEWMAAR'],\n", + " 'mods': ['Acetyl@Protein N-term;Carbamidomethyl@C;Oxidation@M']*repeat+[''],\n", + " 'mod_sites': ['0;4;8']*repeat+[''],\n", + " 'nAA': 11,\n", + " 'NCE': 20,\n", + " 'instrument': 'QE',\n", + " 'rt_pred': 10,\n", + " 'charge': 2,\n", + " 'protein_name': 'unknown',\n", + " 'mobility_pred': 1,\n", + "})\n", + "precursor_df.loc[0,['mods','mod_sites']] = ['Phospho@S','2']\n", + "frag_mass_df = create_fragment_mz_dataframe(precursor_df, charged_frag_types)\n", + "frag_mass_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sequencemodsmod_sitesnAANCEinstrumentrt_predchargeprotein_namemobility_predfrag_start_idxfrag_end_idx
0ASGHCEWMKYRPhospho@S21120QE102unknown1010
1ASGHCEWMKYRAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;81120QE102unknown11020
2ASGHCEWMKYRAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;81120QE102unknown12030
3ASGHCEWMKYRAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;81120QE102unknown13040
4ASGHCEWMKYRAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;81120QE102unknown14050
5ASGHCEWMKYRAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;81120QE102unknown15060
6ASGHCEWMKYRAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;81120QE102unknown16070
7ASGHCEWMKYRAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;81120QE102unknown17080
8ASGHCEWMKYRAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;81120QE102unknown18090
9ASGHCEWMKYRAcetyl@Protein N-term;Carbamidomethyl@C;Oxidat...0;4;81120QE102unknown190100
10ASGHCEWMAAR1120QE102unknown1100110
\n", + "
" + ], + "text/plain": [ + " sequence mods mod_sites \\\n", + "0 ASGHCEWMKYR Phospho@S 2 \n", + "1 ASGHCEWMKYR Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat... 0;4;8 \n", + "2 ASGHCEWMKYR Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat... 0;4;8 \n", + "3 ASGHCEWMKYR Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat... 0;4;8 \n", + "4 ASGHCEWMKYR Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat... 0;4;8 \n", + "5 ASGHCEWMKYR Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat... 0;4;8 \n", + "6 ASGHCEWMKYR Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat... 0;4;8 \n", + "7 ASGHCEWMKYR Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat... 0;4;8 \n", + "8 ASGHCEWMKYR Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat... 0;4;8 \n", + "9 ASGHCEWMKYR Acetyl@Protein N-term;Carbamidomethyl@C;Oxidat... 0;4;8 \n", + "10 ASGHCEWMAAR \n", + "\n", + " nAA NCE instrument rt_pred charge protein_name mobility_pred \\\n", + "0 11 20 QE 10 2 unknown 1 \n", + "1 11 20 QE 10 2 unknown 1 \n", + "2 11 20 QE 10 2 unknown 1 \n", + "3 11 20 QE 10 2 unknown 1 \n", + "4 11 20 QE 10 2 unknown 1 \n", + "5 11 20 QE 10 2 unknown 1 \n", + "6 11 20 QE 10 2 unknown 1 \n", + "7 11 20 QE 10 2 unknown 1 \n", + "8 11 20 QE 10 2 unknown 1 \n", + "9 11 20 QE 10 2 unknown 1 \n", + "10 11 20 QE 10 2 unknown 1 \n", + "\n", + " frag_start_idx frag_end_idx \n", + "0 0 10 \n", + "1 10 20 \n", + "2 20 30 \n", + "3 30 40 \n", + "4 40 50 \n", + "5 50 60 \n", + "6 60 70 \n", + "7 70 80 \n", + "8 80 90 \n", + "9 90 100 \n", + "10 100 110 " + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "precursor_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "11it [00:01, 6.85it/s]\n", + "11it [00:00, 2684.12it/s]\n" + ] + } + ], + "source": [ + "spec_lib = SpecLibBase(charged_frag_types)\n", + "spec_lib._precursor_df = precursor_df\n", + "spec_lib._fragment_intensity_df = frag_mass_df.copy()\n", + "spec_lib._fragment_mz_df = frag_mass_df.copy()\n", + "df = speclib_to_single_df(spec_lib, min_frag_mz=300, max_frag_mz=1800)\n", + "assert (df.FragmentMz>=300).all()\n", + "assert (df.FragmentMz<=1800).all()\n", + "df = speclib_to_single_df(spec_lib, min_frag_mz=200, min_frag_nAA=3)\n", + "assert (df.FragmentNumber>=3).all()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| hide\n", + "\n", + "import tempfile\n", + "from alphabase.peptide.fragment import create_fragment_mz_dataframe" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "11it [00:00, 3152.75it/s]\n", + "100%|██████████| 6/6 [00:00<00:00, 67.25it/s]\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
ModifiedPeptidePrecursorChargeTr_recalibratedIonMobilityStrippedPeptidePrecursorMzFragmentTypeFragmentMzRelativeIntensityFragmentChargeFragmentLossTypeFragmentNumber
0_AS(Phospho)GHCEWMKYR_2101ASGHCEWMKYR724.285972y1376.5275551.0000001noloss10
1_AS(Phospho)GHCEWMKYR_2101ASGHCEWMKYR724.285972y1278.5506590.9288231H3PO410
2_AS(Phospho)GHCEWMKYR_2101ASGHCEWMKYR724.285972b1273.4529930.9251201noloss10
3_AS(Phospho)GHCEWMKYR_2101ASGHCEWMKYR724.285972y1209.5291950.8786811noloss9
4_AS(Phospho)GHCEWMKYR_2101ASGHCEWMKYR724.285972y1152.5077320.8372571noloss8
.......................................
127_ASGHCEWMAAR_2101ASGHCEWMAAR609.760775b771.2878850.6721601noloss7
128_ASGHCEWMAAR_2101ASGHCEWMAAR609.760775y763.3555710.6652471noloss6
129_ASGHCEWMAAR_2101ASGHCEWMAAR609.760775y634.3129780.5527891noloss5
130_ASGHCEWMAAR_2101ASGHCEWMAAR609.760775b585.2085720.5099961noloss6
131_ASGHCEWMAAR_2101ASGHCEWMAAR609.760775b456.1659790.3975381noloss5
\n", + "

132 rows × 12 columns

\n", + "
" + ], + "text/plain": [ + " ModifiedPeptide PrecursorCharge Tr_recalibrated IonMobility \\\n", + "0 _AS(Phospho)GHCEWMKYR_ 2 10 1 \n", + "1 _AS(Phospho)GHCEWMKYR_ 2 10 1 \n", + "2 _AS(Phospho)GHCEWMKYR_ 2 10 1 \n", + "3 _AS(Phospho)GHCEWMKYR_ 2 10 1 \n", + "4 _AS(Phospho)GHCEWMKYR_ 2 10 1 \n", + ".. ... ... ... ... \n", + "127 _ASGHCEWMAAR_ 2 10 1 \n", + "128 _ASGHCEWMAAR_ 2 10 1 \n", + "129 _ASGHCEWMAAR_ 2 10 1 \n", + "130 _ASGHCEWMAAR_ 2 10 1 \n", + "131 _ASGHCEWMAAR_ 2 10 1 \n", + "\n", + " StrippedPeptide PrecursorMz FragmentType FragmentMz RelativeIntensity \\\n", + "0 ASGHCEWMKYR 724.285972 y 1376.527555 1.000000 \n", + "1 ASGHCEWMKYR 724.285972 y 1278.550659 0.928823 \n", + "2 ASGHCEWMKYR 724.285972 b 1273.452993 0.925120 \n", + "3 ASGHCEWMKYR 724.285972 y 1209.529195 0.878681 \n", + "4 ASGHCEWMKYR 724.285972 y 1152.507732 0.837257 \n", + ".. ... ... ... ... ... \n", + "127 ASGHCEWMAAR 609.760775 b 771.287885 0.672160 \n", + "128 ASGHCEWMAAR 609.760775 y 763.355571 0.665247 \n", + "129 ASGHCEWMAAR 609.760775 y 634.312978 0.552789 \n", + "130 ASGHCEWMAAR 609.760775 b 585.208572 0.509996 \n", + "131 ASGHCEWMAAR 609.760775 b 456.165979 0.397538 \n", + "\n", + " FragmentCharge FragmentLossType FragmentNumber \n", + "0 1 noloss 10 \n", + "1 1 H3PO4 10 \n", + "2 1 noloss 10 \n", + "3 1 noloss 9 \n", + "4 1 noloss 8 \n", + ".. ... ... ... \n", + "127 1 noloss 7 \n", + "128 1 noloss 6 \n", + "129 1 noloss 5 \n", + "130 1 noloss 6 \n", + "131 1 noloss 5 \n", + "\n", + "[132 rows x 12 columns]" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#| hide\n", + "repeat = 10\n", + "charged_frag_types = ['b_z1','y_z1','y_modloss_z1']\n", + "precursor_df = pd.DataFrame({\n", + " 'sequence': ['ASGHCEWMKYR']*repeat+['ASGHCEWMAAR'],\n", + " 'mods': ['Acetyl@Protein N-term;Carbamidomethyl@C;Oxidation@M']*repeat+[''],\n", + " 'mod_sites': ['0;4;8']*repeat+[''],\n", + " 'nAA': 11,\n", + " 'NCE': 20,\n", + " 'instrument': 'QE',\n", + " 'rt_pred': 10,\n", + " 'charge': 2,\n", + " 'protein_name': 'unknown',\n", + " 'mobility_pred': 1,\n", + "})\n", + "precursor_df.loc[0,['mods','mod_sites']] = ['Phospho@S','2']\n", + "frag_mass_df = create_fragment_mz_dataframe(precursor_df, charged_frag_types)\n", + "spec_lib = SpecLibBase(charged_frag_types)\n", + "spec_lib._precursor_df = precursor_df\n", + "spec_lib._fragment_intensity_df = frag_mass_df.copy()\n", + "spec_lib._fragment_mz_df = frag_mass_df.copy()\n", + "speclib_sdf = speclib_to_single_df(spec_lib)\n", + "with tempfile.TemporaryFile('w+') as f:\n", + " translate_to_tsv(spec_lib, f, batch_size=2, multiprocessing=False)\n", + " f.seek(0)\n", + " ddf = pd.read_csv(f, sep=\"\\t\")\n", + "assert len(ddf) == len(speclib_sdf)\n", + "assert ddf.StrippedPeptide.values[0] == speclib_sdf.StrippedPeptide.values[0]\n", + "assert ddf.StrippedPeptide.values[-1] == speclib_sdf.StrippedPeptide.values[-1]\n", + "assert ddf.PrecursorCharge.dtype in [np.int,np.int8,np.int32,np.int64]\n", + "ddf" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.8.3 ('base')", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.8.3" + }, + "vscode": { + "interpreter": { + "hash": "8a3b27e141e49c996c9b863f8707e97aabd49c4a7e8445b9b783b34e4a21a9b2" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/nbdev_nbs/statistics/regression.ipynb b/nbdev_nbs/statistics/regression.ipynb new file mode 100644 index 00000000..f89f0830 --- /dev/null +++ b/nbdev_nbs/statistics/regression.ipynb @@ -0,0 +1,325 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Regression" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#---#| default_exp statistics.regression" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from alphabase.statistics.regression import *" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| hide\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#|hide\n", + "from nbdev.showdoc import show_doc" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/statistics/regression.py#L85){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### LOESSRegression.fit\n", + "\n", + "> LOESSRegression.fit (x:numpy.ndarray, y:numpy.ndarray)\n", + "\n", + "fit the model passed on provided training data.\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| x | ndarray | float, of shape (n_samples,) or (n_samples, 1), Training data. Note that only a single feature is supported at the moment. |\n", + "| y | ndarray | of shape (n_samples,) or (n_samples, 1) Target values. |\n", + "| **Returns** | **self: object** | **Returns the fitted estimator.** |" + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/statistics/regression.py#L85){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### LOESSRegression.fit\n", + "\n", + "> LOESSRegression.fit (x:numpy.ndarray, y:numpy.ndarray)\n", + "\n", + "fit the model passed on provided training data.\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| x | ndarray | float, of shape (n_samples,) or (n_samples, 1), Training data. Note that only a single feature is supported at the moment. |\n", + "| y | ndarray | of shape (n_samples,) or (n_samples, 1) Target values. |\n", + "| **Returns** | **self: object** | **Returns the fitted estimator.** |" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "show_doc(LOESSRegression.fit)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/markdown": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/statistics/regression.py#L184){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### LOESSRegression.predict\n", + "\n", + "> LOESSRegression.predict (x:numpy.ndarray)\n", + "\n", + "Predict using the LOESS model.\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| x | ndarray | float, of shape (n_samples,) or (n_samples, 1) Feature data. Note that only a single feature is supported at the moment. |\n", + "| **Returns** | **numpy.ndarray, float** | |" + ], + "text/plain": [ + "---\n", + "\n", + "[source](https://github.com/MannLabs/alphabase/blob/main/alphabase/statistics/regression.py#L184){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n", + "\n", + "### LOESSRegression.predict\n", + "\n", + "> LOESSRegression.predict (x:numpy.ndarray)\n", + "\n", + "Predict using the LOESS model.\n", + "\n", + "| | **Type** | **Details** |\n", + "| -- | -------- | ----------- |\n", + "| x | ndarray | float, of shape (n_samples,) or (n_samples, 1) Feature data. Note that only a single feature is supported at the moment. |\n", + "| **Returns** | **numpy.ndarray, float** | |" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "show_doc(LOESSRegression.predict)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Application example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/georgwallmann/miniconda3/envs/alphadia/lib/python3.8/site-packages/sklearn/utils/estimator_checks.py:290: SkipTestWarning: Can't test estimator LOESSRegression which requires input of type ['1darray']\n", + " warnings.warn(\n" + ] + } + ], + "source": [ + "#| hide\n", + "check_estimator(LOESSRegression())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhYAAAGdCAYAAABO2DpVAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAA9hAAAPYQGoP6dpAABvBUlEQVR4nO3dd3yT5frH8U/a0kFtC2W17AqI7ClDUBRBUMAtiuDAzQ8UxQHq4SgHFdFznCAqKqJMB8gSkKUIgiAVsIIsAVkFWS2UlpYmvz9CStNmN2lGv+/Xqy9o8iS5m47neu77uq/LYDKZTIiIiIh4QZi/ByAiIiKhQ4GFiIiIeI0CCxEREfEaBRYiIiLiNQosRERExGsUWIiIiIjXKLAQERERr1FgISIiIl4TUdovaDQaOXjwIHFxcRgMhtJ+eREREfGAyWTi1KlTVK9enbAw+/MSpR5YHDx4kFq1apX2y4qIiIgX7Nu3j5o1a9q9v9QDi7i4OMA8sPj4+NJ+eREREfFAZmYmtWrVKjiP21PqgYVl+SM+Pl6BhYiISJBxlsag5E0RERHxGgUWIiIi4jUKLERERMRrFFiIiIiI1yiwEBEREa9RYCEiIiJeo8BCREREvEaBhYiIiHhNqRfIEhERkQvyjSbW7T7OkVM5VI2Lpl1KIuFhwdtLS4GFiIiInyxKO8SoeVs4lJFTcFtyQjQv9mlMz6bJfhyZ57QUIiIi4geL0g4xaEqqVVABkJ6Rw6ApqSxKO+SnkZWMAgsREZFSlm80MWreFkw27rPcNmreFvKNto4IbAosRERESiDfaGLNrmPM2XiANbuOuRQMrNt9vNhMRWEm4FBGDut2H/fiSEuHcixEREQ85GmOxJFT9oOKwpZsSadjvUolHmdp0oyFiIiIB0qSI1E1Ltql1/h09R4WpR3yaFbEXzRjISIi4iZnORIGzDkS3RsnWW0dtWwtXfzHIQwGMDmJDwzAiFm/89LcLaRnBsfOEQUWIiIibnInR8KylGFr2cQZE3DyTB6QZ3W7ZVZkwoDWARdcaClERETETa7mSFiOs7ds4qlA3jmiwEJERMRNruZIVI2LdrhsUhKBunNEgYWIiIib2qUkkpwQjb3C2wbMeRDtUhKdLpuUlKuzJ6VFgYWIiIgTRXdlALzYpzFAseDC8vmLfRoTHmbw+Yl/x+HTAbVTRMmbIiJSpjlrAuaoVsWEAa2L3ZdUZMeGq8smRSXFR5FzzkjGmTyHyyjjVuxk3IqdAbNTxGAyOdvs4l2ZmZkkJCSQkZFBfHx8ab60iIiIFWcFrixJl/ZOlE92a8Cgq+qzYe8Ju4FJvtFE57HLSc/IcSnP4oFOdenWOIl2KYks2ZLOoCmpAE4fa3lFX+0UcfX8rcBCRETKJHtBg+UEPf6uVoxesNVpfkRSfDQv3eB4psDyWmA/QLA34+DONlUD5hmTVcO7er31ugILEREROyyzCPZO1gagYmw5jmfl2bzf1vHOZgpsBQiJseW4uWWNghkKe8GAZblm9c5/GLdil9PxTH+og9dLgbt6/laOhYiIlDmuFLhyNaiwsFVps7CeTZPp3jjJYT5HUUXzP+pVjXNpLP7cKaLAQkREyhxvn3htVdq0JTzMYH3/qVOwfj2sWwd//QUHD0JGBoSFcTQP1uSWZ3tMJdKS6rOhRiMiKlV0aTyeJox6gwILEREpc1w98SbGRnIiK9fl4lZFAxabO05OZcLMmfDVV7BiBeTn23yuykCfQp8bMbA5uQFzGndh/qVX8s9FxYMMS45Fu5REF0fsfQosRESkzLEUuLK3U8Nygh7ZqzGDp6W6/LyFA5aiORU1T6bz+Ob53LJpCRFnsi48qHZt6NABGjeGGjXIT6jAv2dvJifjNMmn/qHuiUO0Ovgn9Y4foOWh7bQ8tJ3nV3zK3MZd+KDdreyoUqdgzHChfoa/KLAQEZEyJzzMwIt9GjNoSioGrHdqFD5B92yazISw1rw09w/SM8/afb6iMwWFd5wkZJ/isZ9ncE/qAiKN5wA4Ve8S4h4cCLfeCg0aWD3Xul3HmLohpthrVD11jJ7bf+bmP36g1aFt3Jq2nFvTljOrydW81uU+wmvWUB0L7QoRERF/clbHwiLfaGLc8p28tXR7secoWj+iYMfJyWxu2LqSl5Z+SGJ2JgCr6rTgw/a3sbNFB1aNuMbmzMKcjQcYOmOjw3E3P7SdCQeWUmPZd+bxlY/F8J9RhD35JIT5pqi2doWIiIg44epOjfAwA0O7NaBh0kVOK22u232c7PQjvL9oHNdv/xmAbZVr8+rVD/DjxW3MD8o8azfRs/JFUU7HvTn5Ev7+9z3UOP4XDB1K+Jo18PTTMH8+fPYZ1Knj4TtScgosRESkTCu2U8MBVwKRs7+sY/5nT1Az8wh5YeGM63gH4zv25Vy49SnX1s6URWmHeGnuHw7HYLXsUq8SrF4NH3+M6cknMfzwA3lNm/Hnp1/S+NYefsm1UBMyERERN1gCkd7NqwMwf/PBC03ApkzhyoE3UzPzCHsqJHPTPW/yTue7igUVUHxniiUvw1kuBxRJ0DQYWNSxN7c/OoEN1S9lf7mLuGPNaTqPXc6itENe+ZrdoRwLERERNxXLzTCZeGbTHAYv/hiAny7tyOAeQ8mMvqjYY22V3XZWCdTCVv7Hd5sP8X/nd66EG/OpdvoYB+Orer13iKvnb81YiIiIuMEys1A4qBi5/OOCoGL3fY+SNfMrTkVf5LSluoWzSqAW/72tRZGg4iBDpl/YDpsfFs7B+KrmYZ2/bdS8LaXaUl2BhYiIiIvyjSZGzdtyYXuqycSLyz7igV/nADC664PcXPdm4spHMf6u1iQlWC93JMSU44luDejeOMnqdlcrgR7NurBMsijtEP837TccxQyFK4KWFiVvioiIuMhqZuH8TMXADfMwYmD4dY/zVfPukJ1H/49/ITkhmpG9GrHjSBaTVu/mZHYeJ7PzeGvpDmas32e1pOFqJVDLcZYAx1Wl2TtEMxYiIiIuKnyCfuznGQUzFSN6PmYOKgpJz8jh/6b9xltLt3MyO6/YfYOmpBYkV1oqgdrbw2HAnF9hKcDl6tKJRWn2DlFgISIi4iLLCfr2zUt4atVUAEZ2f5QvW1xb7FhHWQ1F8x8slUABl/Iy3JmBSC7l3iEKLERERFzULiWRG4+kMWbRewCM73A7X7Tu7dFzFc1/6Nk0mQkDiudlJCVEW1X1XLPrGDsOn3L5dUq7d4hyLERERFwU/tcu/vv1GCJMRmY1uZo3rrynxM9ZePbBUQEuW+XHHQkzwLh+3tlq6g4FFiIiIthpcV74Sv/UKbjxRsqdyuBEiza8feszkGUs8esWzX+wVQm0cFMzV43r14rrm5d+QzIFFiIiUuY5bUZmMsH998OWLZCcTMWF81hRLYm1u44xeFpqseRMVxTtiGpPsS2uTtgqolWaFFiIiEiZZm82wLJzY8KA1vRcORu+/hrKlYNZsyA5mXCgU4PKvHZrM7dnE+wVyrLF1R0gQ66uT6f6lW02UStNSt4UEZEyy9FsgOW2aR/OxTRsmPmTsWOhQwer4yxJl4mx5Vx+3cIJmc64ugOkQbWL6Fivkl+DCtCMhYiIlGHOZgOi8nJ4cdrLGM6ehd694YknbB7Xs2ky2XlGnpy50elrDrm6Hk92b+hyAOBu8Sx/04yFiIiUWc5mA0b88Bn1ju8nu0o1mDQJDPaDgaR4107snepXcWtWwd3iWf6mwEJERMosR1f5nfZs5L7U+QDsfn0cVK7s8Ll8FQC4WzzL3xRYiIhImWUvGIg7m8Ub370NwJeX9ab+gFucPpcvAwBXimcFCoPJZCq9Xqq43s9dRESkNFh2hcCFhM2XF49nwMaF7KmQzHUD36NClQoub+F0unW1BJzW2vAhV8/fCixERKTMKxwMtNm/hW+mPgvAnf1eZW3t5gUzDq7ODvgzAPAVV8/f2hUiIiJlXs+myXS9tBqdRy9izKJxAMxs1p21tZsD5pkMA+amYd0bJzkNEmxVzywrlGMhIiICbNh7gttXzOCSY39ztHwCr159v9X9RZuGiW0KLERERICstC08/vMMAEZ3fZCMmDibx7nTsrwsUmAhIiJiMnHZa88TlZ/HyrqtmNP4KruHBkohqkClHAsREZHPPydh7SpyykXxrx6DbRbCcrVpWFnn1oxFfn4+I0eOJCUlhZiYGOrVq8fo0aMp5Y0lIiIiNuUbTazZdYw5Gw+wZtcxcs8ZrT7PN9o4X2VkwDPPALB38FPsq5AUFIWoApVbMxZjx45lwoQJTJ48mSZNmvDrr78ycOBAEhISePzxx301RhEREads1Y8IM0DhWMJmPYlXXoF//oGGDWn4+ktM2Ha02PMk+bkVeTBxq45F7969qVatGp988knBbbfeeisxMTFMmTLFpedQHQsREfE2e63PiypWj2LXLmjUCPLyYP586NULCM06FCXl6vnbraWQyy+/nGXLlrF9+3YANm3axKpVq7juuutKNloREREPOWp9XpTlmFHztpiXRZ591hxUXHstXH99wXGWOhQ3tqwREK3Ig4lbSyEjRowgMzOTSy+9lPDwcPLz83nllVfo37+/3cecPXuWs2fPFnyemZnp+WhFRESKcNb6vChLPYot3yym2axZEBYG//ufw86l4jq3Ziy+/PJLpk6dyrRp00hNTWXy5Mn897//ZfLkyXYfM2bMGBISEgo+atWqVeJBi4iIWHhaVyLpjdHm/wwcCE2benFEZZtbORa1atVixIgRDB48uOC2l19+mSlTpvDnn3/afIytGYtatWopx0JERLxiza5j9Ju41q3HXL5nI9Nm/gsiI2HHDqhd20ejCx0+6RVy5swZwsKsJznCw8MxGo12HxMVFUVUVJQ7LyMiIuIyS+vz9Iwcl/IsDCYTz/081fzJI48oqPAyt5ZC+vTpwyuvvMKCBQvYs2cPs2fP5s033+Tmm2/21fhEREQcCg8z8GKfxgDF6k8UZQCu+utXmu3bCjEx8PzzPh9fWeNWYPHee+9x22238X//9380atSIp59+mkceeYTRo0f7anwiIiJO9WyazIQBrUlKsC63XXQzR1J8FG/uXGD+ZPBgSEoqpRGWHW7lWHiD6liIiIivFK0/0aZORTbsPXGhHsW+NMKvvgqiomD3bkhWwStX+STHQkREJJBZ6k8UZvX5kNfM/953n4IKH1F3UxERCXn5RhOb5q6ARYswhYWR/9TT/h5SyFJgISIiIW1R2iE6j13OnhGjAJjb8Ao6f72XRWmH/Dyy0KTAQkREQpalh4hx/36u37YKgI/a30J6Rg6DpqQ6DS6Kdku12R1VrCjHQkREQlLhHiIDfltIOWM+v9Rswh/V6gHmraej5m2he+Mkm71AbHVLtdkdVaxoxkJEREKSpYdI1Llc7tq4EIBJbW8ouN/SM2TtrmPFHmuZ6Sjag8TVmY6yTIGFiIiEJEsPkRu2/ECl7Ez2x1dhSYMOxY4bPM06UHDULbVYd1QpRoGFiIiEpKpx0WAyMXDDPAC+aN2L/LDwYsedzM6zmoVw1i3VMtOxbvdxn4w72CmwEBGRkNQuJZFrTu2h8ZHd5EREMqN5D4fHW2YhXO2W6mlX1VCnwEJEREJSeJiBUYfMO0EWNOxERkyc3WMLz0JUjYu2e1xhrh5X1iiwEBGRoGZ3S2hGBjUXzwVgXvs+Lj3XkVM5Bd1S7TU0M2DeHdIuJbHkgw9B2m4qIiJBy+GW0B9nQXY2NG7MQyMG8MMn65w+X9W46IJuqYOmpGIAqyROS7DxYp/GNreoimYsREQkSDncEvrFBk69M958wyOP0KFeZbdmIex1S01KiGbCgNaqY+GAZixERCToONsS2iJ9B3E7tmKKjsZw990ezUL0bJpM98ZJVt1S26UkaqbCCQUWIiISdJxtCb05bTkAx7pfT+WKFYELsxBFl06SHFTTtNUtVRxTYCEiIkHH0VbPcvl53LB1JQA7etxM5UL3aRbC9xRYiIhI0HG01bPLX6kkZmdyJLYidOte7H7NQviWkjdFRCToONoSekvaMgAWt7ia9DPn7HYlVedS39CMhYiIBB17yZjxOae5Zpd5W+m0hlexdeZGoHhXUnUu9R3NWIiISFCytSW0958/EZV/jq1V6rK16sUFtxfuSqrOpb6lGQsREQkq+UaTVfLlj89czYa9J0jPyCZl2rMAzGrS1eoxJszbSl+a+wdgsLtN1YC5Z0j3xklK6PSQAgsREQkajpYw6pxMp+W+LeQbwpjTuEuxx5qA9MyzDp+/cM8QJXh6RoGFiIgEBcsSRtHZBssSxmd7FwCwqm5LjsSVLChQ51LPKbAQEb8qOq2tmgJii7NKmwaTiYsXfwvArCZXl/j11LnUcwosRMRvlJkvrnJWabP1ga3UOnGIrMgYljToaPMYA1AtPgowcDgzx2aQYsBciVOdSz2nXSEi4hclzcxXDYKyxdnSxK3nS3jvuKIH2ZHF61tYPn/phia8dENjq9uKHqPOpSWjGQsRKXVOp7VxnJmvmY6yx9HSRET+Oa7bthqAyHvuZkJr5/1A3O0ZIq5TYCEipc7ZtLajzHxnCXxqaR2aLJU20zOKL2FcvncTFXNOcTy2Ag3v7EPjyHJO+4GoZ4jvKLAQkVLnasZ90eNKOtMhwctR2/Pef/4EwOneN5IYWa7geGfbRdUzxDeUYyEipc7VjPuix7kz0yGhx1alzXL5efTcsRaA2oMG+mtoUohmLESk1Dma1gb7mfmeznRI6Ci6hHHJryuJzzkNycnQubO/hydoxkJE/MAyrQ3uZeZ7OtMhocWyhHFjyxo0WrnQfONtt0F4uH8HJoACCxHxE1vT2mCeqbCXgOmoVTaYg5Jk1SAoO3Jy4Ntvzf+/4w6/DkUu0FKIiPiNu5n5jhL4VIOgDFq8GE6dgpo1oaPtolhS+hRYiIhf2crMd1Tm2zLToRoEwsyZ5n9vvx3CNAEfKBRYiEhAcVb8Kt9oIiEmkmd7NOR4Vi6JF0WRFK8aBGXOmTMwd675/1oGCSgKLEQkYDgrfvXwlSnM3XTIZtChoKKMWbgQsrKgTh1o187fo5FCNHckIgHBWfErE/Dhyt0e9xaREGNZBunbFwwKKgOJAgsRCQjOil/ZYwlERs3bokZkZUVWFsyfb/6/lkECjgILEQkIJSlqpYqboctmF9sFCyA7Gy6+GFq39vcQpQjlWIhIQPBGUStV3Awt9hJ5Z/04hWQwF8XSMkjAUWAhIl7jaJuoM87KfLtCFTdDh71E3hNHM4hfvsT8ya23lvq4xDkFFiLiFc62iTrjqPiVM/Z6i0hwcpTIe8We34jNyyE9oQpV2rRFRbwDj3IsRKTELFeXJd2xYa/Md3JCNI9cmYKB4r1FwByEXN/UXMFTCZzBz1Eib89tqwH4rn5H1u05UZrDEhdpxkJESsTZNlED5h0bXS+txoa9J5wukzgq892qdsVisyJhBjCa4JPVe/hk9R63ZkkkMNnLlSmXn0f3nesAWNjwcioppyYgKbAQkRJxtk3UsmOjw5hlHM/KLbjdUQBgq8w3WAcdS7ak8+nqPRSdoLDMkthrZCaBz16uzOV7NxN/Not/YiuwoUYjhimnJiBpKURESsTVnRiFgwrwvLBVeJiBdimJLExLt3m/6loEP3tdbC3LIIsuuZxqFWOVUxOgFFiISIl4uhOjJAGAq7MkqmsRnCyJvHAhpybcmM+1O9YC5sBCZdwDlwILEXFL0YJFbepUtHl16QpPAwBXZ0lU1yJ4FU3kbbfvDyplZ3KyfDz3jLhHy1wBTDkWIuIye1tKb2iRzEcrd7u9TdTC3QDA1VkS1bUIboVzaqq98BUA8XfcSo+Wtfw8MnFEMxYi4hJHW0o/Wrmbh69MKbZNNDG2nEvP7W4AYG8N3sKAOeDRGnzwCw8z0DGlIhev/B6AsNtu8/OIxBnNWIiIU65sKZ276RA/PnO11ZbSlrUq0Gns8mKJmxaeFrZyVEzLEmxoDT6ErF0Lhw5BfDxcc03BzSWp9Cq+o8BCRJxyNVlyw94TBdtEF6Udouv/fnAYVIDnAYBlDb7o0kyS6liEnm++Mf/bpw9ERQElr/QqvqPAQkSccjdZ0l6fh8JsBQDuXoE6KqYlIcJkKggs8m++hXW7jhXUMClKNUwCgwILEXHKnWRJR8smAPE5p+l94DdGta7I4Q8X8kdENKYOHdmf0ohRy3a7fQVqr5iWhIjUVNi7l3MxMXRLi2LP+rV2Dy1c6bV74yQFmH7idmBx4MABhg8fzsKFCzlz5gz169dn0qRJtG3b1hfjE5EA4KzzaOFcCXvLJq0PbGXIzzPpvGcjkcZz8DXUxPwBUC8iiodbXMuH7W4lPb4yoCtQAb7+GoDva7dmT7bzwwtvYVbA6R9uBRYnTpygU6dOXH311SxcuJAqVaqwY8cOKlas6KvxiUgAcCdZsuiySUL2KUb8MIl+m78vuG1rlbpsqXYxpyNjqHr6BG0PbKFK1kkGbpjHXRsX8kH723jv8js5Fx6hK9CyzGTC9M03GICFl1zu1kNVw8R/3Aosxo4dS61atZg0aVLBbSkpKV4flIgEhqI5D+Pvas3oBY6TJQsvm9Q7to9JX71E7YzDAHzZrBsftr+VXZWK1CEwmei0dxOP/zyD9vvSGPrzDLrs3sATvZ9mT2INXYGGCLd3caSlYdixg7Ph5Vhe7zK3Xks1TPzHrcBi7ty59OjRg9tvv50ff/yRGjVq8H//93889NBDdh9z9uxZzp49W/B5Zmam56MVkVJjL+t+ZK9GVIyNsntyOJF1ljADtPk7jYmzXqZCzmn2VEjm6V5P8GvNJrZfzGBgdd2WrK7bkl5bf+LVxeNoeWgHcz8fxiM3P8+aOi10BRrkPNrFcT5pc2VKK7Kiyrv0Op5uYRbvcatA1l9//cWECRNo0KABixcvZtCgQTz++ONMnjzZ7mPGjBlDQkJCwUetWqqYJhLoHBXDGjztNzKyc7mxZQ061qtkFVQsSjvE4Gm/0XL/Vj7/8kUq5JwmtXpDbrn7v/aDiiIWNLqCnveP49cajYg/m8XnX/6b235fqivQIObo58lhI7rzgcWiSzq59DqqYRIYDCaTyeUKvJGRkbRt25aff/654LbHH3+c9evXs2bNGpuPsTVjUatWLTIyMoiPjy/B0EXEF/KNJjqPXW63boXlinDV8K5Wf7wtj4v5aydfT32WxOxMfkhpw6M3P0dOOfeDgqhzubzx3dvcsHUlAMaxYwl79lmPvibxH09/nti2DS69FFNEBD2e+4odueWclotXHQvfyszMJCEhwen5260Zi+TkZBo3bmx1W6NGjfj777/tPiYqKor4+HirDxEJXJ52Dl23+zi5B9OZ/NWLJGZnsjG5AYNu8iyoADgbEckTfZ7mg/a3AhA2fDi88IK5roEEDY870Z6frTB068awvu3N/7fzHA90qsv0hzqwanhXBRUBwK3AolOnTmzbts3qtu3bt1OnTh2vDkpE/MfTzqFHMs7wvwVvUSvjMHsqJPPArS+SHVmy5YtqFcpT9+P3YMwY8w2vvgqPPQZGY4meV0qPx51oz28z5bbbinU6tUhOiOaDAa0Z2adJsWU58R+3kjeffPJJLr/8cl599VX69u3LunXr+Oijj/joo498NT4RKWWedg5t8dWn1N29gZyISB6+5QWOxVZw+7Xvu7wOPZokF08MbToCEhJg8GAYPx4yMmDSJIhQjb9A59HP065d8NtvEB4ON94IqMpqMHHrt/Kyyy5j9uzZPPfcc/znP/8hJSWFt99+m/79+/tqfCJSyiy7Oox2VhxsZt2vW0ed/74MwKhrHmZ7lboevXaPJsn2t5QOGmRuQnXvvTBlCpw4AdOnQ1ycR68lpcOd4moFzi+DnGzfiR/3n6VqxrGCIEJbjgOf2+F+79696d27ty/GIiJ+ZtnV4SyLwSrrPjcXBg7EcO4ch3r0YUaLHsWKaDnj8hbB/v3NgcQdd8CCBXDFFTB/PtSs6fhx4jeedKI9+cV0KgBvXNSUqTM2AkrMDCZu5ViISOhy1uMDIMwA4+8qUl779ddhyxaoWpXkaZ8x4e42NtfCH7kyBQPFE/Dc3iJ4ww3www9QtSps2gRt28KyZc4fJ35jL0ciKSG6WLn2H75fT4W0jRgxsPiSjgW3O92aKgFDC5QiAjjP3gfz8kjF2MgLN2zbBqNHm///zjuQmEjPROyuhbeqXdE7bc7bt4dffjEHGb//Dt27m3eMvPiiVd6F25UexWdcyZHIN5rY9M6nXAWsq9WEo7EX2kWowVjwUGAhIoD72fv5+UZOD3yIhNxcTnTpRvztfQk/f4y9tXCvJuDVrQtr18ITT8DEifDyy/D99/DFF3DJJZ5VehSfsvxcWAK++ZsPWv0MrNt9nE6bfgTgu4bFi2KpwVhwUGAhIoB72fuL0g6x7PWPeWPNT+RERNKnUT/yX1/h0knbkwQ8uzMP5cvDRx9B167m5M5166BlS/4YNpJBec0wGawDFnVL9T9HAZ/h4AF6HNhqPs5B0zGVdw9syrEQEeBC9r69uQMD5hPAiaxcHpu8jkcXfAjAJ21vZH9CNZ+tgS9KO0TnscvpN3EtQ2dspN/EtXQeu9z6de68k/xNmznZqQtkZ9Pklef57KsXqXrqmNVzWfJHRs3bQr69bS/iM85Ke0fNnQPA+hqNORJnP/hUeffApsBCRADzTMLIXo3tbgkEGNmrEaMXbKHfxoXUO36Af8pXYEKH2wHfnLRd7TGxKO0Qnadup1Wnp3ix2yPkRETSZXcqCz4bSoe/N1s91m6lR/EpR8nBltviF5gDi4U2lkHgQnCrBmOBTYGFiADmk/PoBVts3mfJ3q8YG8WpI8d5YvV0AN7ufBenC3Wd9OZJ25UT0ah5W/hu84Xgw2QIY3KbPvS67x22VE2hypmTTJnxLx5YN7tYKfCFaYdYs+uYZi5KibPk4MqnT9ByTxoAixt2LPnuIfEbBRYiYndmwGJkr0b0bGquiDnw1zkkZmeyM7EmM1r0sHm8N9bAXe0x8a85acWCj12VanHLgDf4psnVRJiMjFzxCS9//z7hxvyCYz5fs9dqWSXfaGLNrmPM2XhAAYcPOPuZ6LFjDWGYON60FX1v6UxCTDmr+21tTZXApORNkTIu32jipbn261cYgNELttKjaTLJ5HLV+m8BeKdTP/LDwm0+xhtr4K4GJ8ezcm3enlMumqd6DeOPavX51/KPGbBxIcmnjvLYDc9yJjKm4Lj0jBwenZJKhfLlOHkmr+B27SDxLmc/E9dtWwXA5OpteWfp9oLbK8SUY2Cnugzp2kAzFUFCMxYiZdy45TtIz3St+2TbOZ+TcDaL7ZVqs+DSzsWO9eYauFcS9AwGPr3sRgbd/Bw5EZFcs2s9M6eNoMrpC0s1loCqcFABKsjkbY6SgxPPZNDhb/MyyDcp7a3uy8jO4+2lO1iyJb0URineoMBCpAxblHaIt5bucOnY4wcPE/bWWwC82+lOTDZmK0yYl028cWXpyi6VxNhydu61tviSy7mz3xiOlk+g2eFdzP7iKeod3efwMdpB4l2W0t5QvPrqtdvXEG4ysjmpPvsrJFndp+9D8FFgIVJGWZIjXdV09hTIyCDz4ktoMPh+qsXbnlEYvWCrV67yHZ2ILJ+/fGNTh8EHmIOPuzvUYWP1htwy4L/8VbE6NTP/Yeb0ETQ+/JfDMWgHiXfZK+194841gP3dIPo+BBcFFiJllCslvC2qljNx0cQPABjZuA9vLd9JTt45m8d6cwnBWY+J65tXdxh8GIBXb27G9c3MeRJ/V0zmlrv/y+ak+lQ+k8H06c/R8uA2p+NQQSbv6dk0mVXDuzL9oQ68c2dLvrrtEtrv2QjAQgdFsUDfh2Ch5E2RMsqdP9Jd1y+m0ukTHIirwoJLrwDgZLbtwMLbPR2clQG3BB+OepDkG00FrbtPxsTT/85X+PSrUVx2YAufzxxJv36v8kdSfbtjUEEm77KqvjppEuTns6VqCnsSazh8nL4PwUGBhUgZ5eof6bjIMB5aPxuATy67iXPhzv9seLung7My4M6Cj6Ktu09FxXJP3//w2Vcv0n7/H3zx5b+5s9+rbK9S1+p5XW7nLp77+msAfmrepVhbdQt9H4KLlkJEyihnyZEAFcuXo2PaauodP0BGVCwzWlzr1muU5tS1Jfi4sWUNOtarVGympOiySnZkNA/c9iK/12hIYnYmU2aOpGbG4YLjVZCpFBw7Zm4cBzR+bCBgP59G34fgocBCpIxylhxpAG5pVYMHztetmNLqeqv6D64ItKnrwuv7b/VtwZO3tGHvlK85mtKQqlknmPTVS8TnnAZUkMkVJS4q9vXXcO4ctGrFFTdc6TCfRt+H4KGlEJEyzFl+QvKe7bTY/wd5YeF83rqXy88byFPX4WEGMrJzeX3xtoKvOannc8yd+jQNju1j2ep32PX5N1zWsOT5IaHMK23pp00z/9uvH+B8SUuCg8FkMpXqxuDMzEwSEhLIyMggPj6+NF9aROyw15bc+OCDhH3yCfMvvYIhNw536bksp4BAvcq0lC8v+oev8ZG/mDl1OHG52eYW7O+/75fxBQN776Fb3/t9+6BOHXMPl7//hlq1fDFU8SJXz99aChER2/kJx48Tdv6KcnKb3nbXviuUD7yeDvam6B01NttS9WIev+FZjAYDTJgAn31WqmMOFq42h3O6LDJzpjmouPJKBRUhRkshImLbp59Cdja0bMkDwwewf/5Wm8slgTZ1bWuKPik+in7tapOXb3RYu2NFvct45/J+PLl6Gjz6KDRvDq1bl8awg4arzeGc7giabu6QS79+dmfMJDgpsBCR4ozGC0sBQ4bQs1l1ujdJtvvH3xtbSr3B3hR9euZZl0uXv9vpTvqFHyFp5VK4805ITYWLLvL+YIOUqzt9HB7355/m9zUigmVNOvOvsctLlqshAUVLISJS3NKlsHs3VKhQkFjnbDunvzmaoneHyRDG3299ADVrwo4dMHSoV8YXKlzd6ePwuPOzFUc6duHBBXuLzYCoAVxwU2AhIsVNnGj+d8AAKF/ev2NxkTslyh1Jio+iTcuLYcoUMBjMS0JffVXsuBJvtQxSrjSHc9jh1mQqCCzGJ7crea6GBBwFFiJi7fBh+PZb8/8fftivQ3GHt4px5Zwzmlt0d+mCccQIAHIffIhf1/xRcJJblHaIzmOX02/iWobO2Ei/iWvpPHZ5mbjCDg8zMLJXY7sVMsFJMasNG2DHDvKjY/iqhv38FTUeC14KLETE2uTJ5qJF7dtDs2b+Ho3LvFWMK+NMHoOmpDLmuy1cWb4Lv1erR2RmBsfvfZDOry1jzHdbGDQltcxO3y9KO8ToBba74rq0I+j8TqNDV3Z3qeCaGo8FHwUWInKByXRhGSSIZivAtRLlrjCd//hw5W72nz7HM9c/QW5YBNfuWMtla7/nw5W7y+z0vSU51t6S08hejRwHFfn55m2mwOlbbnfpNQOteqs4p8BCRC5YuRJ27oS4OLjjDn+Pxi2OSpSXxJ9VUxh3ufm9eGnphySeybB7bChP3ztLjjUAoxdsdRxUrVwJBw9ChQrsadMJR/m/TnM1JGApsBCRCyxFoe68E2Jj/ToUTxRtNOYt73e4na1V6pKYncmIHyY5PT4Up+/dqV9h1/mfr33X9GLQ11twNrGjxmPBSYGFiJidPn1h98N99/l1KCVRuNHYO3e25Mlul5AUbx1oJMaWs/No286FR/DCtYMB6Pv7Utru/8Ph8Zbp+1DaOVLi+hWnThW0SP9PlfYOtwWHGWD8XYFZEl6cU4EsETH75hvIyoIGDaBjR3+PpkQsNTcshnStb1Xcq02dinR5YwXpGTku171IrdmIGc2v5c7N3/Py4vfpfd87nAu3/hNauPmaV5p0BZAS16/48ks4c4bsi+uzJD7F4XMYTVAxNtLdIUqA0IyFiJhZlkHuvddcvyGEFC3uFRkR5lE+xtgu93IiOo5Lj+7lvg3zrO6zPM/IXo0Yt3wnj4bYzhFX61e0qVPR9izNJPMS0l+9b3fp5ysUl5PKCnU3FRFzlc2LLzb/wd+zB2rX9veISoWtWQVn7ti0mLGL3iMrMoauD07gcFxlwHxSvaFFMnM2HiQ986zdx1tmNVYN7xp0+QOWXSGA1UyP5at4+MoU5m46VGyWZmyzKK7scwWEhfHrT5u4be5ep681/aEOAVMqXszU3VREXDdlivnfrl3LTFAB1vkYb/VtQWJspNMZjC+bdye1ekNic7MZvfJTHuhUl+kPdWBkr8Z8tHK3w6ACgnvniL3k2KSEaB6+MoWPVu62OUuT9so755+gJ606NClZ5U4JeMqxECnrCpVY5u67/TsWPyicjxETGc6gKakYwG7uhckQxr+uHcy8yU9wbdpKpkyZRZsXHmD0gq1u9SkJ1qn+nk2Ti3W0teSs2Pr6I/Lz6Lt5KQD5A+8v2BZs6312qXKnBDzNWIiUdZs3w9atEBUFN9/s79H4lb0r8qLnuC3VLmZy696AubbFS9/85nafkmAu/FQ0Z2XD3hN2v/6e236m8pmTpF+UyLpmnc23OZj5cFq5UwKeZixEyjrLbEWvXqC8p2JX5D9tP8rXqfuLHffWFf3ps3UlFx8/QJ+fZvNJO9eCssI7R0KFo9mXAb99B8CMFj1IyT5XcLutmY92KYmaqQgBmrEQCUEu108wGi8EFufbo8uFK/KoiDCbQQXAqahY3rjyHgCGrp5O5awTLj9/qE3125t9ueSfPbTf/wfnDGFMb9Gj2HFFZz5C6T0pyzRjIRJi3KqfsGYN/P23uYR3r16lPNLAZilh7chXzbsxYON3NE/fyQs/T2VY9yEO8yyCuY6FI5atqEXrgvTfuBCAJQ068E98ZU5k5fpngFKqNGMhEkLsNYmyWz/BMltx880Q47zTZFnirIQ1mBM5R11jbtZ202+LaZq+0+5uhye7NWDV8K4hF1SAdZ8Wi/ic09yathyAKa2ux2iCwdOCs4aHuEeBhUiIcNQkymbnzXPnLpTw1jJIMa7u2thQszEHr78Zg8nE55unkhQfZXV/ckI0HwxozdBul4T0VH/PpsmMv6tVQaLrgN++46LcbLZWqcvqOi0Kjgvl7q9ipqUQkRDhTpOojvUqwfLlcOQIVK4M11xTegMNEq7u2niy2yVUH/IuNFxMxd/Ws3rYYX7p2LNMJiRWjI3CaIKoc7kFlUk/andLQaXNYj+DEpI0YyESIly9wk7PyGbNrmP8Pf4TAIy33Qbl3GvKVRY4K2ENkBQfxZCu9aFmTXj+eQDCRgynY1J0mUxItPwM3vTHCqpmneBgXGXmNbrS7nESmhRYiIQIV6+wRy/Yyn0TVlJh0XwABhkbBuy6tz+7gxbOGygaGhjOf7x0Q5MLgcOwYVC3Lhw4AK+9VmrjtPDle+Xqc1eNi8ZgMvLwutkAfNL2xmKN2izHSejSUohIiLCXmV/U8axceuz6lfjcMxyIq8KSCvX4fkpqwBUmCoTuoJZCTkXHkWRrHDEx8L//wa23whtvwP33Q4rjLp625BtNbtd28OV75c5zt0tJ5O69a6l3fD+ZUbHMaNHD6v5QrOEhxakJmUgIsdckqqjx346h17bVfNDuFl67+v6Aa4xl+TqKfg2WkZV2EOTyyd5kgm7dzPkrt9xibkXvxuM9CRB8+V65/dx5eWTVu4TYfXv43xUDeO/yO706HvEvNSETKYPslUpOjL2QQ3HR2TNcs2s9APMadwECqzGW27tbSoHLhZwMBnjnHQgPh1mzYPlyFqUdovPY5fSbuJahMzbSb+JaOo9dXmz5ye2twvj2vfLouT/5hNh9ezibWJkFXe+weozKdZcdWgoRCTG2SiWnZ+bw5MyNAHTfsZboc7nsSqzJH1UvtnpsICTVub27JdA0bQqDBsG4cZx6ZDBDbh7LubBwq0MswYLlROvsJG7AfBLv3jjJKqjx5Xvl9nOfOQOjRgEQNepFlvxfL5XrLqM0YyESgopeYSfFX5jBuHHLjwDMadylYBugRSAk1bka3ARCEGTXqFGYEhOJ2/kn/c5Xnyys6BW/Oyfxwnz5Xrn93K+9Bunp5gTWhx9Wue4yTIGFSBlgSeysdCaDznt+A2BuoW2ABsxr+YGQVOdqcBMIQZBdiYnsfnwEAE/9NIUK2ZnFDikcLHgaIPjyvXLrudPSLuyEeeMNiIx0+/UkdCiwECkDLFsnr9u2mgiTkc1J9dmTWAO4kFQXKI2xnNWPCKQgyJG0Xn3ZWqUuFXJO8+SqqXaPsywVuKLocb58r1x+7toJ8OCDkJcHN9xg3hUjZZoCC5EyomfTZIYd3QBYz1YEWlKds/oREDhBkCNVKl7EqG7mPiIDfltIw3/22DzOkn/gykm8TZ2KVvUkAJ+9Vy5/H8aPg19+MTeyGz++2PKalD3abipSVuzbB7VrYzIYSF25if0XJQZ0Ul0g1LEoiXyjic5jlzNy8otcv201P9duzl13vlJw4i26xdfeVmHLd+bhK1OYu+mQzfcD8E8di4y/4OqrzbMV779vTlqVkOXq+VuBhUgIcVgv4Y034NlnoUsX+OEHv47TVZ4Uiyptjsa4KO0QL49fyNKPBxF9LpdHb3qORQ072a3pYO8kfkOLZD5audthPYmiO4Ha1KnIhr0nXH7vHH0dNu87dBDatIHDh+H222HmTM1WhLhSCSxee+01nnvuOYYOHcrbb7/t1YGJiHucXuG3bg2//QYffACPPOLHkYYOV2ZVFqUd4uDjz3L/iinsj69Ktwffp2LlCnZnE4qexNvUqUiXN1bY3TViq7iZu7M9bs8OnTxpLgS2YQM0awZr1kBsrCtvmQQxnwcW69evp2/fvsTHx3P11VcrsBDxI2cVEj/vFM8VN1wJERHmLYGVArD+Q5Bxpypl/qnTnLu0EVEH93Pg4cdImvCOyzMva3Ydo9/EtU6Pm/5QBzrWq+R2tUx7x1sMvLwO1zZJvjCDcfw4XHutOaioVAnWrYOLL7bzaAklPq28efr0afr378/EiROpWLGix4MUkZJzpULitrcnAnCi81XM2ZdT6g29Qo27VSnD4y4i6sMJANT45H3Cf9/s8mu5sxXV3XE5Ot5i0s97C6qF/rD0V+ja1RxUVK5sLl1+PqjwZ8M4CSweVd4cPHgwvXr1olu3brz88ssOjz179ixnz54t+Dwzs/h+bhHxnNPiSiYTV29cDsCoi1rw7YyNQHAlQgYajype9u5t3or5zTfw8MPkr1rNur8znOZAuLMV1d1xOTu+sJRNa2k2+nXIzoRq1WDZMmjSBAj+RFvxLrdnLGbMmEFqaipjxoxx6fgxY8aQkJBQ8FGrVi23BylSVnhy1efsirbJ4V3UO36A7IgoltRvX3C7ox4U4pjHFS/ffde8LXPdOsbd9JjT/iFgridRuHJqUYVrVbg7LpeON5kYtPYrvvjy31TKzmRb9frkr/7ZKqhwt8eJhDa3Aot9+/YxdOhQpk6dSnS0a1H0c889R0ZGRsHHvn37PBqoSKhztVlVUc6uaG/a8gMAy+q3IyuqfMHtpvMfI775ndU7j2rq2g0eV7ysXp0/nvgXAI98/ykpxw8U3HUoI4dHp6Ty3eaDVg9ZsiWdnHP5Np+/aK0Kd8fl7Pi4s1l8OPsVhv84mXCTkS+bdeOGO8eyjgQgMBvGif+5FVhs2LCBI0eO0Lp1ayIiIoiIiODHH3/k3XffJSIigvz84j/8UVFRxMfHW32IiLWSXPU5Kq4UZswv6A3ybeOrbD7+ZHYe/T/+xaUgRsw8rXiZbzTxYHRrfqrTkuhzufx3wVuEGa3/bg6Z/hvfbTZ/Hyw/FyfP5Nl8nQrly1klY7o7LsvxttQ5cZDZnz9Fjx1rORsewYgeQ3j2uqGcLRdVMNPhaY8TCW1uBRbXXHMNv//+Oxs3biz4aNu2Lf3792fjxo2Eh4c7fxKxS8lPZVNJr/ocVUjstHcTVbNOcDwmnh8vbu1wHJq6dp2n1UHX7T7OocyzjLjucU5FxtDm4J88vG621TFGE/zfNPPMhbPEyqiIMLo3TvJ4XIWPL6z937/z7edPUf/4fg7GVeb2/q8zo2XPgjoVlpmOkGgYJ17nVmARFxdH06ZNrT5iY2OpVKkSTZs29dUYywRPp8El+Hnjqq9n02QmDGhNUpGrz9v+NM9WzL/0CvLCyzkch6au3WPvPXdUIt1ygj2QUJXRXR8C4KmfvqDFwW3Fjv3XnDSniZXpmWeL/VzYG1fF2HLc36kuCTGRVt/fnk2Tef+uVlhioL6bvmfKzH9RMecUG5Mv4cZ73mRz8iVA8RmPkGgYJ17n0a4Q8S57+8gtV5CB1MdBvM9bV309myZbVV/cv+8o3d5cDcC3Ta5y6TVs7mYQu4q+584qXBY+wX7ZvDtX7k6l97ZVvDvvDXrd9y6nC+XAHM+yvfxRlK2fi8LjWrIlnW83HuR4Vi6frN7DJ6v3FNuxcX3z6ozLN7L/kcd5eL15BmXepVfw9PVPcLZclNVzF57xsCylpGfk2JxZsRTvCvSGceJdJW5C9sMPP7hcHEuKU/KTePOqLzzMQMd6lejdvDpHpswkNi+HPRWSSa1+qVtj0tS16yzv+Y0ta9CxXiWHha+schoMBp7vOYT98VWpczKd1xa9Bx7UKyz6c2FZUp2/+SDrdh9n0uo9HM/KtTqm2LLXsWNcP+KBgqDi7U79eOyGZ62CimQbMzGh0jBOvEszFn7m0X54CSm+uOpbt/s4XdcvBs7PVrjZw0FT175hORE/er7ZWGb0RTx+wzPMnDaC3n/+xB/VLmZCh9sLjk+MjSwWFFjY+rmwVU/CFtP5x4+at4XuWfsIv/MO2LMHypfH+PEntG/XnbcysjmelUviRVEkxdufibEsvRR93STVsSizFFj4mZKfxHKyGTQlFQO2O1u6e9WXsftvuu/ZCNjfDWKLpq59z5LTMGT6bxhNkFqjES91e4RXvn+fZ378nG2V67CifjsSypfDaGem0tbPhbPS3EVF5OfRb94XhI38GvLzzRU0Z88mrHlzOnrwNbmzJCShrcRLIVIySn4S8CwR0JFLVywg3GQktXpD9iTWcOkxmrouPdc3r864fhd26UxtdT1TWl5HGCbenfcGzQ9u4+SZPE5mu7bN1JXS3IVd+dcGvpv0OI+vmYkhPx/69YNff4XmzT3+mtxZEpLQphkLP3M2DQ4QZoATdqZDJXR486qvziLzWvm3Ta62e0yYwby10UJT16Xr+ubJfBB2YQnhpW6PUPfEQTrv3cTnX7/IHXeO4c+qKTYfW3ibab7RxGerd7tUmjvl+AFeWP4x3XatB+BYTDxHx75Fw8fu994XJmVeidqme0LdTYtzZQrTQPGuhCI2bdkCTZpgjIig7aDJnCifYHN5ZfxdragYG6Wpaz8r3CY9Kewcje67nfjf1nO0fAL39B3Nlmq2O4dOf6gDGdm5LuVUxOec5rGfZ3DfhnmUM+aTFxbO5Na9ea9zP8YMvJLrm+vvijjn87bpnlJgYdt3mw8WrLnaYln7XjW8q/74i2PPPw9jxkCfPix69UM1hyolhQOEkgRqC37aQp3bb6Dp4V1klYvmsRueZXn9dsWOu79TXSat3uO4gNa5XO7ZMJ/Ba7+kQs5pAJZf3JaXuz7IX5VqArpoEde5ev7WUkiAqBgbZTeoAO0OkQscnsCMRpg61fz/AQOUVFdKvNndM7F6Ne668xXe/3YMnfduYuKslxnf4XbGX34HZyMiC477duNBu0GFwWTkpj9+4KmfvqBm5j8A/Fm5DmOuvp8fL25T7PhR87bQvXGSfi7EKxRYBAjtDhFXOD2BLVsGf/8NCQnQpw9wIalOfMPbBe7apSQSW60yA28fxaglH3DXpkU8vmYmvbat4rWrBrKi3mXEx0Xb3IYak5vDLX8s574N82hwzNzw8dBFlXjzigF807QrxrDibRd00SLepsAiQGh3iDjj0gns44/NN/bvDzExpT7GssZZgbuCWhFuzAYU3n78Qo/B/FS3JS8t+4h6xw8wcdbLHLqoEnu7Xs+s3Iociq9MfE4WSaeOcvnfm+n492bK550FIDMqlgkdbmNW51s5fM75BsDVO//RbJZ4hXIsAkS+0UTnscudFklSjkXZZPn5sJekZwAaRpxl4et3YsjLg99+g5YtS3WMZdGaXcfoN3Gt0+OmP9TB7dmAwrNTcWezGLzmS+78fQkVzmQ6fNyeCslMbtObr5p158lb2nBpcjz9P/7FpddU/o04ohyLIOOLIkkSOlyp0NppzUJzUNGmjYKKUuLLJcxi+TFDriGueizMm4vxp59Yt3gNFU4cJSP6Io6XT2BT8iX8eHFrtlZJwWAwkJQQzX2dzNtVnW1pt1B/IvEGBRYBxJXSuN7KPJfg4vTEZDJxx6bvzf9/6CHfD0gA3y9h2syP6duXsL59OZl2iH7nS4M7uxCxd9FSlKfLNyKFKbAIMI6y+L2ZeS7BxdmJqfWBP7nk2N/kx5QnvF+/UhqVuNvnxZsXBu706LB3rC1K5pSSUmARgGxdpai1etnm7AR2z2/zATDc0ReUu1Rq3FnC9MWFgTvbiS3HvrVkO+NW7HT63NqBJp5Sr5AgoNbq4qg9dZWsE1z/52oAwoYMKeWRiSt9XiwXBkVnC4q1L/eAOz06wsMMdKpf2aXn1Q408ZRmLIKAN1qrKzcj+Nmbzr5nyzIijecwtW+PoU3x4kfie45mDnyxJbUkv8/uLt+IuEuBRRAoaea5cjNCh+UENm75Tiat3s2prBxuWb8AgNG1utAu7ZC+p35irxCZNy4MCivp77N2oImvaSkkCJQk89yXU7DiH0u2pPP20u2czM7jmp3rqHHqH47FxDO1Tgd9TwOQqxcG6RnZrNl1jDkbD7Bm1zGbS5ve+n12ZflGxFOasQgAzqY1PZ269MUUrPhX0e/pwA1zAfiy+bWcjYjU9zQAuXphMHrBVqsy3UVnIbz9+6w+MuIrCiz8zJVpTU+nLr09BSv+V/h72iR9Jx3//p28sHA+b90L0Pc0EDm7MLAo2vuj6I4vX/w+u9tHRrla4gothZRAvtHkdOrSEXemNT2ZulRjs9BT+Hv1wK9zAFhwaWcOxVexe5z4l6MdPY4U3fHl79/nRWmH6Dx2Of0mrmXojI30m7iWzmOXO11+KenfSQk+mrHwkKcJVJaI/+CJM7w0371pTXenLtXYLPRYvldJmUfps3UlAJ+0vcnucRIY7O3oSYwtx/GsPLuPKzwL4c/fZ0/r6ChxvGxSYOEBb/6S2WNvWtOdqUttKwsNhaefK8dGkRQfzb0/zKecMZ9fajXl9+QGBcfqexq4bF0YpGfm8OTMjU4fe+RUDr2bV/fL77OnuR0q6ld2KbBwk7d/yZwpybSmtpUFP5tXfOHnuGvjQgA+vuymgtv1PQ18RS8M1uw65tLjqsZF++332ZPcDiWOl23KsXCTO79kFo5+yZwp6bSmtpUFL3s5ONeuW0jC2Sz+TqzO0vrtCm7X9zT4WGYV7Z1aDZiXDiyzEP74ffYkt8OTv5MSOjRj4SZf/JLZUpLmRUWP7d44SdvKgoy9YDTMmM/AX81bTGd2upUpD3Xk6Omz+p4GKU9mIbyxTdSdvyee5Hb4O9FU/EuBhZt8+UtWWM2T6UyIOUH4iMUcTNvBTxlhbIuuxC+1m/JHtXp2E6CULBUa7AWj3Xauo+7JQ5yMvohP63ehs8HAjS1r+GGE4i3udCm1cHebaGHu/o3wJFdLieNlmwILN/nylwyTia671vPwxvl02JVacHN14I5Ch6VVq8eUVtcz+EQW4++5rOCPgZKlQoe9YPTB9bMBmNryOrIjo3XFFyJKq1iVJ38jPJlVUeJ42aYcCzc52pPu7JfMkVon05n09Ut8+s1/zEGFwYCpSxe+7HgTr141kA/a3cKS+u04Gx5B08O7eG3Re3wz5RmmfDSffKNJHVBDjK1gtMXBbbTbv4XcsAgmt+5t9zgJTu50KfVESf5GuJvb4cnfSQkdmrHwgLtTl4Ujflu/1Ldv/p7RSz4g+lwuxnKRhA19HP7v/1hrjOfZiWutjq2Qncntm5fy2M8zaHloO5PGD2JP1UyO9LtPVTZDiK0rPktBrHmNr+SfuEpWSX2qiCjOlLRyp7uzKp4s8UhoUGDhIW/8kkWdy2XUkg+4c/P3ABxr14lKn38CDRsCcGTjgWLPczImnontb2Fu4ysZveQDrt2xlnojn8a4fQdhSddjDAt3OG5NnQeHotPPyZlHuP7PVcCFgliWKz7l1YgrvJFQ6W5uh/qRlE0KLEqgJL9kx/an0/bx+0ja/CsmgwHTf/5Dpeefh7ALq1OOprkPx1Xm4Ztf4LGfZ/DUqqk0+OJD3miynad7PYnJYH+FS1PnwaNwMHrvivlEmIysrtOcE5c0ZsL5oEF5NeIqfyVUliTRVIKTAotSFh5moGPMWXisH/z+OyQkYPjySwzXXlvs2HYpiSTFm6vz2WQw8F6nfuytWJ3/LXiTW/9YQU65KF64djAYrK8IlCwVmJwtYfRsmkz3muUxvboEgMSRz7FqYFfCwwwqQiRuUUKllBYFFqVtxw649lrYsweSkmDxYmje3OahS7akk3Mu3+lTzm3cBaPBwLtz36D/xkWcjizPmKvvL7hfyVKBydUljPDPJsHpU3DppTQa2BfOfw/VvVbcoUq8Ulq0K8THCnf22zxnOaZOncxBRf368PPPdoMKyxT3yTP2GxQVNr/RlQy/7jEAHlk3i76bvi+4TxUZA4/LnW3PnYN33jH//8knrZbKVIRI3KVKvFIaNGPhQ4WvSFsd+JPPvxyJITebI/UbU2nlMsKTk2w+ztMS4F81v5bkU8cYtmoqry2bQJ87ribiiiuULBVg3FrC+PZbcyBauTLcfbfVsSpCJJ5QQqX4mmYsfCDfaOKdpTt49PwVafND25n85b+Jy81mba2mdO39Em0mbr5wVVqEJyXALd67/A6O9uxDWF4eVwx/hI7ROfqDEWDc6qPw5pvmG//v/yAmxuo4d/tMiFj4umaGlG0KLLxsUdohOr22jLeWbgfg0iO7+WLmSOJzz/BLraYMvO0lTkeV5+SZPOsp70JKMnVtMoRxW/uHyWzYGI4cgQEDIN95noaUHle/v3mrVsOaNRAZaQ4silARIhEJRAosvMiybp6eeRaAaqeOMumrl0g4m8WvNRpx/63/JjvywrS0CduV7ko6db03x8DNVzzOuZjy8MMP8OqrJXo+8S5Xv7+NZ35q/s+AAVCtms1jtGYuIoFGORZeUnTdPPbsGT79+j8knz7GzsSa3H/bi2RFlS/2OFtZ+862hQHFsroLMwF/VarJq72G8O+vX4eXXoKrr4bOnT3/AsVrXNn219yUSaXv55tveOIJh8+nNXMRCSSasfASq3Vzk4k3F7xJkyN/8U/5Ctx3+0tkRl9k97FFp8adTXEbgKHX1Hc4HhPwab0r+efG28FohPvug6wst74m8Q1XljDeOroaQ34+dO0KzZq59JxaMxeRQKDAwksKBwcPrp9Njx1rORsewUO3jmR/Bdu7PyxsTY07m+JOqWI/UCls3VOjoGZN2LULRoxw6THie46+vx/eeikps6cB8EufAazZdUzN40QkaGgpxEsswUHb/X8w4ofPABh9zcNsrN7Q7mOcVbpzNMW9Ztcxl8aVWL0qfPIJ9OgB48bBzTebr4LF7+x9f/986Q0MJ06wt0IS/Q5WwjhxrXp/iEjQ0IyFl7RLSaRB5DnenfsGESYjcxp1YUrL6+we72rWvr0pbmdbDQGS4qPMQcu118Ijj5hvfPhhyM5286sTXyn6/V3yxyHKvT8egMmt+xQ0lStWOEtEJEApsPCS8DADn22cQvVTR9ldMZnneg4p1q+jsJJm7Ttap7fIOWdkyZZ08yevvw7Vq5uXRF57zaXXKFw1VNPxvpdvNPHdW1O45NjfnI6M4avm3Qrus7zztnYRiYgEEoPJZCrVv1KZmZkkJCSQkZFBfHx8ab60b82eDbfcgiksjIcffpslCRcX3JWcEM3IXo2oGBvl9az9RWmHGDHrd5ulvy3PXhDAfPUV9O1rrovw++9wySUOn1etuEvXml3HONPjOq7ZtZ5JbfowqtsjNo+b/lAH9f4QkVLn6vlbORbecPRowVKD4dln+eCVIaW29a974yRemrsFKB5YFCsPfdtt0LMnLFpkLri0ZInNWRW14vaPrLQtdNu1HiMGJrfubfc49f4QkUCmpRBvePZZ+OcfaNoUXnqpVLf+rdt93H5bdYqUhzYYzAmc0dGwbBnMmFHseGd9LEDT8b7SZNYXAKyo15Y9iTXsHqfeHyISyBRYlNTKlTBpkvm/T7/Cmv2nS/Wk63aHy3r14IUXzP9/8kk4edLqOLf6WIj3ZGaSNGs6AJ+1ucHmIer9ISLBQIFFSeTmcur+hwCY1qIn92wNp9/EtXQeu7zUsvc96nD5zDPQsCEcPgz/+pfVcWrF7SdTpmA4fZrTFzdgVd2W6v0hIkFLgUUJ/Pn8y8Tt2s7R8gmM7XJvwe2luTXQow6XUVHw/vvm/7//PqSmFtylVtx+YDLBhAkAXPTEY0y4u416f4hI0FLypofyDx+h5rj/ATC2y31kxMQV3FcsadKHV5iWbaeDpqQW6x/i8Cq3a1fo1w+mTzcvifzwAxgMLvWxcFTUSzzw88+Qlgbly8Pdd9OzQgX1/hCRoKUZCw/989RzXHT2DL9Xq8fXza4pdn9p5iJ43OFy7FhMMTGwciXr/jexoJqnWnGXsvOzFfTrBxUqAOr9ISLBSzMWbso3mvj9+zU0mz4ZgFe6PoDJYD8+K61cBE86XC7KiOBAx9t4YPkXJL38b7qnVyGxUjwv9mnMhAGti9WxSHKxjkW+0aSrbVcdPWquLwLw6KP+HYuIiBcosHCDpWjU6E+eI9yYz+IGHVhbu7nDx5RmLoLlKtcVlloV0S1upNe6BdTOOMz9v87hgw63F9SqWDW8q9sBggpruWnSJMjNhbZtzR8OKGATkWDg1lLImDFjuOyyy4iLi6Nq1arcdNNNbNu2zVdjCyiWE3HSlo1027Wec4YwXrtqoN3jA3lrYL7RxEtzzbUqsiOjGdvlPgAGr/mSyqdPAOb8EMCt6XjLe1R0u6r6XNhhNMKHH5r/72S2YlHaITqPXU6/iWsZOmNjqe8+EhFxlVuBxY8//sjgwYNZu3YtS5YsIS8vj2uvvZasrCxfjS8gFC4a9fRPnwPwdbNu7LZTxCjQcxHGLd9hVVTr2yZXsTH5Ei7Kzeapn77wKD9EhbU8sHSpuXdLQgLceafdwxSwiUgwcSuwWLRoEffddx9NmjShRYsWfPbZZ/z9999s2LDBV+MLCJaiUR33bqLT3s3khkXw3uX2TwQJMeV4olsDujdOKsVRumZR2iHeWrrD6jaTIYz/XGOux9F38xKaHN4FuJcfosJaHvjgA/O/99wDsbE2D1HAJiLBpkS7QjIyMgBITLQ/3X/27FkyMzOtPoLNkVM5YDLx9EpzyeVpLXtyIKFqsePKR5pbXJ/MzuOtpTsCbqracpKyJbVGI+Y06kIYJkYumwgmk1v5ISqs5bp8o4kNq9Mwzp1r/vyhh+0eq4BNRIKNx4GF0WjkiSeeoFOnTjRt2tTucWPGjCEhIaHgo1atWp6+pN9UjYvm8r2baHPwT3IiIhnfsa/N487k5lt9HmhT1c5OUmOvupeciEg67EvjjoOpVvkhzlqoq7CWayy5EiuHjyEsP59fajWl8/zDdn9GFLCJSLDxOLAYPHgwaWlpzLDRyKqw5557joyMjIKPffv2efqSftMuJZGn1pm3BE5v0YN/LnItITPQpqqdnXwOxldl4mU3A/Dc8k/NuxVwLXHQowqgZYwlV+LIiSzu3LQYgKktr3MYgCpgE5Fg41FgMWTIEObPn8+KFSuoWbOmw2OjoqKIj4+3+gg24WvX0Gb3JnLDIpjY7ha3HhtIU9WunHwmdLiNI7EVqXBwL+NufYIx321xKXHQUgEUVFirqHyjidU7jjLim98xAdfsXEfy6WMcLZ/AoksudxiAKmATkWDjVmBhMpkYMmQIs2fPZvny5aSkpPhqXIHllVcAOHzT7ZiKLOVUiCnn0lMEwlS1s5MUwJnIGP57xd0A3LfsC2Yu3mQ3cdAEDP96MxNX/sXs3w6QEBPJ+Ls8qAAawiyzPf0/+YWT2XkA9N+4EICvmnUnN8L882MvAFXAJiLBxq0CWYMHD2batGnMmTOHuLg40tPTAUhISCAmJsYnA/S7TZvgu+8gLIxaY//DqovrWRUpMppM9P/4F6dPEwhT1Y76ihT2dbNruC91Ho2P7Gbo6umM6vaI3efMyDnHK99tLfg8OSGakb0aUTE2qswXcrIsfRR+n2ufOESX3akYMTCtZc9ij7EVgFpKtntaCVVEpDS5FVhMON/T4KqrrrK6fdKkSdx3333eGpPfFK5sWDk2CgxQ+4XR1AKMt91OWP36hINVdct8oymomnbZO0kVZgwLZ3TXB5k+4wXuTl3AlFbXs6uSa0m3hzJyGDztNyYMaM2NLW3X+SgL7G0TvWvTIgBWprRmX4Xi25HtBaCelGwXEfEHtwILk8n/CYi+YqsUdbVTR1m18FsAHqp0BbenHSp2dehxd1E/KnySWph2iM/X7C12zJo6LVhSvz3dd/7Ccys+5cHbXnTrNUqjs2sgs7UDJ+pcLrdvXgLA1FbXWd3nSgDqTsl2ERF/UXdT7Fc2vCd1AeWM+ayr2Zjl8XXtZu573F3UjywnqescjO3Vq+8nLyycbrvW02nPRpef25IvsPZ8t9SyyNaSRq8/f6JSdiYH4qqwvN5lBbcHagAqIuKJMt+EzN6UdUxuTkGS3ceX3Vxw/4hvficuuhwdLrbunRGsU9WWhE5byyK7E2vwRate3L9hLv9a/jG97nsHY1i4y889eFoqr93aLCjfl5KytaRxT+oCwDxbkV/ofVSuhIiEkjIfWNgrGnVb2lIq5JxmT4VkltZvV3D7yew8+n/8i82OncE4VW1Zynl0SqrN+9/p1I9b/lhOo3/20HfzEmbYSDi052R2Ho9OSaVC+XKcPJNXcHtZ6HZqCdgsuTctDm6j5aHtnA2PYGbzawFIiIng/f5tigWpIiLBrMwvhdjcBmoyFVxdftamj82r9ECrqlkSPZsm8/5drbB1bsuIieOdTv0AeGbVFJLD8oof5EThoAJC672zp+g20Xt+M/88zb/0Co7FVjDfbjBwKidPQYWIhJQyH1jYmrLu+PdmGhzbR1a5aL5pdo3NxwVaVU1X2SvNfX3z6ozr19rmY6a2up7dFatTKeskU9OXOKyD4Ypgfe/cZcm9qWvKovfWnwD4onXvgvszzuSFfIAlImVPmV8KKTplDRfWwmc17cqpKNtdJ8G6qFEgLoEU3j5bNS6aE1m5jF5gvfOl8LLE9c2T+SCs+FbUSolxHB89hpQh93LxFx/x+Td38OwfeQ77jjhT9L0rOtZQycPo3jiJXRu/Jyo/j01JDdiYfEnBfSbMsxllfQeNiISWMh9YFN0uWi3zKN13rAXg81a9XHqOQKiqWZSt7bO2WJYlLLtXHCahLv4a5s3jindGser7Jazbc4JVO/5h/A+7PB7nkVM5NscaLHkYzgKidTuOcONacxfTz1v3BoN18BDowamIiLvKfGAB1kWj7vxpEREmI2trNWVHlTouPT4QqmoWZqvioz22rprtJqG+8w4sWQLLlxP+9Vd0vOMO2qUkMuu3A3YLhDmz5+gZ3l66vdhjiwY8gciVgCjsu/nUzPyH4zHxzG90hd3nCsTgVETEE2U+x8KiZ9NkVj11JYN2rgCgwlND+eL+dg57gQRiAyh722cdcblRWkoKPP+8+f9PPAEnTjjsZeGIAUiKj2L6ur/t9iKBwM3DsFf7pGhiasNvvgBgZvNrORsRaff5Ai04FRHxlAKLQsIXLSTyyGGoUoVLB93DFZdU4bVbm2EgeBpA2ds+6wqXrpqfeQYuvRTS02HYMMB+gTBn+rWrTXqm/dcMpM6whTkK3qwCoj+2UGH1j+QbwopV2rQIxOBURKQkFFgUNnGi+d/77oNI89VlsFXVLMmUuktXzdHR8Mkn5lyBzz6DxYuB8zM+w7sy9YH2Tju+hhlg/F2tqVvZfmJsYYG2TOAseLMERP+8+l8AjnbpxoGEakETnIqIlIRyLCwOHDB3MQV44AGru4KpqqYnU+puN0q7/HJ47DF49114+GHYvBkSEggPMxAWZihoD26P0QQVY+0vCxQVaMsErgQ6Fc9kUHnWdACqvfgcEyo3VHdSESkTFFhYTJoERiNceSU0bFjs7mCpqmlr+6wjHl81v/oqzJ8Pf/0FjzwC06eDweDy7MKRUzn0bl49qDrDWrgS6Az47TsicnKgTRvo0oWeBkPQBKciIiWhpRAwBxSffGL+/4MP+ncsJeRuMqXHSzqxsTBtGkREwMyZ5sAM12cXqsZFOxxrIC8TWII3e6OKOpfLwPOVNnnqqYItppbg9MaWNehYT2W8RSQ0GUyl3As9MzOThIQEMjIyiI+PL82Xtm/FCujaFeLjzUmJMTEFdwVr4SZ7WyFH9mpExdgo7309r70Gzz0H5cvDunXkN2pM57HLnc5CrBreteB1g7GOhWVXCGD1dRqAOzYt5rVF70Ht2rBzJ5RznHMiIhIMXD1/l+nAwhI01Bj2f9Se+yXGBx8kzJLASXCe8AorlaDIaIQePWDpUvN21F9+YdHhc3ZPuoDNGZJgDOBs/XzUiCvH9x8PInbPX/C//xXsnBERCXYKLJywnBRO/nOS9ePv5qLcbB555G1uHtKXnk2T7RaZcnRyLLOOHYP27WHXLujUCZYtY9GO40EdlLmqaEDUft0Swu7qB4mJsGcPxMX5e4giIl7h6vk7pJI3Xb3qLRw03Lz9Zy7KzWZ3xWS+T6jH91NSGX9XK0Yv2Gq3TkFZ7u9g8z2uVMmcyNmhA6xeDf3703P6dLo37hp0sxDuskrqNRrh5lfN/x86VEGFiJRJIRNYuLpskXvOyPOz0wqChlvTlgEwq0lXTAYDBuBfc9I4nmV/y2RZ7e/g+D2+FL7+Gnr1gm++gf79CZ86NSDen1JbZpk/H37/3RxQPPaY959fRCQIhERgYW/Zomi/iUVph3h+9u8FQUNy5j9cvnczALObdgXMQYOjoKKwQCvc5EsuvcfdusGsWXDLLfDVV5CfD1OmWCXDlrZSy5MxmeDll83/HzIEKlb03nOLiASRoN9u6mp55e82m0+MhYOGPltXEoaJtbWasj+hmtuvHWiFm3zF5RLWRtOFGYvISHOQ0bUrHDli8znX7DrGnI0HWLPrmE/6gbjaz8NdNsc+fz6sX2/eHfPkk94YvohIUAr6GQtXyyv/a05asRNj7z9/AmBu4y7FHpcYG8mJrNygKtzkK66+xwVLQ717w/ffw803w9q15tyL2bOhRQvA9ixChZhyDOxUlyFdG3hlmcJZMORpnoytsVePi2Tx5OHEATz+OFSpUsLRi4gEr6CfsXB1OeJ4Vq7V53VOHKR5+k7OGcJYeMnlBbdbmkK9fGPTgs8LC+TCTb7iTjXNAl26wJo1cPHFsHs3dOwIU6bYnUU4mZ3HW0t30OblJR7PJBTmTjDkKntjb/vLEuJ2bOVsbBzf9ezv0QxMaczgiIiUhqCfsfB0OaL3VvNsxc91WnCifILVfZb19wlhrdXfAfeqaVpp2NC8PNC/PyxaBHffzekONxLR+T7ywm0XjTp5Js8qL8ZTHgVDDtibAYnIP8eTq6YA8G7rmxi/cC+w1608jmCvlyIiUljQz1g4K69sABJji5/ELMsg8xpdWXBbpdhIqxOapWPn9Ic68M6dLZn+UAdWDe9a5v7Yu/Ie2239nZhozj/4978BuG3tHGZMe45qp47afT0ThXI2PORxMGSHvRmQOzctJuXEIY6WT2BS2xsKbnc1j8NXeSAiIv4S9IGFK/0mXr6xqdWJsf7Rv2n0zx5ywyJYfElHwBx8rHnummJBg/o7uPYeO1waCg+HUaNY+85nZETF0ubgn8z/7Ak6/L3Z7mu6u0xRVImCIRtszWzE55xm2KqpALzd6S7ORF7Y/VIsqdUGt5JiRUSCRNAHFmCeWZgwoDVJCdZXn5YGW9c3r251YuxzfhlkZUorTkVfhAF49eZmREaExNvhE87eY1dmcUy9etPn3rfZWqUuVc6cZMqMf/HgulnmrZo2lGQ7r7cbnNma2Ri6ejqJ2Zlsq1yb6S17FrvfWR6HL/JARET8LehzLCx6Nk122JbacmIcNfcPq2WQpPONuRJiIpmz8UDIVoj0BmfvsTPtUhLJq5vCzXf/l1cXj+eWP1bwrxWf0vLgdoZf9zhZUeWtji/pdt6C77kX8mSKtqO/+Nh+7kmdD8Dorg+RHxZu97H2AiRv54GIiASCkAksoEh5ZRt6Nk2me2464S/sJz8qirteHkIPQxSjFyhxzlXO3mNnj32xT2MenZLKsF7D+K16Q/69bCK9t62i4dG9PHrz8+yqVMur23lLGgwVHfugKakYTCb+s2QC5Yz5LKnfjlUprRw+1l6A5O08EBGRQBDyc/9Ft/EZvpwJQHivXpwIj2LwNCXOlaaeTZP5YEBrKsRG8kXr3tzR7zXSL0qkwbF9fPv5MHpu+xmwXqYo6VZMR3ky7jy3ZQbk/l0r6bx3E9kRUYzu+pDD106Kj7IbIHk7D0REJBCEdHfTYtv4TCZWT3yIGifSyZ8xk85/VbK7xm25al41vKuWRXwg32hi3PKdTFq9m3L/HGHc3LG035cGwJ7+D1B34nsQE+PTrZjOCnUBxWc6jv6DqVEjDMeP88fQ51na+z7eXrodwGYSZoXy5XjtlmZ2x2rZFVL08eqiKyKBpsy3TbfV26LFwW3M+eIpsspF89mstbyxar/T55n+UIeAaKQVKoo2BGtTpyIb9p7gn+OnaPvhG1T/5H3zgU2asGrUO9y9Pscnrevt9T6xiIwIIzI8jNNnzxXclpwQzayf3iN54Rxo2dJcoyMigkVphxgx63dOnineY8aVsaqOhYgEgzLZNt3C3jY+S9LmsvrtmLjhsEvPpcQ573F0Ar3hsrpw2Xi4tTcMHAh//EG7O67j/ivv4dPLbsRkuLBqV9LW9Y62eVrknjOSe85odVuHnxeSvHAOxvBwwj76CCLMvz7dGyfx0twtQPHAwpWxeisPREQkEIRkjoXNbXwmE9dtWw3A/Euv4GS2ax1MlTjnHS4XgrruOti8meNdexCZn8fIFZ8w+csXScg+ZfW4kmzFdLbN05ZaJ9P5z/fm2ZRPrhpAfpu2Vs+XnlmybaOqlyIioSIkAwtbswxNjvxFzcx/OFMuih9TWgNQPjJciXOlwO1CUFWr8tN/P+b5HoPJjojiyj2/MefzYdQ/+nexx3syo+TuY8rl5/H2vP8Sl5vN+hqNea31LVZBgraNiohcEJKBha1Zhu471gLwU91WnC0XBcCZ3PyCqerCymKjMV/ypBBU1fgYprW8jpvv/i/746tS9+QhZn/xFF13rrN6rCczSu4+5qWlH9Lm4J9kRpbnyT5PkR8WbhUkaNuoiMgFIRlYWLbxFdZ9xy8ALGnQoeA2A+as/WrxnleTFOc8uaK3fA+3VU3hhnvf4pdaTYnLzebjb0bz6NqvwWQizAAninStdcWJrLO4Gi8O+O07+m9chBEDQ294hv0J1QDrIEHbRkVELgjJwKJwOWeAGhlHaHLkL/INYSyrd1nB7SbM3TT/d3uLMt9ozJc8uaIv/D08Xj6BAXeMZmrLnoRhYsSPn/HW/P9RLi+XwdPs1xuxVaNiUdohBk/7DVdKYXT5awMvLv0QgLFX3cuKepfZDBK8XT5cRCSYheSuEDBn2j/QqS6frN5Dt53m2YpfazQq1iId4GjWWW5sWaO0h1hmFC2HXZS9Sps9myYz/q5WDJn+G3nh5Xjh2sH8WaUuLy79iJu3/EDdE4d45JYXbO64sLUDJSk+ipxzRoe7QSw67t3Mh7NfoZwxn1lNrubDdrc6DBK8WT5cRCSYhWxgAdCtcRKfrN5TkF+xpEF7m8dp7du3rMphY7sQlL0r+oqxURdmFwwGvmjdm12JNXl/zmu0OrSNOZOf5KFbR7J2VwvCwgwcOZXD7n+yeHvZjmLPlZ551qXxttuXxsff/Ifoc7ksqd+eZ68bCgaD0yBB20ZFREI8sGiXkkiDyHMFFR0L51eA/Stl8T5Pr+ht5Wf8XLclN97zJp98/R/qH9/PV1OH82LWYb6s16nE47zxjxW8vvAdovLPsbJuK0b2+xd3t61LzYrlSbwoioSYSPKNJrvBQkl6qYiIhIKQDizCwwz8N3Y/5Yz5bK9Um70Vqxfcp7Xv0ufqFX3h6pxHT9meZdhbsTo33/M/3p37Olf/tYHXvx5D22bd+M81D3O6SJdUV5TLz2Po6ukMWfMlAAe79iTqnY/4tzGiWJO6wmW/9bMjImItZEt6F7jjDvjySyZ36ceLHfoX3KySyYHJVm5E0eWTwsKM+Tz10xQGrf2aMEzsj6/Kq1ffz3cNO4HBtZN+k8O7eOO7t2l8ZDcAxqefJmzsWBZtOeyw7LezPiAiIqGkzPcKASA3FypXhlOnyP95DeuqNtDadwBz1r/Dkcv2pfHmgreolWEu1b4xuQGftr2J7xu0J6ecjRwak4nWB/7kkXXf0H3HL4Rh4nhMPH//Zywtn36UfKOJzmOXO63QaUCNwkSkbFBgAfD999CjByQnw/79EBaSu2tDgqsn8sIqxJSzKs1ePjebh9bN5uF1s4jNMz/P6cgYfq3RmF2VanI8Jp6LcrOpm3WUdns2Uen0iYLHft/8aiLefYeuXZoBsGbXMfpNXOvSOJLVBVdEyoAy3YQMzCeqfz6fSRJwuEt3KmMg3N+DErvc6d9RIaYc4/uby7L3//iXgtvPRMbwTue7mNrqOu7ZMJ+btvxA7YzDXLV7A1ft3lDsefKjY9jf4wZODBrKNd07WAUG7pTftlQNLZq0WbSTq2bJRKQsCMnAYlHaIUbN/YNv5s4FYPi5FLaNXa6cigDmzon8ZHYeYQaD3foYR2Mr8uaVd/PmFQNonr6Dxof/ot7x/cSfPUO75nVJubQ2dO5MeIcO1ImKoo6N13B3C3LR8asVuoiUVSEXWFjW6Zuk76T6qaNklYtmTZ0W5J7voqn18MDkyYncUX0MAAwGNidfwubkSwB4/65WpDSvXvQomyxBi6uzKIXHby9XJF0/gyJSBoRU0kHhLppdd60HYGVKa85GRNruoikBw1Z/F0csJ3JLfYwkB49NTojmgwGtud7FoAKKl4W3p2iJb7c7uYqIhJiQmrEovE7f5S/zmvqKi9sW3F+4i6aKGAUWy4n80SmpDo+zVdSsaH2MyrFRYICjp8+WKLehZ9NkPhjQmhGzfufkmbxi99uqheJOJ1f9DIpIKAqpwMKyzp2QfYqWh7YD5hkLe8dJYPHkRG7hq4qXlqBl3PKdTFq922oXiq2qoZ50chURCSUhFVhYpsc779lIuMnIn5XrkB5f2e5xEnjcPZGXhvAwA0O7NWBI1/pOd3l40slVRCSUhFRgYVmn73J+a+GPF7exul+9QYKDOyfy0h6Xs1kRTzu5ioiEipBK3gwPM/Bi70Z02W1ep/+x0DKIeoMEH8uJ/MaWNehYr1JQfN8KJ30WHa1+BkWkLPAosBg/fjx169YlOjqa9u3bs27dOm+Py2M9TUepdvo42eWi+bVmk4LbkxKitc1PSoW9nSr6GRSRssDtpZCZM2cybNgwPvjgA9q3b8/bb79Njx492LZtG1WrVvXFGN2zaBEA0dd2Y/KgKwJmGl3KFlc7uYqIhBq3e4W0b9+eyy67jHHjxgFgNBqpVasWjz32GCNGjHD6eJ/3Crn6avjhBxg3DgYP9v7zi4iIlEGunr/dWgrJzc1lw4YNdOvW7cIThIXRrVs31qxZY/MxZ8+eJTMz0+rDZ06dglWrzP/v2dN3ryMiIiI2uRVYHD16lPz8fKpVq2Z1e7Vq1UhPT7f5mDFjxpCQkFDwUatWLc9H68zy5XDuHNSvD/Xq+e51JCjlG02s2XWMORsPsGbXMVW/FBHxAZ9vN33uuecYNmxYweeZmZm+Cy7O51dotkKKUlMwEZHS4daMReXKlQkPD+fw4cNWtx8+fJikpCSbj4mKiiI+Pt7qwydMJgUWYpOlKVjRUtuWpmCL0g75aWQiIqHHrcAiMjKSNm3asGzZsoLbjEYjy5Yto2PHjl4fnFu2b4c9eyAyEq66yr9jkYChpmAiIqXL7ToWw4YNY+LEiUyePJmtW7cyaNAgsrKyGDhwoC/G5zrLbMWVV0JsrH/HIgHDnaZgIiJScm7nWNxxxx38888//Pvf/yY9PZ2WLVuyaNGiYgmdpU7LIGKDmoKJiJQuj5I3hwwZwpAhQ7w9Fs9lZ5trV4ACizIi32hyqfiUmoKJiJSu0GhCFhUFq1ebg4vGjf09GvExd3Z4qCmYiEjpCo0mZGFh0Lo1DBsGBpVMDmX2dngcysjh0SmpfLf5oNXtagomIlK6QiOwkDLB0Q4PiyHTf+O7zdbbR9UUTESk9ITGUoiUCc52eAAYTfB/01L5IMw6YFBTMBGR0qHAQoKGOzs3Rs3bQvfGSVaBQ3iYgY71KvliaCIicp6WQiRouLNzQ7UpRET8Q4GFBA3LDg9XqTaFiEjpU2AhQaPwDg9XqDaFiEjpU2AhQaVn02Tev6sVjnIuDZjrWqg2hYhI6VNgIUHn+ubVGdevtc37VJtCRMS/FFhIULq+eTIfDGhdLOdCtSlERPxL200laKk2hYhI4FFgIUFNtSlERAKLlkJERETEa0JixsLVFtoiIiLiW0EfWLjTQltERER8K6iXQuy10E7PyGHQlFQWpR2y80gRERHxhaANLBy10LbcNmreFvKNjppsi4iIiDcFbWDhrIW2CTWiEhERKW1BG1i42mBKjahERERKT9AGFq42mFIjKhERkdITtIGFpYW2vU2lakQlIiJS+oI2sCjcQrtocKFGVCIiIv4RtIEFmHtFTBjQmiQ1ohIREQkIQV8gS42oREREAkfQBxagRlQiIiKBIqiXQkRERCSwKLAQERERr1FgISIiIl6jwEJERES8RoGFiIiIeI0CCxEREfEaBRYiIiLiNQosRERExGsUWIiIiIjXlHrlTZPJBEBmZmZpv7SIiIh4yHLetpzH7Sn1wOLUqVMA1KpVq7RfWkREREro1KlTJCQk2L3fYHIWeniZ0Wjk4MGDxMXFYTB4r1FYZmYmtWrVYt++fcTHx3vteQOVvt7QV9a+Zn29oU1fb/AzmUycOnWK6tWrExZmP5Oi1GcswsLCqFmzps+ePz4+PmS+ia7Q1xv6ytrXrK83tOnrDW6OZioslLwpIiIiXqPAQkRERLwmZAKLqKgoXnzxRaKiovw9lFKhrzf0lbWvWV9vaNPXW3aUevKmiIiIhK6QmbEQERER/1NgISIiIl6jwEJERES8RoGFiIiIeE3IBBbjx4+nbt26REdH0759e9atW+fvIfnEmDFjuOyyy4iLi6Nq1arcdNNNbNu2zd/DKjWvvfYaBoOBJ554wt9D8ZkDBw4wYMAAKlWqRExMDM2aNePXX3/197B8Ij8/n5EjR5KSkkJMTAz16tVj9OjRTnsRBIuVK1fSp08fqlevjsFg4Ntvv7W632Qy8e9//5vk5GRiYmLo1q0bO3bs8M9gvcTR15yXl8fw4cNp1qwZsbGxVK9enXvuuYeDBw/6b8Al5Ox7XNijjz6KwWDg7bffLrXx+UNIBBYzZ85k2LBhvPjii6SmptKiRQt69OjBkSNH/D00r/vxxx8ZPHgwa9euZcmSJeTl5XHttdeSlZXl76H53Pr16/nwww9p3ry5v4fiMydOnKBTp06UK1eOhQsXsmXLFv73v/9RsWJFfw/NJ8aOHcuECRMYN24cW7duZezYsbz++uu89957/h6aV2RlZdGiRQvGjx9v8/7XX3+dd999lw8++IBffvmF2NhYevToQU5OTimP1Hscfc1nzpwhNTWVkSNHkpqayqxZs9i2bRs33HCDH0bqHc6+xxazZ89m7dq1VK9evZRG5kemENCuXTvT4MGDCz7Pz883Va9e3TRmzBg/jqp0HDlyxASYfvzxR38PxadOnTplatCggWnJkiWmLl26mIYOHervIfnE8OHDTZ07d/b3MEpNr169TPfff7/Vbbfccoupf//+fhqR7wCm2bNnF3xuNBpNSUlJpjfeeKPgtpMnT5qioqJM06dP98MIva/o12zLunXrTIBp7969pTMoH7L39e7fv99Uo0YNU1pamqlOnTqmt956q9THVpqCfsYiNzeXDRs20K1bt4LbwsLC6NatG2vWrPHjyEpHRkYGAImJiX4eiW8NHjyYXr16WX2fQ9HcuXNp27Ytt99+O1WrVqVVq1ZMnDjR38Pymcsvv5xly5axfft2ADZt2sSqVau47rrr/Dwy39u9ezfp6elWP9MJCQm0b9++TPztssjIyMBgMFChQgV/D8UnjEYjd999N8888wxNmjTx93BKRak3IfO2o0ePkp+fT7Vq1axur1atGn/++aefRlU6jEYjTzzxBJ06daJp06b+Ho7PzJgxg9TUVNavX+/vofjcX3/9xYQJExg2bBjPP/8869ev5/HHHycyMpJ7773X38PzuhEjRpCZmcmll15KeHg4+fn5vPLKK/Tv39/fQ/O59PR0AJt/uyz3hbqcnByGDx9Ov379QqpRV2Fjx44lIiKCxx9/3N9DKTVBH1iUZYMHDyYtLY1Vq1b5eyg+s2/fPoYOHcqSJUuIjo7293B8zmg00rZtW1599VUAWrVqRVpaGh988EFIBhZffvklU6dOZdq0aTRp0oSNGzfyxBNPUL169ZD8euWCvLw8+vbti8lkYsKECf4ejk9s2LCBd955h9TUVAwGg7+HU2qCfimkcuXKhIeHc/jwYavbDx8+TFJSkp9G5XtDhgxh/vz5rFixwqdt6P1tw4YNHDlyhNatWxMREUFERAQ//vgj7777LhEREeTn5/t7iF6VnJxM48aNrW5r1KgRf//9t59G5FvPPPMMI0aM4M4776RZs2bcfffdPPnkk4wZM8bfQ/M5y9+nsva3Cy4EFXv37mXJkiUhO1vx008/ceTIEWrXrl3w92vv3r089dRT1K1b19/D85mgDywiIyNp06YNy5YtK7jNaDSybNkyOnbs6MeR+YbJZGLIkCHMnj2b5cuXk5KS4u8h+dQ111zD77//zsaNGws+2rZtS//+/dm4cSPh4eH+HqJXderUqdj24e3bt1OnTh0/jci3zpw5Q1iY9Z+h8PBwjEajn0ZUelJSUkhKSrL625WZmckvv/wSkn+7LCxBxY4dO1i6dCmVKlXy95B85u6772bz5s1Wf7+qV6/OM888w+LFi/09PJ8JiaWQYcOGce+999K2bVvatWvH22+/TVZWFgMHDvT30Lxu8ODBTJs2jTlz5hAXF1ewFpuQkEBMTIyfR+d9cXFxxfJHYmNjqVSpUkjmlTz55JNcfvnlvPrqq/Tt25d169bx0Ucf8dFHH/l7aD7Rp08fXnnlFWrXrk2TJk347bffePPNN7n//vv9PTSvOH36NDt37iz4fPfu3WzcuJHExERq167NE088wcsvv0yDBg1ISUlh5MiRVK9enZtuusl/gy4hR19zcnIyt912G6mpqcyfP5/8/PyCv2GJiYlERkb6a9gec/Y9Lho4lStXjqSkJBo2bFjaQy09/t6W4i3vvfeeqXbt2qbIyEhTu3btTGvXrvX3kHwCsPkxadIkfw+t1ITydlOTyWSaN2+eqWnTpqaoqCjTpZdeavroo4/8PSSfyczMNA0dOtRUu3ZtU3R0tOniiy82vfDCC6azZ8/6e2hesWLFCpu/r/fee6/JZDJvOR05cqSpWrVqpqioKNM111xj2rZtm38HXUKOvubdu3fb/Ru2YsUKfw/dI86+x0WVhe2mapsuIiIiXhP0ORYiIiISOBRYiIiIiNcosBARERGvUWAhIiIiXqPAQkRERLxGgYWIiIh4jQILERER8RoFFiIiIuI1CixERETEaxRYiIiIiNcosBARERGvUWAhIiIiXvP/lM6Mzz/pUS4AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "np.set_printoptions(formatter={'float': lambda x: \"{0:0.3f}\".format(x)})\n", + "def noisy_1d(x):\n", + " y = np.sin(x)\n", + " y_err = np.random.normal(y,0.5)\n", + " return y + y_err + 0.5 * x\n", + "\n", + "x_train = np.linspace(0,15,200)\n", + "y_train = noisy_1d(x_train)\n", + "\n", + "x_test = np.linspace(0,15,200)\n", + "y_test = LOESSRegression().fit(x_train, y_train).predict(x_test)\n", + "\n", + "plt.scatter(x_train,y_train)\n", + "plt.plot(x_test,y_test,c='r')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Weight function" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAnYAAAHVCAYAAAB8NLYkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAA9hAAAPYQGoP6dpAABqxklEQVR4nO3deVhUZf8G8PvMADPIKoIggoCKuIOiIlYuSVGaueXW4r5UmhG99gut1HrLrFwq7VXrVdtdcqvcUnKpJE0QU9wVEFEQRBj2Zeb5/UHM2wQog8CZGe7PdZ1L58xzzvmeBxhuzvIcSQghQERERERmTyF3AURERERUNxjsiIiIiCwEgx0RERGRhWCwIyIiIrIQDHZEREREFoLBjoiIiMhCMNgRERERWQgGOyIiIiILwWBHREREZCEY7IgIALB+/XpIkoSkpCSjl92zZw+CgoKgVqshSRKys7PrvL7GwtfXFxMnTqy39ffv3x+dO3e+a7ukpCRIkoT169fXWy1EVPcY7Ijonty6dQujR4+Gra0tVq5ciS+//BJ2dnZ45513sH37drnLk82ZM2ewYMGCWgVlIqLaspK7ACIyb3/88Qdyc3Px1ltvISwsTD//nXfewRNPPIFhw4bJV5yMzpw5g4ULF6J///7w9fWt8XLnz5+HQiH/39w+Pj4oLCyEtbW13KUQkRHk//QgIrN28+ZNAICzs7O8hZgxIQQKCwsBACqVyiTClCRJUKvVUCqVcpdCREZgsCOiau3evRsPPPAA7Ozs4ODggMGDByMhIUH/fv/+/TFhwgQAQM+ePSFJEiZOnAhJkpCfn4/PP/8ckiTp59dUfn4+Xn75ZXh7e0OlUiEgIAAffPABhBAG7SRJwqxZs/D1118jICAAarUawcHBOHz4cKV1pqamYvLkyXB3d4dKpUKnTp2wdu1agzYHDx6EJEnYtGkT3n77bXh5eUGtVmPgwIG4dOlSjetfv349Ro0aBQAYMGCAvg8OHjwIoPw6usceewx79+5Fjx49YGtri9WrV+vf+2dfZWdn46WXXoKvry9UKhW8vLwwfvx4ZGZm6rdX1fWRFftTsd2/i42NRZ8+fWBraws/Pz+sWrXK4P3qrrE7d+4cRo8eDTc3N9ja2iIgIADz5s2rcd8QUf3iqVgiqtKXX36JCRMmIDw8HIsXL0ZBQQH+85//4P7778eJEyfg6+uLefPmISAgAGvWrMGbb74JPz8/tGnTBmFhYZg6dSp69eqF6dOnAwDatGlTo+0KIfD444/jwIEDmDJlCoKCgrB3717MmTMHqampWLZsmUH7Q4cOYePGjZg9ezZUKhU++eQTPPLIIzh27Jj+JoH09HT07t1bHwTd3Nywe/duTJkyBRqNBhEREQbrfPfdd6FQKPCvf/0LOTk5eO+99/DUU0/h6NGjNdqHvn37Yvbs2fjoo48wd+5cdOjQAQD0/wLlp1zHjRuHGTNmYNq0aQgICKhyXXl5eXjggQdw9uxZTJ48Gd27d0dmZia+//57XLt2Da6urjWq6e9u376NQYMGYfTo0Rg3bhw2bdqE5557DjY2Npg8eXK1y/3555944IEHYG1tjenTp8PX1xeXL1/GDz/8gLffftvoOoioHggiIiHEunXrBACRmJgocnNzhbOzs5g2bZpBm7S0NOHk5GQwv2K5P/74w6CtnZ2dmDBhgtF1bN++XQAQ//73vw3mP/HEE0KSJHHp0iX9PAACgDh+/Lh+XnJyslCr1WL48OH6eVOmTBEtWrQQmZmZBuscO3ascHJyEgUFBUIIIQ4cOCAAiA4dOoji4mJ9uw8//FAAEKdOnarxfmzevFkAEAcOHKj0no+PjwAg9uzZU+V7f++3N954QwAQW7durdRWp9MJIQy/dn9XsT9/r6Ffv34CgFiyZIl+XnFxsQgKChLNmzcXJSUlQgghEhMTBQCxbt06fbu+ffsKBwcHkZycXGUdRCQ/noolokr27duH7OxsjBs3DpmZmfpJqVQiJCQEBw4cqLdt79q1C0qlErNnzzaY//LLL0MIgd27dxvMDw0NRXBwsP51q1atMHToUOzduxdarRZCCGzZsgVDhgyBEMJgf8LDw5GTk4O4uDiDdU6aNAk2Njb61w888AAA4MqVK3W2n35+fggPD79ruy1btiAwMBDDhw+v9J4kSbXatpWVFWbMmKF/bWNjgxkzZuDmzZuIjY2tcpmMjAwcPnwYkydPRqtWreqkDiKqezwVS0SVXLx4EQDw4IMPVvm+o6NjvW07OTkZnp6ecHBwMJhfcRozOTnZYL6/v3+ldbRr1w4FBQXIyMiAQqFAdnY21qxZgzVr1lS5zYobQCr8M7g0bdoUQPkpzLri5+dXo3aXL1/GyJEj62y7AODp6Qk7OzuDee3atQNQfm1d7969Ky1TEWprMgYeEcmHwY6IKtHpdADKr7Pz8PCo9L6Vlfl8dFTsy9NPP62/0eOfunbtavC6ujtBxT9u3rgXtra2dbau6o6YabXaOtsGEZkH8/l0JqIGU3GjQ/PmzQ3GpjNGbU/P+fj4YP/+/cjNzTU4anfu3Dn9+39XcXTx7y5cuIAmTZrAzc0NAODg4ACtVlvrfamNujo92aZNG5w+ffqObSqOKP7ziR//PLpZ4fr168jPzzc4anfhwgUAqHbMvdatWwPAXWshInnxGjsiqiQ8PByOjo545513UFpaWun9jIyMu67Dzs6uVo8WGzRoELRaLVasWGEwf9myZZAkCY8++qjB/JiYGINr5FJSUrBjxw48/PDDUCqVUCqVGDlyJLZs2VJlKKnJvtRGRWi618erjRw5EidPnsS2bdsqvVdxBLEiiP99mBetVlvtqeeysjL98CoAUFJSgtWrV8PNzc3gesW/c3NzQ9++fbF27VpcvXq1yjqISH48YkdElTg6OuI///kPnnnmGXTv3h1jx46Fm5sbrl69ip07d+K+++6rFLz+KTg4GPv378fSpUvh6ekJPz8/hISE3HXbQ4YMwYABAzBv3jwkJSUhMDAQP/30E3bs2IGIiIhKw6Z07twZ4eHhBsOdAMDChQv1bd59910cOHAAISEhmDZtGjp27IisrCzExcVh//79yMrKqkUv3VlQUBCUSiUWL16MnJwcqFQqPPjgg2jevLlR65kzZw6+++47jBo1CpMnT0ZwcDCysrLw/fffY9WqVQgMDESnTp3Qu3dvREVFISsrCy4uLtiwYQPKysqqXKenpycWL16MpKQktGvXDhs3bkR8fDzWrFlzx8GRP/roI9x///3o3r07pk+fDj8/PyQlJWHnzp2Ij483ar+IqJ7IeUsuEZmOqobMOHDggAgPDxdOTk5CrVaLNm3aiIkTJxoML1LdcCfnzp0Tffv2Fba2tgKAUUOf5Obmipdeekl4enoKa2tr4e/vL95///1Kw2oAEDNnzhRfffWV8Pf3FyqVSnTr1q3KIUbS09PFzJkzhbe3t7C2thYeHh5i4MCBYs2aNQb7C0Bs3rzZYNmqhv6oiU8//VS0bt1aKJVKg2FHfHx8xODBg6tc5p/DnQghxK1bt8SsWbNEy5YthY2NjfDy8hITJkwwGL7l8uXLIiwsTKhUKuHu7i7mzp0r9u3bV+VwJ506dRLHjx8XoaGhQq1WCx8fH7FixYoa7fPp06fF8OHDhbOzs1Cr1SIgIEC8/vrrRvULEdUfSQgeQyci8yRJEmbOnHnXo4dERI0Fr7EjIiIishC8xo6IGoRWq73rjQr29vawt7dvoIpqp7CwEDk5OXds4+LiYjDAMRFRQ2GwI6IGkZKSctdBeefPn48FCxY0TEG1tHHjRkyaNOmObQ4cOID+/fs3TEFERH/Da+yIqEEUFRXh119/vWOb1q1b68dLM1U3btxAQkLCHdsEBwfrx5YjImpIDHZEREREFsIsTsXqdDpcv34dDg4OfNg0ERERNSpCCOTm5sLT0xMKxZ3vezWLYHf9+nV4e3vLXQYRERGRbFJSUuDl5XXHNmYR7CqeF5mSkgJHR0eZqyEiIiJqOBqNBt7e3gbPz66O0cHu8OHDeP/99xEbG4sbN25g27ZtGDZs2B2XOXjwICIjI5GQkABvb2+89tprmDhxYo23WXH61dHRkcGOiIiIGqWaXI5m9ADF+fn5CAwMxMqVK2vUPjExEYMHD8aAAQMQHx+PiIgITJ06FXv37jV200RERER0B0YfsXv00Ufx6KOP1rj9qlWr4OfnhyVLlgAAOnTogF9//RXLli1DeHh4lcsUFxejuLhY/1qj0RhbptGKSrV4aNmhGreXULObOIy516OmTY25gcSoW01q2NiYdda0VuPWWcN2Rqy1Pu7JkXXfjfq+k+972ZiV1vzno8arrPOfOWulBHuVNRzUVrBXWcFebQVHtTU8nFRo4WQLTydbeDipYWPFh/4QUf2o92vsYmJiEBYWZjAvPDwcERER1S6zaNEiLFy4sJ4rqywlq7DBt0lEjYskAa72KrR2tUM7dwcEeDggyNsZAR4OsFYy8BHRvan3YJeWlgZ3d3eDee7u7tBoNCgsLIStrW2lZaKiohAZGal/XXHRYH2yUSqw7fk+NWpb04H/jBshsGaNjVlnfdRZ02EPjdl14/apho3l7idZv541X2mNW8q973X/Za+X7+WSMh3yisuQV1SG3L/+zS4owY2cItzIKcT1nCKUlOmQkVuMjNxiHE3M0i+rslIgyNsZ97V1xX1tmyHQyxlWDHpEZCSTvCtWpVJBpVI16DYVCgndWnGkeCKqP0IIZOWXIDW7EJdu5uF8ei7OXNfgZEo2NEVlOJqYhaOJWVi6D3Cxs0FYh+Z4tHMLPODvypBHRDVS78HOw8MD6enpBvPS09Ph6OhY5dE6IiJLJUkSmtmr0Mxeha5ezvr5Op1A4q18/H7lFn67lInfLt1CVn4JNh2/hk3Hr8HVXoXh3Twxpqc32ja/+3AHRNR41XuwCw0Nxa5duwzm7du3D6GhofW9aSIis6BQSGjjZo82bvZ4KsQHpVodjiVmYW9CGnaduoHMvGJ8+ksiPv0lEQ/4u2Ly/X7o386NT+IhokqMflZsXl4eLl26BADo1q0bli5digEDBsDFxQWtWrVCVFQUUlNT8cUXXwAoH+6kc+fOmDlzJiZPnoyff/4Zs2fPxs6dO6u9K/afNBoNnJyckJOTw3HsiKhRKdXqcOh8BjYeT8H+s+n66w07tnDEi2H+eLijOwMekYUzJgcZHewOHjyIAQMGVJo/YcIErF+/HhMnTkRSUhIOHjxosMxLL72EM2fOwMvLC6+//rpRAxQz2BERAVdvFeDzmCRsOHYV+SVaAEDnlo6YN6gjQts0k7k6Iqov9Rrs5MBgR0T0P7fzS/DZr1ew/rckfcAL7+SOeYM6olWzJjJXR0R1jcGOiKgRyMovwfL9F/D10avQ6gRUVgpEPtQOU+734120RBaEwY6IqBG5kJ6LBd8n4MjlWwCATp6OWDI6EO09+HlJZAmMyUH8k46IyMy1c3fA11ND8N4TXeFka42E6xo8vuI3rPst0agBq4nI/DHYERFZAEmSMLqHN/ZF9sWAADeUlOmw8IczmLT+D9zOL5G7PCJqIAx2REQWpLmDGmsn9sTCxzvBxkqBg+czMGTFrzidmiN3aUTUABjsiIgsjCRJmNDHF9ufvw+tXJrg2u1CjPzPEWw/kSp3aURUzxjsiIgsVEdPR/ww634MCHBDcZkOERvj8eH+i7zujsiCMdgREVkwpybW+O+Enni2XxsAwLL9F/Dy5pMoKdPJXBkR1QcGOyIiC6dQSHj10fZYNKILlAoJW+NSMe2L4yj8a3BjIrIcDHZERI3EuF6tsHZiT9haK3HoQgbGrz0KTVGp3GURUR1isCMiakT6tXPDV1N7wUFthT+SbmPcmt+RXcDhUIgsBYMdEVEjE+zjgg3Te6OZnQ0Srmvw1GdHkVPAI3dEloDBjoioEerk6YRv/xbunv7vUeQUMtwRmTsGOyKiRqqduwO+mdYbLnY2OJWag4nrjqGgpEzusojoHjDYERE1YgEeDvhmWgicbK1x4mo2ZnwZy6FQiMwYgx0RUSPX3sMR6yaV3y37y8VMvLQpHlodBzEmMkcMdkREhO6tmmLVM8GwVkrY+ecNvL3zrNwlEVEtMNgRERGA8qFQPhgVCABY+1si1v2WKHNFRGQsBjsiItIbGtQSrzwSAAB488cz+CkhTeaKiMgYDHZERGTguX5tMK5XKwgBvLghHmdvaOQuiYhqiMGOiIgMSJKEt4Z2wgP+rigs1WL6l8f5dAoiM8FgR0RElVgpFfh4XDd4u9giJasQL3x7AmVaDoNCZOoY7IiIqErOTWyw5pke+mFQ3t97Xu6SiOguGOyIiKhaHVo44v1RXQEAqw9fwY74VJkrIqI7YbAjIqI7eqyrJ57t1wYA8H9b/kTC9RyZKyKi6jDYERHRXc0JD0Dfdm4oKtVh+hexuJ3PmymITBGDHRER3ZVSIeHjsd3g06wJUrMLMee7PyEEHztGZGoY7IiIqEacmljjk6e6w0apwP6z6Vj3W5LcJRHRPzDYERFRjXXydMK8wR0AAIt2n8Wpa7zejsiUMNgREZFRxof6ILyTO0q1ArO+jUNuUancJRHRXxjsiIjIKJIk4b2RgWjpbIvkWwWYt+00r7cjMhEMdkREZDSnJtb4aFwQlAoJ35+8jk3HU+QuiYjAYEdERLUU7OOClx9uBwCY/30CLqTnylwRETHYERFRrT3btw0e8HdFUakOL26IR3GZVu6SiBo1BjsiIqo1hULCktGBcLGzwdkbGizbd1HukogaNQY7IiK6J80d1Fg0ogsAYPXhyzh65ZbMFRE1Xgx2RER0z8I7eWB0Dy8IAURuOskhUIhkUqtgt3LlSvj6+kKtViMkJATHjh2rtu369eshSZLBpFara10wERGZpjeGdIK3iy1Sswux4PszcpdD1CgZHew2btyIyMhIzJ8/H3FxcQgMDER4eDhu3rxZ7TKOjo64ceOGfkpOTr6noomIyPTYq6ywbHQQFBKwJe4adp+6IXdJRI2O0cFu6dKlmDZtGiZNmoSOHTti1apVaNKkCdauXVvtMpIkwcPDQz+5u7vfU9FERGSaevi64Nl+bQAAc7edwk1NkcwVETUuRgW7kpISxMbGIiws7H8rUCgQFhaGmJiYapfLy8uDj48PvL29MXToUCQkJNxxO8XFxdBoNAYTERGZh4iwdujk6YjbBaWY892ffCoFUQMyKthlZmZCq9VWOuLm7u6OtLS0KpcJCAjA2rVrsWPHDnz11VfQ6XTo06cPrl27Vu12Fi1aBCcnJ/3k7e1tTJlERCQjGysFlo8Jgo2VAocuZODbY3wqBVFDqfe7YkNDQzF+/HgEBQWhX79+2Lp1K9zc3LB69epql4mKikJOTo5+SknhhwIRkTnxd3fAK+EBAIB/7zyDq7cKZK6IqHEwKti5urpCqVQiPT3dYH56ejo8PDxqtA5ra2t069YNly5dqraNSqWCo6OjwUREROZl8n1+6OXngoISLf61+SR0Op6SJapvRgU7GxsbBAcHIzo6Wj9Pp9MhOjoaoaGhNVqHVqvFqVOn0KJFC+MqJSIis6JQSFgyKhB2NkocS8rC2t8S5S6JyOIZfSo2MjISn376KT7//HOcPXsWzz33HPLz8zFp0iQAwPjx4xEVFaVv/+abb+Knn37ClStXEBcXh6effhrJycmYOnVq3e0FERGZJG+XJnjtsY4AgPf2nsfF9FyZKyKybFbGLjBmzBhkZGTgjTfeQFpaGoKCgrBnzx79DRVXr16FQvG/vHj79m1MmzYNaWlpaNq0KYKDg3HkyBF07Nix7vaCiIhM1tie3tibkIaD5zMQuekktj7fB9ZKPviIqD5IwgzuQ9doNHByckJOTg6vtyMiMkPpmiI8vOwwcgpLERHmj4iwdnKXRGQ2jMlB/JOJiIjqnbujGm8O7QQAWPHzJZy6liNzRUSWicGOiIgaxOOBnhjcpQXKdAKRm+JRVKqVuyQii8NgR0REDUKSJLw1rDNc7VW4eDMPS/ddkLskIovDYEdERA3Gxc4Gi0d2AQB8+ssVHEvMkrkiIsvCYEdERA1qYAd3jO7hBSGAf20+ifziMrlLIrIYDHZERNTgXn+sI1o62+JqVgHe2XVW7nKILAaDHRERNTgHtTXeH9UVAPD10as4dCFD5oqILAODHRERyaJPG1dM7OMLAHjlu5PIKSiVtyAiC8BgR0REsvm/R9qjtasd0jXFmP/9abnLITJ7DHZERCQbWxsllowOhEICtsdfx+5TN+QuicisMdgREZGsurVqiuf7twUAzNt+Ghm5xTJXRGS+GOyIiEh2swf6o2MLR2TllyBq6ymYwWPMiUwSgx0REcnOxkqBpWMCYaNUYP/ZdHx19KrcJRGZJQY7IiIyCe09HPHKIwEAgLd+PINzaRqZKyIyPwx2RERkMqbc74cH2zdHSZkOs745gYISPpWCyBgMdkREZDIkScL7T3RFcwcVLt3Mw5s/nJG7JCKzwmBHREQmpZm9CsvHBkGSgA1/pOCHk9flLonIbDDYERGRyenTxhUz/xoCZe7WU0jJKpC5IiLzwGBHREQmKSLMH8E+TZFbXIZZ355AqVYnd0lEJo/BjoiITJKVUoEPxwbBUW2FkynZeGfXWblLIjJ5DHZERGSyvJo2wQejAgEA635LwvYTqTJXRGTaGOyIiMikPdzJA7MGlF9v9+rWP3HmOse3I6oOgx0REZm8lx5qh77t3FBUqsOMr44jK79E7pKITBKDHRERmTylQsJHY4Pg7WKLlKxCPPtlLIrLtHKXRWRyGOyIiMgsODexwdoJPeGgssKxpCzM23YaQgi5yyIyKQx2RERkNvzdHbDiqe5QSMB3sdew8sAluUsiMikMdkREZFb6tXPDgsc7AQA++OkCNhy7KnNFRKaDwY6IiMzO+FBfPN+/DQBg7rZT2HM6TeaKiEwDgx0REZmlOeEBGNPDGzoBzN5wAgfP35S7JCLZMdgREZFZkiQJbw/vjEc6eaCkTIfpX8TiwDmGO2rcGOyIiMhsWSkV+GhcN4R3ckeJVocZX8Zi/5l0ucsikg2DHRERmTUbKwVWPNkdg7p4lIe7r2LxLW+ooEaKwY6IiMyetVKBD8d2w4juLaHVCURtPYX3957jOHfU6DDYERGRRbBWKrBkVCBmD/QHAKw8cBnTvohFTkGpzJURNRwGOyIishiSJCHyoXZ474musFEqsP9sOgZ99AtOXL0td2lEDYLBjoiILM7oHt7Y+nwf+DRrgtTsQjyxKgbv7DqLgpIyuUsjqlcMdkREZJE6t3TCDy/cjyGBntDqBNYcvoKHlh7Gzj9vQKfjtXdkmSRhBleWajQaODk5IScnB46OjnKXQ0REZib6bDre2JGA1OxCAEA7d3vMetAfj3b2gLWSxzjItBmTg2r13bxy5Ur4+vpCrVYjJCQEx44du2P7zZs3o3379lCr1ejSpQt27dpVm80SERHVysAO7tgX2RezB/rDQWWFC+l5mP3tCfR+JxoLf0hA3NXbKNPq5C6T6J4ZfcRu48aNGD9+PFatWoWQkBAsX74cmzdvxvnz59G8efNK7Y8cOYK+ffti0aJFeOyxx/DNN99g8eLFiIuLQ+fOnWu0TR6xIyKiupJTWIp1vyXiq9+TkZlXop9vZ6NED18XdPR0hJ+rHVq5NEHTJjZwtLWCrbUSEiRAAhRS+U0aEgBJAhSSJN/OkOwkCVBZKet1G8bkIKODXUhICHr27IkVK1YAAHQ6Hby9vfHCCy/g1VdfrdR+zJgxyM/Px48//qif17t3bwQFBWHVqlVVbqO4uBjFxcUGO+Tt7c1gR0REdaZMq8MvFzOxJe4afrmYiZxCDotCxuvl64JNz4bW6zaMCXZWxqy4pKQEsbGxiIqK0s9TKBQICwtDTExMlcvExMQgMjLSYF54eDi2b99e7XYWLVqEhQsXGlMaERGRUayUCgxo3xwD2jeHTidwLi0XfyRl4XJGHhIz83HtdiFyCkuRU1gKLW+2IDNhVLDLzMyEVquFu7u7wXx3d3ecO3euymXS0tKqbJ+WllbtdqKiogzCYMUROyIiovqgUEjo6OmIjp6Vj4YIIaDVCQgAQgACovzfv/7PzNe4KU3sVLxRwa6hqFQqqFQqucsgIiKCJEmwUprWL2+i6hh1V6yrqyuUSiXS09MN5qenp8PDw6PKZTw8PIxqT0RERES1Y9QROxsbGwQHByM6OhrDhg0DUH7zRHR0NGbNmlXlMqGhoYiOjkZERIR+3r59+xAaWvMLDSvu79BoNMaUS0RERGT2KvJPje53FUbasGGDUKlUYv369eLMmTNi+vTpwtnZWaSlpQkhhHjmmWfEq6++qm//22+/CSsrK/HBBx+Is2fPivnz5wtra2tx6tSpGm8zJSVFAODEiRMnTpw4cWq0U0pKyl0zk9HX2I0ZMwYZGRl44403kJaWhqCgIOzZs0d/g8TVq1ehUPzvDG+fPn3wzTff4LXXXsPcuXPh7++P7du313gMOwDw9PRESkoKHBwcINXjRYoVN2mkpKQ06mFV2A/sgwrsh3Lsh3LsB/ZBBfZDuYbqByEEcnNz4enpede2ZvFIsYbCgZDLsR/YBxXYD+XYD+XYD+yDCuyHcqbYD3xAHhEREZGFYLAjIiIishAMdn+jUqkwf/78Rj+GHvuBfVCB/VCO/VCO/cA+qMB+KGeK/cBr7IiIiIgsBI/YEREREVkIBjsiIiIiC8FgR0RERGQhGOyIiIiILASDHREREZGFYLAjIiIishAMdkREREQWgsGOiIiIyEIw2BERERFZCAY7IiIiIgvBYEdERERkIRjsiIiIiCwEgx0RERGRhWCwIyIiIrIQDHZEZPEkScKCBQvqbf2+vr547LHH7tru4MGDkCQJBw8erLdaiKhxY7AjIrNy5MgRLFiwANnZ2XKXQkRkcqzkLoCIyBhHjhzBwoULMXHiRDg7O9domcLCQlhZyf9x17dvXxQWFsLGxkbuUojIQvGIHRFZJJ1Oh6KiIgCAWq02iWCnUCigVquhUPCjl4jqBz9diMhsLFiwAHPmzAEA+Pn5QZIkSJKEpKQkSJKEWbNm4euvv0anTp2gUqmwZ88eAFVfY5eamoopU6bA09MTKpUKfn5+eO6551BSUqLfliRJlWpYv369fpv/9NNPPyEoKAhqtRodO3bE1q1bDd6v7hq7o0ePYtCgQWjatCns7OzQtWtXfPjhh7XsJSJqzOT/E5aIqIZGjBiBCxcu4Ntvv8WyZcvg6uoKAHBzcwMA/Pzzz9i0aRNmzZoFV1dX+Pr6Vrme69evo1evXsjOzsb06dPRvn17pKam4rvvvkNBQUGtTpVevHgRY8aMwbPPPosJEyZg3bp1GDVqFPbs2YOHHnqo2uX27duHxx57DC1atMCLL74IDw8PnD17Fj/++CNefPFFo+sgosaNwY6IzEbXrl3RvXt3fPvttxg2bFil4Hb+/HmcOnUKHTt2vON6oqKikJaWhqNHj6JHjx76+W+++SaEELWq7cKFC9iyZQtGjBgBAJgyZQrat2+P//u//6s22Gm1WsyYMQMtWrRAfHy8wTWDta2DiBo3noolIovRr1+/u4Y6nU6H7du3Y8iQIQahrkJVp19rwtPTE8OHD9e/dnR0xPjx43HixAmkpaVVucyJEyeQmJiIiIiISjeC1LYOImrcGOyIyGL4+fndtU1GRgY0Gg06d+5cp9tu27ZtpTDWrl07AKjyejwAuHz5MgDUeS1E1Hgx2BGRxbC1ta2zdVV3xEyr1dbZNoiI6hqDHRGZlXs9Renm5gZHR0ecPn36ju2aNm0KAJUGQk5OTq6y/aVLlypdF3fhwgUAqPYmjjZt2gDAXWshIqopBjsiMit2dnYAKgeumlIoFBg2bBh++OEHHD9+vNL7FeGsInQdPnxY/15+fj4+//zzKtd7/fp1bNu2Tf9ao9Hgiy++QFBQEDw8PKpcpnv37vDz88Py5csr7Q9vniCi2uBdsURkVoKDgwEA8+bNw9ixY2FtbY0hQ4YYtY533nkHP/30E/r164fp06ejQ4cOuHHjBjZv3oxff/0Vzs7OePjhh9GqVStMmTIFc+bMgVKpxNq1a+Hm5oarV69WWme7du0wZcoU/PHHH3B3d8fatWuRnp6OdevWVVuHQqHAf/7zHwwZMgRBQUGYNGkSWrRogXPnziEhIQF79+41rnOIqNFjsCMis9KzZ0+89dZbWLVqFfbs2QOdTofExESj1tGyZUscPXoUr7/+Or7++mtoNBq0bNkSjz76KJo0aQIAsLa2xrZt2/D888/j9ddfh4eHByIiItC0aVNMmjSp0jr9/f3x8ccfY86cOTh//jz8/PywceNGhIeH37GW8PBwHDhwAAsXLsSSJUug0+nQpk0bTJs2zah9IiICAEnweD8RERGRReA1dkREREQWgsGOiIiIyEIw2BERERFZCAY7IiIiIgvBYEdERERkIcxiuBOdTofr16/DwcGBD8YmIiKiRkUIgdzcXHh6ekKhuPMxObMIdtevX4e3t7fcZRARERHJJiUlBV5eXndsY3SwO3z4MN5//33Exsbixo0b2LZtG4YNG3bHZQ4ePIjIyEgkJCTA29sbr732GiZOnFjjbTo4OAAo3yFHR0djSyYiIiIyWxqNBt7e3vo8dCdGB7v8/HwEBgZi8uTJGDFixF3bJyYmYvDgwXj22Wfx9ddfIzo6GlOnTkWLFi3uOiJ7hYrTr46Ojgx2RERE1CjV5HI0o4Pdo48+ikcffbTG7VetWgU/Pz8sWbIEANChQwf8+uuvWLZsWY2DHRFRfRBCoESrQ1GpDsVlWpSU6fD3Z/FU/F9A/O3/5RQSYKVUwEoh/TUpoLJWQGWl4LXARCSber/GLiYmBmFhYQbzwsPDERERUe0yxcXFKC4u1r/WaDT1VR4RWaD84jIkZubjSmY+kjLzkZlXjFv5JcjKK0FWfglu5Zcgr7gUxf8IcnXBWinBXmUFe7UV7FXWcFRbwcNJjRZOtvB0Lv+3hZMafq52sFOZxWXORGRG6v1TJS0tDe7u7gbz3N3dodFoUFhYCFtb20rLLFq0CAsXLqzv0ojIAtzIKURccjZOXsvG6dQcXMnIR5qmyOj1SBJgo1RAkgAJkn6epH9f0v8fEqDTCZT9NWl1/0uHpVqB2wWluF1QCqDwjtv0amqL9h4O6OrljG6tnBHk7QwHtbXRtRMRVTDJPxejoqIQGRmpf11x0SARUVGpFr9czMShCzfx26VbSMzMr7Kdi50NWrvawdfVDh6OarjY2aCZvQ1c7MonR7U1VNYKqK2VUFspYa2Uan0KVacT0AqBolIt8ou1yCsuRW5RGfKKy3C7oBRpOYW4nl2EGzmFuJFThNTbhbiVX4Jrtwtx7XYh9p+9CQBQKiR09XLC/W1d8WD75gj0coZCwdO6RFRz9R7sPDw8kJ6ebjAvPT0djo6OVR6tAwCVSgWVSlXfpRGRmSgp0+HnczexIz4Vhy5koKBEq39PIQEdWjgiyNsZgV7OaOtuj9audnBuYtNg9SkUEhSQYK1U/HXETX3XZbLyS3AhPRdnrmsQn5KNEym3kZJViBNXs3HiajY+/vkS3B1VCO/kgRHdvRDo5cRr94joruo92IWGhmLXrl0G8/bt24fQ0ND63jQRmbmkzHx8EZOMbSeu/XVqs5ynkxphHd3xgL8bQlq7wNEMT1+62Nmgd+tm6N26mX5eanYhfruUiUMXMnDofAbSNcX4IiYZX8Qko21ze4zt6Y3RPb3Ncn+JqGFIQhh36XBeXh4uXboEAOjWrRuWLl2KAQMGwMXFBa1atUJUVBRSU1PxxRdfACgf7qRz586YOXMmJk+ejJ9//hmzZ8/Gzp07a3xXrEajgZOTE3JycjjcCVEjcPTKLXz6yxVEn7upv7mhuYMKw7u1xGNdPdG5paPFH70qLtPit0uZ+D7+OvYkpKGoVAcAsLNR4olgL0x9oDW8XZrIXCURNQRjcpDRwe7gwYMYMGBApfkTJkzA+vXrMXHiRCQlJeHgwYMGy7z00ks4c+YMvLy88Prrrxs1QDGDHVHjcCwxC8v2XUDMlVv6eQ+2b45nevvgAX9XWCkb5+Otc4tK8cPJG1h/JBEX0vMAAFYKCaN6eGHmgLbwasqAR2TJ6jXYyYHBjsiyXc7Iwzs7zyL6XPlNBNZKCaN6eGPK/X5o42Yvc3WmQwiB3y7dwqpDl/HrpUwA5XfyTrrPF7MebMs7aoksFIMdEZmF/OIyLNt3AeuPJKFMJ2ClkDC6pzdmDmiLls5V31xF5f5IKj+6eeRy+dFNV3sbvPJIe4wK9rL409REjQ2DHRGZvAPnb+K1baeRml0+1tvA9s0xd3AHHqEzghACB89n4K2dZ3Alo3zYlz5tmuGd4V3g62onc3VEVFcY7IjIZOUVl2H+jgRsibsGoHyQ3n8P64z+Ac1lrsx8lWp1WPdbIpbuu4CiUh1UVgq8+mh7TOzjy6N3RBaAwY6ITFLc1duI2BCPq1kFUEjApPv88PLD7dDExiTHSjc7V28VYO62U/rr7/oHuOH9JwLh5sBxQYnMGYMdEZkUIQQ+/eUKFu85D61OoKWzLZaPDUJPXxe5S7M4Qgh8EZOMt3edRUmZDq72Nvh4XHeEtml294WJyCQZk4Ma59gBRNRg8ovLMOubE3hn1zlodQJDAj2x68UHGOrqiSRJmNDHFz/Muh8B7g7IzCvB0/89is9+uQIz+DueiO4Rgx0R1Ztrtwsw/JPfsPPUDVgpJLw1tBM+GhsEJ1sOy1HfAjwcsH3mfRgW5AmtTuDfO88ictNJFJdp774wEZktBjsiqhd/XsvGsJVHcCE9D24OKmyY3hvPhPJi/oZka6PEsjFBWDCkI6wUEradSMUz/z2G7IISuUsjonrCYEdEdW7/mXSMWf07MvOK0d7DAd/Pug89eOpVFpIkYeJ9flg/qRccVFY4lpiFEZ8cQUpWgdylEVE9YLAjojq17cQ1zPgqFoWlWvRr54bNz4aihRMHG5bb/f6u+O65PmjpbIsrmfl4YtURXEzPlbssIqpjDHZEVGe+jEnCSxtPQqsTGNG9Jf47oQcfc2VCAjwcsO35Pghwd0C6phijV8fgz2vZcpdFRHWIwY6I6sRnv1zB6zsSAAAT+/jigycCYaXkR4ypae6oxsYZvRHo7YzbBaV48tOjiLt6W+6yiKiO8FOXiO7Z2l8T8e+dZwEAswa0xfwhHaFQ8CYJU+XcxAZfTw1B79YuyCsuw4T/HkN8SrbcZRFRHWCwI6J78vmRJLz54xkAwAsPtsXLD7fjna9mwF5lhbUTe6KXnwtyi8vwzH+P8rQskQVgsCOiWtsSew3zvy8//fp8/zaIfIihzpw0sbHCuok90cvXBblFZZiw9hgu3eQNFUTmjMGOiGpl35l0vLLlTwDAlPv9MCc8gKHODNmprLB2Uk/9NXdPf3YM125zKBQic8VgR0RGO3rlFmZ+EwetTmBkdy/MG9SBoc6M2aussH5iT7Rtbo80TRGe+e8x3MorlrssIqoFBjsiMkpiZj6mfxmLkjIdwjq4Y/HILrxRwgI0tbPBl1N6oaWzLRIz8zH1i+MoKuXjx4jMDYMdEdVYdkEJpqz/AzmFpQjydsaKJ7txSBML0sLJFp9P7gUnW2ucuJqNlzbGQ6cTcpdFREbgJzIR1UhJmQ7PfRWHK5n5aOlsizXjg6G2VspdFtWxts3tseaZYNgoFdh9Og2Ldp+VuyQiMgKDHRHdlRACr28/jZgrt2Bno8RnE3qguYNa7rKonoS0bob3R3UFAHz6SyK2xF6TuSIiqikGOyK6q89+ScTG4ylQSMDHT3ZDhxaOcpdE9WxoUEvMfrAtACBq2ymOcUdkJhjsiOiO9p1Jxzt/nY57bXBHPNjeXeaKqKFEhLXDwPbNUVKmw4wvY5GRyztliUwdgx0RVetyRh4iNpyAEMBTIa0w6T5fuUuiBqRQSFg2Ngit3exwI6cIM7+JQ6lWJ3dZRHQHDHZEVKWCkjI891Us8ku0CPFzwYLHO3GsukbIUW2NNc/0gL3KCscSs/Dvvx4fR0SmicGOiCoRQuC1badxIT0Pbg4qfPxkN1hzWJNGq21zeywbEwQA+DwmGZuOp8hbEBFVi5/URFTJt8dSsPVEKpQKCSvGdeMdsISHOrojIswfAPDattM4nZojc0VEVBUGOyIycOpaDhZ8nwAAmBMegJDWzWSuiEzF7Af9EdbBHSVaHWZ9E4e84jK5SyKif2CwIyK9nIJSPP9NLEq05Y8Lm9G3tdwlkQlRKCR8MKorWjrbIulWAeZtOwUh+GQKIlPCYEdEAACdTuDlzfFIySqEt4stlowO5M0SVIlzExt8NC4ISoWEHfHXsfk4By8mMiUMdkQEAFh/JAn7z96EjZUC/3kqGE621nKXRCYq2McFkQ+1AwC88f1pXEzPlbkiIqrAYEdEOHtDg3d3nwMAvD64Azq3dJK5IjJ1z/Vrgwf8XVFUqsOsb06gsEQrd0lEBAY7okavqFSL2d+e+Ou6uuZ4ureP3CWRGVAoJCwdHQRXexXOp+fizR8T5C6JiMBgR9TovbPrLC7eLB+vbvHIrryujmrMzUGFD8cGQZLKh8j58c/rcpdE1Ogx2BE1YvvPpOOLmGQAwJJRgWhmr5K5IjI397V1xcz+bQEAc7eeQlpOkcwVETVuDHZEjdRNTRFe2fInAGDK/X7o285N5orIXL0Y5o9ALydoisrwr80nodNxCBQiuTDYETVC5UObnERWfgk6tHDEK48EyF0SmTFrpQJLxwRBba3Ar5cy8XlMktwlETVaDHZEjdD6I0n45WImVFYKfDQ2CCorpdwlkZlr42aPeYM6AADe3X2OQ6AQyaRWwW7lypXw9fWFWq1GSEgIjh07Vm3b9evXQ5Ikg0mt5nMnieRy6WYeFu8pH9rktcEd4O/uIHNFZCme7u2Dfu3cUFymQ8TGeJSU6eQuiajRMTrYbdy4EZGRkZg/fz7i4uIQGBiI8PBw3Lx5s9plHB0dcePGDf2UnJx8T0UTUe2UaXV4efNJFJfp8IC/K4c2oTolSRLef6IrmjaxRsJ1DZbvvyB3SUSNjtHBbunSpZg2bRomTZqEjh07YtWqVWjSpAnWrl1b7TKSJMHDw0M/ubu733EbxcXF0Gg0BhMR3btVhy7jZEo2HNRWeO8JDm1Cda+5oxqLRnQBUP799kdSlswVETUuRgW7kpISxMbGIiws7H8rUCgQFhaGmJiYapfLy8uDj48PvL29MXToUCQk3Hkgy0WLFsHJyUk/eXt7G1MmEVUh4XoOPoy+CABY+HgntHCylbkislSPdG6Bkd29oBNA5KZ45BWXyV0SUaNhVLDLzMyEVqutdMTN3d0daWlpVS4TEBCAtWvXYseOHfjqq6+g0+nQp08fXLtW/YOjo6KikJOTo59SUlKMKZOI/qG4TIvIjSdRqhUI7+SO4d1ayl0SWbgFj3dES2dbpGQV4p1dZ+Uuh6jRqPe7YkNDQzF+/HgEBQWhX79+2Lp1K9zc3LB69epql1GpVHB0dDSYiKj2lu+/iPPpuWhmZ4O3h3fhKViqdw5qa7w/qisA4JujV3HwfPXXYRNR3TEq2Lm6ukKpVCI9Pd1gfnp6Ojw8PGq0Dmtra3Tr1g2XLl0yZtNEVEuxyVlYfegyAODt4V3gyqdLUAPp08YVE/v4AgD+b8ufyCkolbcgokbAqGBnY2OD4OBgREdH6+fpdDpER0cjNDS0RuvQarU4deoUWrRoYVylRGS0gpIyvLzpJHQCGNGtJR7pXLM/wIjqyv890h6tXe2QrinGG9+flrscIotn9KnYyMhIfPrpp/j8889x9uxZPPfcc8jPz8ekSZMAAOPHj0dUVJS+/ZtvvomffvoJV65cQVxcHJ5++mkkJydj6tSpdbcXRFSlxbvPIelWATwc1Zj/eCe5y6FGyNZGiSWjA6GQgB3x17Hr1A25SyKyaFbGLjBmzBhkZGTgjTfeQFpaGoKCgrBnzx79DRVXr16FQvG/vHj79m1MmzYNaWlpaNq0KYKDg3HkyBF07Nix7vaCiCr57VImPo8pHzPyvSe6wsnWWuaKqLHq1qopnu/fFisOXMK8bafQ09cFbg68JICoPkhCCJN/WrNGo4GTkxNycnJ4IwVRDWiKSvHIssO4nlOEp3u3wr+HdZG7JGrkSsp0GLryN5y9oUFYB3d8Oj6YN/EQ1ZAxOYjPiiWyQAu/P4PrOUXwadYEUY92kLscIthYKbB0dCCslRL2n03Hd7HVD3lFRLXHYEdkYfYmpGFL3DVIErBkVCDsVEZfcUFULzq0cMRLD7UDALz5wxmkZhfKXBGR5WGwI7IgmXnFmLv1FABget/W6OHrInNFRIZm9G2D7q2ckVtchjmbT0KnM/mrgYjMCoMdkYUQQmDu1lO4lV+CAHcHRP51ZITIlCgVEpaMDoKttRJHLt/Cl78ny10SkUVhsCOyEFvjUvHTmXRYKyUsHRMIlZVS7pKIquTnaoeoQe0BAIt2n8WVjDyZKyKyHAx2RBYgNbsQC75PAABEhLVDJ08nmSsiurOnQ3xwf1tXFJXq8PLmkyjT6uQuicgiMNgRmTmdTuCV704it7gM3Vo5Y0bf1nKXRHRXCoWE957oCgeVFU5czcbqw1fkLonIIjDYEZm5L2KS8NulW1BbK7B0dBCslPyxJvPg6WyrfyLK8v0XcOa6RuaKiMwffwMQmbHLGXl4d885AMDcQR3g52onc0VExhnZvSUe6uiOUq1A5KZ4lJTxlCzRvWCwIzJTZVodIjedRFGpDg/4u+LpEB+5SyIymiRJWDSiC1zsbHAuLRcfRl+QuyQis8ZgR2SmVh26jJMp2XBQW+G9J7pCoeDjmcg8udqr8M7wzgCA/xy8jLirt2WuiMh8MdgRmaHTqTlYvv8iAODNoZ3QwslW5oqI7s0jnVtgeLeW0Ang5U0nkV9cJndJRGaJwY7IzOQVl2HWN3Eo0wk82tkDw4Jayl0SUZ1YMKQTWjipkZiZj/l/Dd9DRMZhsCMyM29sP42kWwXwdFJj0YgukCSegiXL4NTEGsvHBEEhAd/FXsOO+FS5SyIyOwx2RGZkS+w1bD2RCoUEfDiuG5yb2MhdElGdCmndDC886A8AmLftNJIy82WuiMi8MNgRmYkrGXl4fcdpAMBLYe3Q09dF5oqI6scLD7ZFL18X5BWXYfaGExwChcgIDHZEZqC4TIsXvj2BghIterd2wfMD2spdElG9sVIqsHxsEJybWOPPazl4f+85uUsiMhsMdkRmYPHu80i4roGLnQ0+HNsNSg5tQhbO09kW743sCgD49JdEHDh/U+aKiMwDgx2Ridt/Jh1rf0sEAHwwqivcHdUyV0TUMB7u5IEJoeUDb/9r00mka4pkrojI9DHYEZmwpMx8RG6KBwBMvs8PD7Z3l7cgogYWNagDOrRwxK38Ejz/dRyvtyO6CwY7IhNVUFKGZ7+KhaaoDME+TfHqo+3lLomowamtlfjPU93hoLZCbPJt/HvnGblLIjJpDHZEJkgIgaitp3AuLReu9ip88lR32Fjxx5UaJ19XOywfEwQA+CImGVtir8lbEJEJ428KIhO0+vAV7Ii/DqVCwsonu/G6Omr0BnZwx+yB5ePbRW07xefJElWDwY7IxOxNSMPiPeXDO7zxWEeEtG4mc0VEpiFioD/COjRHSZkO07+IRWp2odwlEZkcBjsiE3I6NQcRG+IhBPBMbx9M6OMrd0lEJkOhkPDh2G5o7+GAzLxiTFn/B/KKy+Qui8ikMNgRmYiUrAJM+fwPFJZq8YC/K+YP6Sh3SUQmx05lhf9O7AlXexXOpeXyTlmif2CwIzIBmXnFGL/2GNI1xWjnbo8VT3aHlZI/nkRVaelsi88m9ICttRKHL2RgzncnodMJucsiMgn8zUEks7ziMkxa9wcSM/PR0tkWX0wOgZOttdxlEZm0IG9nfPJ0d1gpJOyIv443fzwDIRjuiBjsiGSUW1SKiWuP4VRqDlzsbPDllF7wcOIdsEQ1MSCgOT4YFQgAWH8kCe/uOcdwR40egx2RTDRFpZiw9hiOJ9+Go9oKn0/qhdZu9nKXRWRWhnVriTeHdgIArD50Be/sOstwR40agx2RDG7nl2D8f48h7mo2nGyt8fXU3uji5SR3WURmaXyorz7cffpLIhb+cIbX3FGjxWBH1MCSb+VjxH+OID4lG85NrPH11BCGOqJ7ND7UF/8e1hlA+WnZmd/EoahUK3NVRA2PwY6oAcUm38aIT47ob5TYPCMUnVsy1BHVhad7++DDsUGwUSqw+3Qanvz0d2TmFctdFlGDYrAjagBCCPz310SMXRODW/kl6NzSEdtm9oG/u4PcpRFZlKFBLfHFlF5wVFsh7mo2Bn/0C45euSV3WUQNhsGOqJ5l5ZdgxpexeOvHMyjVCgzq4oGN00PR3IF3vxLVh96tm2Hr833Qxs0O6ZpijPv0d3wcfRFlWg5kTJZPEmZw+5BGo4GTkxNycnLg6OgodzlENSKEwObj1/DO7rPILiiFjVKB1x7rgGd6+0CSJLnLI7J4+cVleH37aWw9kQoA6NDCEe8M74xurZrKXBmRcYzJQQx2RHVMCIGYy7ewZN8FxCbfBgC093DA+08E8iYJogYmhMDWuFS8tfMMsgtKIUnAyO5eeOHBtvBpZid3eUQ1YkwOqtWp2JUrV8LX1xdqtRohISE4duzYHdtv3rwZ7du3h1qtRpcuXbBr167abJbIpBWXabHn9A2MXh2DJz87itjk27C1VmLuoPb44YX7GeqIZCBJEkYGeyE6sh9GdG8JIYDvYq/hwSWHELkpHnFXb3PcO7IoRh+x27hxI8aPH49Vq1YhJCQEy5cvx+bNm3H+/Hk0b968UvsjR46gb9++WLRoER577DF88803WLx4MeLi4tC5c+cabZNH7MhUZeWX4FjiLRy+mImdf95ATmEpAMDGSoFxPb3xbP82aOFkK3OVRFQh7uptfBR9EQfPZ+jn+bnaYUjXFght44purZyhtlbKWCFRZfV6KjYkJAQ9e/bEihUrAAA6nQ7e3t544YUX8Oqrr1ZqP2bMGOTn5+PHH3/Uz+vduzeCgoKwatWqGm2zIYKdView70ya0cvV9g+92ixW+20Zv2DD7lfD/rVcm80JCOQVa6EpLEVmXjGSMvORmJmPpFsFBu08HNUY3r0lJvbxhbsjb44gMlUnU7Kx/kgS9pxOQ+HfxruzsVKgjZs9/FyboJWLHZo2sYajrTVsrZWouDRWkiRIACQJkCBBIQG8bLbxcm5ig96tm9XrNozJQVbGrLikpASxsbGIiorSz1MoFAgLC0NMTEyVy8TExCAyMtJgXnh4OLZv317tdoqLi1Fc/L+xhzQajTFl1kqpVodnv4qr9+2Q5Wnnbo8Qv2Z4uJM7+rRxhVLBT3giUxfo7YxlY4Lw72Fl2HM6DYcuZOD3K7dwM7cYZ29ocPZG/f/eIcvQy9cFm54NlbsMPaOCXWZmJrRaLdzd3Q3mu7u749y5c1Uuk5aWVmX7tLTqj44tWrQICxcuNKa0eyZJQE/f2t0pVf63W60WbIhFyper1bZqt7Xa/uVq6jU2sVHCydYaTe1s4ONiB1/XJghwd0Aze1WtaiAi+dmprDAy2Asjg70ghMDVrAJczsjDlYx8pGYXIqewFJrCUhSV6iAgIET5UX+d+OtcyF//p8YrwMO0xiM1Ktg1lKioKIOjfBqNBt7e3vW6TZWVEpuf7VOv2yAiItMlSRJ8mtnBp5kdHmwvdzVEtWNUsHN1dYVSqUR6errB/PT0dHh4eFS5jIeHh1HtAUClUkGl4lEQIiIiImMYNdyJjY0NgoODER0drZ+n0+kQHR2N0NCqzy+HhoYatAeAffv2VdueiIiIiGrH6FOxkZGRmDBhAnr06IFevXph+fLlyM/Px6RJkwAA48ePR8uWLbFo0SIAwIsvvoh+/fphyZIlGDx4MDZs2IDjx49jzZo1Nd5mxV2TDXETBREREZEpqcg/NRpFQtTCxx9/LFq1aiVsbGxEr169xO+//65/r1+/fmLChAkG7Tdt2iTatWsnbGxsRKdOncTOnTuN2l5KSopA+UganDhx4sSJEydOjXJKSUm5a2Yyi0eK6XQ6XL9+HQ4ODvX6jM2KmzRSUlIa9UDI7Af2QQX2Qzn2Qzn2A/ugAvuhXEP1gxACubm58PT0hEJx56voTPKu2H9SKBTw8vJqsO05Ojo26m/UCuwH9kEF9kM59kM59gP7oAL7oVxD9IOTk1ON2tXqWbFEREREZHoY7IiIiIgsBIPd36hUKsyfP7/Rj6HHfmAfVGA/lGM/lGM/sA8qsB/KmWI/mMXNE0RERER0dzxiR0RERGQhGOyIiIiILASDHREREZGFYLAjIiIishAMdkREREQWgsGOiIiIyEIw2BERERFZCAY7IiIiIgvBYEdERERkIRjsiIiIiCwEgx0RERGRhWCwIyIiIrIQDHZEREREFoLBjoiIiMhCMNgREQBgwYIFkCTpnpbNzMys46qogq+vLyZOnFhv6+/fvz86d+5813ZJSUmQJAnr16+vt1qIqPYY7IioQb3zzjvYvn273GXI5syZM1iwYAGSkpLkLoWILBCDHREBAF577TUUFhbW+3YY7M5g4cKFRge78+fP49NPP62foozg4+ODwsJCPPPMM3KXQkRVYLAjIuTn58PKygpqtVruUuhvhBD6sK1SqWBtbS1zRYAkSVCr1VAqlXKXQkRVYLAjamQqroc7c+YMnnzySTRt2hT3339/ldfYFRYWYvbs2XB1dYWDgwMef/xxpKamQpIkLFiwoNK6s7OzMXHiRDg7O8PJyQmTJk1CQUGB/n1JkpCfn4/PP/8ckiRBkiSjrhvLz8/Hyy+/DG9vb6hUKgQEBOCDDz6AEMKgnSRJmDVrFr7++msEBARArVYjODgYhw8frrTO1NRUTJ48Ge7u7lCpVOjUqRPWrl1r0ObgwYOQJAmbNm3C22+/DS8vL6jVagwcOBCXLl2qcf3r16/HqFGjAAADBgzQ98HBgwcBlF9H99hjj2Hv3r3o0aMHbG1tsXr1av17/+yr7OxsvPTSS/D19YVKpYKXlxfGjx+vv9Zx/fr1kCSp0tHBiv2p2O7fxcbGok+fPrC1tYWfnx9WrVpl8H5119idO3cOo0ePhpubG2xtbREQEIB58+bVuG+IqG5YyV0AEclj1KhR8Pf3xzvvvAMhBG7evFmpzcSJE7Fp0yY888wz6N27Nw4dOoTBgwdXu87Ro0fDz88PixYtQlxcHD777DM0b94cixcvBgB8+eWXmDp1Knr16oXp06cDANq0aVOjeoUQePzxx3HgwAFMmTIFQUFB2Lt3L+bMmYPU1FQsW7bMoP2hQ4ewceNGzJ49GyqVCp988gkeeeQRHDt2TH+TQHp6Onr37q0Pgm5ubti9ezemTJkCjUaDiIgIg3W+++67UCgU+Ne//oWcnBy89957eOqpp3D06NEa7UPfvn0xe/ZsfPTRR5g7dy46dOgAAPp/gfJTruPGjcOMGTMwbdo0BAQEVLmuvLw8PPDAAzh79iwmT56M7t27IzMzE99//z2uXbsGV1fXGtX0d7dv38agQYMwevRojBs3Dps2bcJzzz0HGxsbTJ48udrl/vzzTzzwwAOwtrbG9OnT4evri8uXL+OHH37A22+/bXQdRHQPBBE1KvPnzxcAxLhx46qcXyE2NlYAEBEREQbtJk6cKACI+fPnV1p28uTJBm2HDx8umjVrZjDPzs5OTJgwwei6t2/fLgCIf//73wbzn3jiCSFJkrh06ZJ+HgABQBw/flw/Lzk5WajVajF8+HD9vClTpogWLVqIzMxMg3WOHTtWODk5iYKCAiGEEAcOHBAARIcOHURxcbG+3YcffigAiFOnTtV4PzZv3iwAiAMHDlR6z8fHRwAQe/bsqfK9v/fbG2+8IQCIrVu3Vmqr0+mEEEKsW7dOABCJiYkG71fsz99r6NevnwAglixZop9XXFwsgoKCRPPmzUVJSYkQQojExEQBQKxbt07frm/fvsLBwUEkJydXWQcRNRyeiiVqpJ599tk7vr9nzx4AwPPPP28w/4UXXqjxOh944AHcunULGo2mllX+z65du6BUKjF79myD+S+//DKEENi9e7fB/NDQUAQHB+tft2rVCkOHDsXevXuh1WohhMCWLVswZMgQCCGQmZmpn8LDw5GTk4O4uDiDdU6aNAk2NjYG+wcAV65cuef9q+Dn54fw8PC7ttuyZQsCAwMxfPjwSu/VdtgaKysrzJgxQ//axsYGM2bMwM2bNxEbG1vlMhkZGTh8+DAmT56MVq1a1UkdRFR7DHZEjZSfn98d309OToZCoajUrm3bttUu889f7E2bNgVQforvXiUnJ8PT0xMODg4G8ytOYyYnJxvM9/f3r7SOdu3aoaCgABkZGcjIyEB2djbWrFkDNzc3g2nSpEkAUOn0dH3uX4W7fV0qXL58uUbjzhnD09MTdnZ2BvPatWsHANXexVsRauu6FiKqHV5jR9RI2dra1vk6q7tTUvzj5gZToNPpAABPP/00JkyYUGWbrl27GrxuiP2ry69LdUfMtFptnW2DiEwLgx0RVcnHxwc6nQ6JiYkGR7+MuQu0KrU9Pefj44P9+/cjNzfX4KjduXPn9O//3cWLFyut48KFC2jSpAnc3NwAAA4ODtBqtQgLC6tVTbVRV6cn27Rpg9OnT9+xTcURxezsbIP5/zy6WeH69evIz883OGp34cIFAOV35ValdevWAHDXWoioYfBULBFVqeI6r08++cRg/scff3xP67Wzs6sUNGpi0KBB0Gq1WLFihcH8ZcuWQZIkPProowbzY2JiDK6RS0lJwY4dO/Dwww9DqVRCqVRi5MiR2LJlS5WhJCMjw+gaa6IiNNWmD/5u5MiROHnyJLZt21bpvYojiBV3HP99mBetVos1a9ZUuc6ysjL98CoAUFJSgtWrV8PNzc3gesW/c3NzQ9++fbF27VpcvXq1yjqIqOHwiB0RVSk4OBgjR47E8uXLcevWLf1wJxVHcGp75Ck4OBj79+/H0qVL4enpCT8/P4SEhNx1uSFDhmDAgAGYN28ekpKSEBgYiJ9++gk7duxAREREpWFTOnfujPDwcIPhTgBg4cKF+jbvvvsuDhw4gJCQEEybNg0dO3ZEVlYW4uLisH//fmRlZdVqH+8kKCgISqUSixcvRk5ODlQqFR588EE0b97cqPXMmTMH3333HUaNGoXJkycjODgYWVlZ+P7777Fq1SoEBgaiU6dO6N27N6KiopCVlQUXFxds2LABZWVlVa7T09MTixcvRlJSEtq1a4eNGzciPj4ea9asuePgyB999BHuv/9+dO/eHdOnT4efnx+SkpKwc+dOxMfHG7VfRHSPZLwjl4hkUDE0SUZGRpXz/y4/P1/MnDlTuLi4CHt7ezFs2DBx/vx5AUC8++67d11nVcNtnDt3TvTt21fY2toKAEYNfZKbmyteeukl4enpKaytrYW/v794//33Kw2rAUDMnDlTfPXVV8Lf31+oVCrRrVu3KocYSU9PFzNnzhTe3t7C2tpaeHh4iIEDB4o1a9bo21QMD7J582aDZasa+qMmPv30U9G6dWuhVCoNhh3x8fERgwcPrnKZfw53IoQQt27dErNmzRItW7YUNjY2wsvLS0yYMMFg+JbLly+LsLAwoVKphLu7u5g7d67Yt29flcOddOrUSRw/flyEhoYKtVotfHx8xIoVK2q0z6dPnxbDhw8Xzs7OQq1Wi4CAAPH6668b1S9EdO8kIXisnIhqLj4+Ht26dcNXX32Fp556Su5yqiRJEmbOnFnptC0RkaXjNXZEVK2K55T+3fLly6FQKNC3b18ZKiIiojvhNXZEVK333nsPsbGxGDBgAKysrLB7927s3r0b06dPh7e3d51sQ6vV3vVGBXt7e9jb29fJ9upLYWEhcnJy7tjGxcXFYIBjIqK6xmBHRNXq06cP9u3bh7feegt5eXlo1aoVFixYUKcPd09JSbnroLzz58/HggUL6myb9WHjxo36gY2rc+DAAfTv379hCiKiRonX2BGRrIqKivDrr7/esU3r1q3146WZqhs3biAhIeGObYKDg/VjyxER1QcGOyIiIiILYRanYnU6Ha5fvw4HBwc+VJqIiIgaFSEEcnNz4enpCYXizve9mkWwu379ep1dqE1ERERkjlJSUuDl5XXHNkYHu8OHD+P9999HbGwsbty4gW3btmHYsGF3XObgwYOIjIxEQkICvL298dprr2HixIk13mbFcyFTUlLg6OhobMlEREREZkuj0cDb29vgOdnVMTrY5efnIzAwEJMnT8aIESPu2j4xMRGDBw/Gs88+i6+//hrR0dGYOnUqWrRooX8W5d1UnH51dHRksCMiIqJGqSaXoxkd7B599NFKD9u+k1WrVsHPzw9LliwBAHTo0AG//vorli1bVuNgR0RUF4pKtcjKL0FWfgnyistQVKpFcZlO/29JmQ4CAP66p0z89V/xz9d/rY/3nhGRh5Maj3X1lLsMvXq/xi4mJgZhYWEG88LDwxEREVHtMsXFxSguLta/1mg09VUeEVmQwhItkm7l40pGPhIz83AlIx9Jt/KRkVeMrLwS5Jdo5S6RiCxML1+XxhXs0tLS4O7ubjDP3d0dGo0GhYWFsLW1rbTMokWLsHDhwvoujYjMmBACV7MKcOTyLcQl30Z8SjYuZeThbgfRrBQSXOxs4KC2gtpaCZWVAmprJdTWSlgrJUiQUHG2Q5IACRUvUPE/SJL0t//Xx94Rkblo7WpaT8Uxybtio6KiEBkZqX9dcdEgETVuJWU6xFy5hb0JaTh0PgOp2ZWfZetka43Wbnbwc7VDGzd7+Dazg4eTCi52KrjY2cBRbcVhk4jIYtV7sPPw8EB6errBvPT0dDg6OlZ5tA4AVCoVVCpVfZdGRGZACIG4q7fxXew1/PjnDeQWlenfs1ZK6NaqKXr5uiDI2xldvZ3gZq9icCOiRqveg11oaCh27dplMG/fvn0IDQ2t700TkRnLLy7Dlrhr+PxIEi5n5Ovnu9qr8FBHdzzUsTlC/JrBTmWSJx6IiGRh9CdiXl4eLl26pH+dmJiI+Ph4uLi4oFWrVoiKikJqaiq++OILAMCzzz6LFStW4JVXXsHkyZPx888/Y9OmTdi5c2fd7QURWYys/BJ8+ssVfPV7sv7oXBMbJQZ1aYGR3b3Qy88FSgWPyBERVcXoYHf8+HEMGDBA/7riWrgJEyZg/fr1uHHjBq5evap/38/PDzt37sRLL72EDz/8EF5eXvjss8841AkRGcgpLMXqQ5fx+ZEk/d2rfq52mHSfL0Z094I9j8wREd2VJMxgICaNRgMnJyfk5ORwgGIiC1Om1eHbY1exdN8F3C4oBQB08nTEiwP9EdbBHQoenSOiRs6YHMQ/gYlINrHJtzF36ymcT88FAPg3t8ec8AA81NGdN0AQEdUCgx0RNbi84jJ8sPc8Po9JghCAcxNrRD7UDk/2agUrpULu8oiIzBaDHRE1qLirtxGxIR5XswoAACO7e+G1wR3Q1M5G5sqIiMwfgx0RNQitTmDlgUv4MPoitDqBls62eHdkFzzg7yZ3aUREFoPBjojqXVZ+CV7ccAK/XMwEADwe6Im3hnWGk621zJUREVkWBjsiqlenU3Mw48tYpGYXwtZaibeHd8aI7l5yl0VEZJEY7Iio3uw5fQMvbohHcZkOvs2aYNUzwWjvwSGLiIjqC4MdEdU5IQQ++yUR7+w+CyGA/gFu+HBsN556JSKqZwx2RFSndDqBN388g/VHkgAA40N98MZjHTmMCRFRA2CwI6I6U6bV4ZXv/sTWE6mQJGDeoA6Ycr8fBxsmImogDHZEVCeKy7SY9c0J7DuTDqVCwpJRgRjWraXcZRERNSoMdkR0z4rLtHjuqzj8fO4mbKwU+OTJ7gjr6C53WUREjQ6DHRHdk5IyHWZ+XR7qVFYKrJ3YE/e1dZW7LCKiRolXMxNRrZVpdXjh2zjsP1se6v47gaGOiEhODHZEVCs6ncD/bTmFvQnpsLFS4NPxPXC/P0MdEZGcGOyIyGhCCLy96yy2xF2DUiHhkye7o287PvOViEhuDHZEZLTVh6/gv78mAgDeG9mVN0oQEZkIBjsiMsqe0zfw7u5zAIDXBnfAyGA+95WIyFQw2BFRjZ26loOIjfEAgIl9fDH1gdbyFkRERAYY7IioRtJyijD1iz9QVKpDv3ZueG1wB7lLIiKif2CwI6K7yi8uw5TP/0C6phjt3O3x8ZPd+OxXIiITxE9mIrojnU4gYmM8Eq5r0MzOBv+d0BOOamu5yyIioiow2BHRHb239zz2nSkfq27N+GB4uzSRuyQiIqoGgx0RVWvP6RtYdegyAOD9J7oi2MdF5oqIiOhOGOyIqEqJmfmYs/lPAMD0vq0xNKilzBUREdHdMNgRUSVFpVo891UscovL0NO3KeaEB8hdEhER1QCDHRFV8vr20ziXlgtXexuseLI7rHkHLBGRWeCnNREZ2PRHCjbHXoNCAj4a1w3ujmq5SyIiohpisCMivYTrOXh9x2kAwMsPB6BPG1eZKyIiImMw2BERACC3qBTPfx2H4jIdBrZvjuf6tZG7JCIiMhKDHREBAN7YkYDkWwVo6WyLJaMDoVBIcpdERERGYrAjImw/kYptJ1KhVEj4aFw3ODexkbskIiKqBQY7okYuJasAr20vv65u9oP+CPZpKnNFRERUWwx2RI1YmVaHFzecQF5xGXr4NMXMAbyujojInDHYETViH/98CXFXs+GgssKyMUGw4nh1RERmjZ/iRI3U8aQsfPzzRQDAv4d3hrdLE5krIiKie8VgR9QIaYpKEbExHjoBjOjWks+BJSKyEAx2RI3Qgu8TcO12IVq5NMHCoZ3kLoeIiOpIrYLdypUr4evrC7VajZCQEBw7dqzatuvXr4ckSQaTWs1HFBHJZW9CGrbGpUIhAcvGBMJBbS13SUREVEeMDnYbN25EZGQk5s+fj7i4OAQGBiI8PBw3b96sdhlHR0fcuHFDPyUnJ99T0URUO7fyijF36ykAwPS+bRDs4yJzRUREVJeMDnZLly7FtGnTMGnSJHTs2BGrVq1CkyZNsHbt2mqXkSQJHh4e+snd3f2O2yguLoZGozGYiOjeCCEwb9tp3MovQXsPB7z0kL/cJRERUR0zKtiVlJQgNjYWYWFh/1uBQoGwsDDExMRUu1xeXh58fHzg7e2NoUOHIiEh4Y7bWbRoEZycnPSTt7e3MWUSURW2x6diT0IarBQSlowOhMpKKXdJRERUx4wKdpmZmdBqtZWOuLm7uyMtLa3KZQICArB27Vrs2LEDX331FXQ6Hfr06YNr165Vu52oqCjk5OTop5SUFGPKJKJ/uJFTiDd2lP9B9eJAf3TydJK5IiIiqg9W9b2B0NBQhIaG6l/36dMHHTp0wOrVq/HWW29VuYxKpYJKparv0ogaBSEEXvnuT+QWlSHQywnP9efTJYiILJVRR+xcXV2hVCqRnp5uMD89PR0eHh41Woe1tTW6deuGS5cuGbNpIqqlr49exS8XM6GyUmDJaD5dgojIkhn1CW9jY4Pg4GBER0fr5+l0OkRHRxsclbsTrVaLU6dOoUWLFsZVSkRGS76Vj3d2nQUAvPJIe7Rtbi9zRUREVJ+MPhUbGRmJCRMmoEePHujVqxeWL1+O/Px8TJo0CQAwfvx4tGzZEosWLQIAvPnmm+jduzfatm2L7OxsvP/++0hOTsbUqVPrdk+IyIBWJ/DyppMoKNEixM8Fk/r4yl0SERHVM6OD3ZgxY5CRkYE33ngDaWlpCAoKwp49e/Q3VFy9ehUKxf8OBN6+fRvTpk1DWloamjZtiuDgYBw5cgQdO3asu70goko+++UKjiffhp2NEh+MCoRCIcldEhER1TNJCCHkLuJuNBoNnJyckJOTA0dHR7nLITJ5F9Jz8dhHv6JEq8O7I7pgbK9WcpdERES1ZEwO4lXURBampEyHlzbGo0SrQ/8AN4zpyXEgiYgaCwY7Iguz4ueLSLiugXMTa7w3siskiadgiYgaCwY7IgsSn5KNlQcvAwDeGtoZzR3VMldEREQNicGOyEIUlmgRuSkeWp3AkEBPDAn0lLskIiJqYAx2RBZi8Z5zuJKRj+YOKrw1tJPc5RARkQwY7IgswJFLmVh/JAkAsPiJrnBuYiNvQUREJAsGOyIzpykqxb82nwQAPBnSCgMCmstcERERyYXBjsjMvfnDGVzPKUIrlyaYN6iD3OUQEZGMGOyIzNhPCWn4LvYaJAlYMjoQdiqjHyZDREQWhMGOyExl5hUjauspAMD0vq3R09dF5oqIiEhuDHZEZkgIgXnbTuFWfgkC3B0Q+VA7uUsiIiITwGBHZIY2H7+GvQnpsFZKWDomECorpdwlERGRCWCwIzIzl27mYv73CQCAiLB26OTpJHNFRERkKhjsiMxIUakWs745gcJSLe5v64rn+rWRuyQiIjIhDHZEZmTRrrM4l5aLZnY2WDo6EAqFJHdJRERkQhjsiMzE3oQ0fB6TDKB8aJPmjmqZKyIiIlPDYEdkBq5nF+KV7/4EUD60SX8+XYKIiKrAYEdk4sq0OkRsiEdOYSkCvZzwr4cD5C6JiIhMFIMdkYlbvv8ijiVlwV5lhY/GdYONFX9siYioavwNQWTC9p1Jx4oDlwAAbw/vDJ9mdjJXREREpozBjshEXcnIQ+TGeADAxD6+GBrUUt6CiIjI5DHYEZmgvOIyPPtVLHKLy9DTtynmDe4gd0lERGQGGOyITIxWJxCx4QQupOfBzUGFlU92h7WSP6pERHR3/G1BZGLe3X0W+8/ehI2VAmueCeZ4dUREVGMMdkQmZMOxq/j0l0QAwJJRgejWqqnMFRERkTlhsCMyEdFn0zFv+2kAQESYP4YEespcERERmRsGOyIT8EdSFp7/Og5ancCI7i3x4kB/uUsiIiIzxGBHJLMz1zWYvP4PFJfpMLB9cywe2RWSJMldFhERmSEGOyIZJVzPwZOf/Y7cojL08GmKFbwDloiI7oGV3AUQNVanU3Pw1GdHy58B6+2M/07sCVsbpdxlERGRGWOwI5LB0Su3MO2L49AUlaFbK2d8PrkXHNXWcpdFRERmjsGOqIHtiE/FnM1/okSrQw+fplg3qSccGOqIiKgOMNgRNRCdTmDlgUtYsu8CAODRzh5YNiYIamuefiUiorrBYEfUAG7lFeOlTSdx+EIGAGDq/X6YO6gDFAre/UpERHWHwY6onh04fxNRW04hTVMEtbUCbz7eGaN7estdFhERWSAGO6J6kq4pwsIfErDrVBoAoI2bHT55KhgBHg4yV0ZERJaKwY6ojmXkFmPN4cv46verKCzVQqmQMPk+X7z0UDs0seGPHBER1Z9ajYS6cuVK+Pr6Qq1WIyQkBMeOHbtj+82bN6N9+/ZQq9Xo0qULdu3aVatiiUyVTidwLDEL//fdn7h/8c/49JdEFJZq0a2VM36YdT/mDe7IUEdERPXO6N80GzduRGRkJFatWoWQkBAsX74c4eHhOH/+PJo3b16p/ZEjRzBu3DgsWrQIjz32GL755hsMGzYMcXFx6Ny5c53sBFFDK9PqcO12IeJTsvH7lVv45WImUrML9e8HeTvjxYH+6B/gxseDERFRg5GEEMKYBUJCQtCzZ0+sWLECAKDT6eDt7Y0XXngBr776aqX2Y8aMQX5+Pn788Uf9vN69eyMoKAirVq2qchvFxcUoLi7Wv9ZoNPD29kZOTg4cHR2NKbfGSsp0eH37aaOXEzCq+/63XC0Wq92WarutWm6tQferln1fq20B+cVlyCksxa38EqRkFaBMZ7gme5UVBnXxwMjuXujl58JAR0REdUKj0cDJyalGOcioI3YlJSWIjY1FVFSUfp5CoUBYWBhiYmKqXCYmJgaRkZEG88LDw7F9+/Zqt7No0SIsXLjQmNLumU4IbDye0qDbJPOmtlYgwN0BIa2bIcTPBX3auPKRYEREJCujgl1mZia0Wi3c3d0N5ru7u+PcuXNVLpOWllZl+7S0tGq3ExUVZRAGK47Y1SelQsKc8IBaLVvbAzMSjF+w9tuqxTINuF/3sr3abcv4jdnZKOFkaw3nJjbwadYEHo5qjkNHREQmxSSv5lapVFCpVA26TWulAjMHtG3QbRIRERHVJaPuinV1dYVSqUR6errB/PT0dHh4eFS5jIeHh1HtiYiIiKh2jDpiZ2Njg+DgYERHR2PYsGEAym+eiI6OxqxZs6pcJjQ0FNHR0YiIiNDP27dvH0JDQ2u83YqL5DUajTHlEhEREZm9ivxTo5sGhZE2bNggVCqVWL9+vThz5oyYPn26cHZ2FmlpaUIIIZ555hnx6quv6tv/9ttvwsrKSnzwwQfi7NmzYv78+cLa2lqcOnWqxttMSUkRKL+ZkRMnTpw4ceLEqVFOKSkpd81MRl9jN2bMGGRkZOCNN95AWloagoKCsGfPHv0NElevXoVC8b8zvH369ME333yD1157DXPnzoW/vz+2b99u1Bh2np6eSElJgYODQ70OIVFxk0ZKSkq9DatiDtgP7IMK7Idy7Idy7Af2QQX2Q7mG6gchBHJzc+Hp6XnXtkaPY2fJjBknxpKxH9gHFdgP5dgP5dgP7IMK7IdyptgPtXqkGBERERGZHgY7IiIiIgvBYPc3KpUK8+fPb/Ax9EwN+4F9UIH9UI79UI79wD6owH4oZ4r9wGvsiIiIiCwEj9gRERERWQgGOyIiIiILwWBHREREZCEY7IiIiIgsBIMdERERkYVo1MEuKSkJU6ZMgZ+fH2xtbdGmTRvMnz8fJSUld1yuqKgIM2fORLNmzWBvb4+RI0ciPT29gaque2+//Tb69OmDJk2awNnZuUbLTJw4EZIkGUyPPPJI/RZaz2rTD0IIvPHGG2jRogVsbW0RFhaGixcv1m+h9SwrKwtPPfUUHB0d4ezsjClTpiAvL++Oy/Tv37/S98Ozzz7bQBXXjZUrV8LX1xdqtRohISE4duzYHdtv3rwZ7du3h1qtRpcuXbBr164GqrR+GdMP69evr/R1V6vVDVht3Tt8+DCGDBkCT09PSJKE7du333WZgwcPonv37lCpVGjbti3Wr19f73XWN2P74eDBg5W+FyRJQlpaWsMUXA8WLVqEnj17wsHBAc2bN8ewYcNw/vz5uy4n92dDow52586dg06nw+rVq5GQkIBly5Zh1apVmDt37h2Xe+mll/DDDz9g8+bNOHToEK5fv44RI0Y0UNV1r6SkBKNGjcJzzz1n1HKPPPIIbty4oZ++/fbbeqqwYdSmH9577z189NFHWLVqFY4ePQo7OzuEh4ejqKioHiutX0899RQSEhKwb98+/Pjjjzh8+DCmT59+1+WmTZtm8P3w3nvvNUC1dWPjxo2IjIzE/PnzERcXh8DAQISHh+PmzZtVtj9y5AjGjRuHKVOm4MSJExg2bBiGDRuG06dPN3DldcvYfgAAR0dHg697cnJyA1Zc9/Lz8xEYGIiVK1fWqH1iYiIGDx6MAQMGID4+HhEREZg6dSr27t1bz5XWL2P7ocL58+cNvh+aN29eTxXWv0OHDmHmzJn4/fffsW/fPpSWluLhhx9Gfn5+tcuYxGeDIAPvvfee8PPzq/b97OxsYW1tLTZv3qyfd/bsWQFAxMTENESJ9WbdunXCycmpRm0nTJgghg4dWq/1yKWm/aDT6YSHh4d4//339fOys7OFSqUS3377bT1WWH/OnDkjAIg//vhDP2/37t1CkiSRmppa7XL9+vUTL774YgNUWD969eolZs6cqX+t1WqFp6enWLRoUZXtR48eLQYPHmwwLyQkRMyYMaNe66xvxvaDMZ8Z5giA2LZt2x3bvPLKK6JTp04G88aMGSPCw8PrsbKGVZN+OHDggAAgbt++3SA1yeHmzZsCgDh06FC1bUzhs6FRH7GrSk5ODlxcXKp9PzY2FqWlpQgLC9PPa9++PVq1aoWYmJiGKNFkHDx4EM2bN0dAQACee+453Lp1S+6SGlRiYiLS0tIMvhecnJwQEhJitt8LMTExcHZ2Ro8ePfTzwsLCoFAocPTo0Tsu+/XXX8PV1RWdO3dGVFQUCgoK6rvcOlFSUoLY2FiDr6NCoUBYWFi1X8eYmBiD9gAQHh5utl93oHb9AAB5eXnw8fGBt7c3hg4dioSEhIYo12RY4vfCvQgKCkKLFi3w0EMP4bfffpO7nDqVk5MDAHfMCKbw/WDVYFsyA5cuXcLHH3+MDz74oNo2aWlpsLGxqXQNlru7u1lfS2CsRx55BCNGjICfnx8uX76MuXPn4tFHH0VMTAyUSqXc5TWIiq+3u7u7wXxz/l5IS0urdOrEysoKLi4ud9ynJ598Ej4+PvD09MSff/6J//u//8P58+exdevW+i75nmVmZkKr1Vb5dTx37lyVy6SlpVnU1x2oXT8EBARg7dq16Nq1K3JycvDBBx+gT58+SEhIgJeXV0OULbvqvhc0Gg0KCwtha2srU2UNq0WLFli1ahV69OiB4uJifPbZZ+jfvz+OHj2K7t27y13ePdPpdIiIiMB9992Hzp07V9vOFD4bLPKI3auvvlrlRZx/n/75QZWamopHHnkEo0aNwrRp02SqvO7Upg+MMXbsWDz++OPo0qULhg0bhh9//BF//PEHDh48WHc7UQfqux/MRX33w/Tp0xEeHo4uXbrgqaeewhdffIFt27bh8uXLdbgXZGpCQ0Mxfvx4BAUFoV+/fti6dSvc3NywevVquUujBhYQEIAZM2YgODgYffr0wdq1a9GnTx8sW7ZM7tLqxMyZM3H69Gls2LBB7lLuyiKP2L388suYOHHiHdu0bt1a///r169jwIAB6NOnD9asWXPH5Tw8PFBSUoLs7GyDo3bp6enw8PC4l7LrlLF9cK9at24NV1dXXLp0CQMHDqyz9d6r+uyHiq93eno6WrRooZ+fnp6OoKCgWq2zvtS0Hzw8PCpdKF9WVoasrCyjvr9DQkIAlB8Fb9OmjdH1NiRXV1colcpKd7bf6Wfaw8PDqPbmoDb98E/W1tbo1q0bLl26VB8lmqTqvhccHR0bzdG66vTq1Qu//vqr3GXcs1mzZulvJLvbkWhT+GywyGDn5uYGNze3GrVNTU3FgAEDEBwcjHXr1kGhuPNBzODgYFhbWyM6OhojR44EUH4X0NWrVxEaGnrPtdcVY/qgLly7dg23bt0yCDimoD77wc/PDx4eHoiOjtYHOY1Gg6NHjxp9h3F9q2k/hIaGIjs7G7GxsQgODgYA/Pzzz9DpdPqwVhPx8fEAYHLfD1WxsbFBcHAwoqOjMWzYMADlp12io6Mxa9asKpcJDQ1FdHQ0IiIi9PP27dtnUp8BxqpNP/yTVqvFqVOnMGjQoHqs1LSEhoZWGs7C3L8X6kp8fLxZfAZURwiBF154Adu2bcPBgwfh5+d312VM4rOhwW7TMEHXrl0Tbdu2FQMHDhTXrl0TN27c0E9/bxMQECCOHj2qn/fss8+KVq1aiZ9//lkcP35chIaGitDQUDl2oU4kJyeLEydOiIULFwp7e3tx4sQJceLECZGbm6tvExAQILZu3SqEECI3N1f861//EjExMSIxMVHs379fdO/eXfj7+4uioiK5duOeGdsPQgjx7rvvCmdnZ7Fjxw7x559/iqFDhwo/Pz9RWFgoxy7UiUceeUR069ZNHD16VPz666/C399fjBs3Tv/+P38mLl26JN58801x/PhxkZiYKHbs2CFat24t+vbtK9cuGG3Dhg1CpVKJ9evXizNnzojp06cLZ2dnkZaWJoQQ4plnnhGvvvqqvv1vv/0mrKysxAcffCDOnj0r5s+fL6ytrcWpU6fk2oU6YWw/LFy4UOzdu1dcvnxZxMbGirFjxwq1Wi0SEhLk2oV7lpubq//ZByCWLl0qTpw4IZKTk4UQQrz66qvimWee0be/cuWKaNKkiZgzZ444e/asWLlypVAqlWLPnj1y7UKdMLYfli1bJrZv3y4uXrwoTp06JV588UWhUCjE/v375dqFe/bcc88JJycncfDgQYN8UFBQoG9jip8NjTrYrVu3TgCocqqQmJgoAIgDBw7o5xUWFornn39eNG3aVDRp0kQMHz7cIAyamwkTJlTZB3/fZwBi3bp1QgghCgoKxMMPPyzc3NyEtbW18PHxEdOmTdN/+JsrY/tBiPIhT15//XXh7u4uVCqVGDhwoDh//nzDF1+Hbt26JcaNGyfs7e2Fo6OjmDRpkkG4/efPxNWrV0Xfvn2Fi4uLUKlUom3btmLOnDkiJydHpj2onY8//li0atVK2NjYiF69eonff/9d/16/fv3EhAkTDNpv2rRJtGvXTtjY2IhOnTqJnTt3NnDF9cOYfoiIiNC3dXd3F4MGDRJxcXEyVF13Kobt+OdUsd8TJkwQ/fr1q7RMUFCQsLGxEa1btzb4jDBXxvbD4sWLRZs2bYRarRYuLi6if//+4ueff5an+DpSXT74+9fXFD8bJCGEqM8jgkRERETUMCzyrlgiIiKixojBjoiIiMhCMNgRERERWQgGOyIiIiILwWBHREREZCEY7IiIiIgsBIMdERERkYVgsCMiIiKyEAx2RERERBaCwY6IiIjIQjDYEREREVmI/weNRZfjwKUCrAAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, axs = plt.subplots(nrows=3,sharex=True)\n", + "\n", + "x = np.linspace(-2,2,200)\n", + "y = left_open_tricubic(x)\n", + "axs[0].plot(x,y)\n", + "axs[0].set_title('left_open_tricubic')\n", + "\n", + "x = np.linspace(-2,2,200)\n", + "y = tricubic(x)\n", + "axs[1].plot(x,y)\n", + "axs[1].set_title('tricubic')\n", + "\n", + "x = np.linspace(-2,2,200)\n", + "y = right_open_tricubic(x)\n", + "axs[2].plot(x,y)\n", + "axs[2].set_title('right_open_tricubic')\n", + "\n", + "fig.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#| hide\n", + "### Unit Tests for Edge Cases" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Curve fitting with 4 kernels and polynomials of 2 degree requires at least 12 datapoints.\n", + "Number of kernels will be reduced to 2 kernels.\n" + ] + } + ], + "source": [ + "#| hide\n", + "\n", + "def noisy_1d(x):\n", + " y = np.sin(x)\n", + " y_err = np.random.normal(y,0.5)\n", + " return y + y_err + 0.5 * x\n", + "\n", + "# To few datapoints for choosen number of kernels\n", + "\n", + "x_train = np.linspace(0,15,6)\n", + "y_train = noisy_1d(x_train)\n", + "x_test = np.linspace(0,15,10)\n", + "y_test = LOESSRegression(n_kernels=4, polynomial_degree=2).fit(x_train, y_train).predict(x_test)\n", + "\n", + "# Extrapolation\n", + "\n", + "x_train = np.linspace(0,15,60)\n", + "y_train = noisy_1d(x_train)\n", + "x_test = np.linspace(-10,25,10)\n", + "y_test = LOESSRegression(n_kernels=4, polynomial_degree=2).fit(x_train, y_train).predict(x_test)\n", + "\n", + "\n", + "\n", + "# single datapoint inference\n", + "\n", + "x_train = np.linspace(0,15,100)\n", + "y_train = noisy_1d(x_train)\n", + "x_test = np.linspace(10,10,1)\n", + "y_test = LOESSRegression(n_kernels=4, polynomial_degree=2).fit(x_train, y_train).predict(x_test)\n", + "\n", + "# extrapolation when no other points are interpolated\n", + "\n", + "x_train = np.linspace(0,15,60)\n", + "y_train = y = np.sin(x_train)\n", + "x_test = np.linspace(-2,-1,1)\n", + "y_test = LOESSRegression(n_kernels=4, polynomial_degree=2).fit(x_train, y_train).predict(x_test)\n", + "assert (-2.604 - y_test) < 0.01" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.8.3 ('base')", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/nbdev_nbs/utils.ipynb b/nbdev_nbs/utils.ipynb index 50f7fe2f..6a4704d4 100644 --- a/nbdev_nbs/utils.ipynb +++ b/nbdev_nbs/utils.ipynb @@ -6,7 +6,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| default_exp utils" + "#---#| default_exp utils" ] }, { @@ -15,51 +15,15 @@ "source": [ "# Utils" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "import tqdm\n", - "import os\n", - "import sys\n", - "import pandas as pd\n", - "import itertools\n", - "\n", - "# from alphatims\n", - "def process_bar(iterator, len_iter):\n", - " with tqdm.tqdm(total=len_iter) as bar:\n", - " i = 0\n", - " for i,iter in enumerate(iterator):\n", - " yield iter\n", - " bar.update()\n", - " bar.update(len_iter-i-1)\n", - "\n", - "def _flatten(list_of_lists):\n", - " '''\n", - " Flatten a list of lists\n", - " '''\n", - " return list(\n", - " itertools.chain.from_iterable(list_of_lists)\n", - " )\n", - "\n", - "def explode_multiple_columns(df:pd.DataFrame, columns:list):\n", - " try:\n", - " return df.explode(columns)\n", - " except ValueError:\n", - " # pandas <= 1.2.x?\n", - " print(f'pandas=={pd.__version__} cannot explode multiple columns')\n", - " ret_df = df.explode(columns[0])\n", - " for col in columns[1:]:\n", - " ret_df[col] = _flatten(df[col].values)\n", - " return ret_df" - ] } ], - "metadata": {}, + "metadata": { + "kernelspec": { + "display_name": "Python 3.8.3 ('base')", + "language": "python", + "name": "python3" + } + }, "nbformat": 4, "nbformat_minor": 2 } diff --git a/nbdev_nbs/yaml_utils.ipynb b/nbdev_nbs/yaml_utils.ipynb index bde59645..22fb5c96 100644 --- a/nbdev_nbs/yaml_utils.ipynb +++ b/nbdev_nbs/yaml_utils.ipynb @@ -6,7 +6,7 @@ "metadata": {}, "outputs": [], "source": [ - "#| default_exp yaml_utils" + "#---#| default_exp yaml_utils" ] }, { @@ -15,25 +15,6 @@ "source": [ "# YAML Utils" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "import yaml\n", - "\n", - "def load_yaml(filename)->dict:\n", - " with open(filename) as f:\n", - " settings = yaml.load(f, Loader=yaml.FullLoader)\n", - " return settings\n", - "\n", - "def save_yaml(filename, settings):\n", - " with open(filename, \"w\") as file:\n", - " yaml.dump(settings, file)" - ] } ], "metadata": { diff --git a/release/one_click_linux_gui/control b/release/one_click_linux_gui/control index 8aa42ab0..041d98b7 100644 --- a/release/one_click_linux_gui/control +++ b/release/one_click_linux_gui/control @@ -1,5 +1,5 @@ Package: AlphaBase -Version: 0.2.0 +Version: 0.2.1 Architecture: all Maintainer: Mann Labs Description: AlphaBase diff --git a/release/one_click_linux_gui/create_installer_linux.sh b/release/one_click_linux_gui/create_installer_linux.sh index 34ee741c..4adc2e57 100644 --- a/release/one_click_linux_gui/create_installer_linux.sh +++ b/release/one_click_linux_gui/create_installer_linux.sh @@ -17,7 +17,7 @@ python setup.py sdist bdist_wheel # Setting up the local package cd release/one_click_linux_gui # Make sure you include the required extra packages and always use the stable or very-stable options! -pip install "../../dist/alphabase-0.2.0-py3-none-any.whl[stable]" +pip install "../../dist/alphabase-0.2.1-py3-none-any.whl[stable]" # Creating the stand-alone pyinstaller folder pip install pyinstaller diff --git a/release/one_click_macos_gui/Info.plist b/release/one_click_macos_gui/Info.plist index ee23608e..02167502 100644 --- a/release/one_click_macos_gui/Info.plist +++ b/release/one_click_macos_gui/Info.plist @@ -9,9 +9,9 @@ CFBundleIconFile alpha_logo.icns CFBundleIdentifier - alphabase.0.2.0 + alphabase.0.2.1 CFBundleShortVersionString - 0.2.0 + 0.2.1 CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/release/one_click_macos_gui/create_installer_macos.sh b/release/one_click_macos_gui/create_installer_macos.sh index 8d8161eb..d91f4c8f 100644 --- a/release/one_click_macos_gui/create_installer_macos.sh +++ b/release/one_click_macos_gui/create_installer_macos.sh @@ -20,7 +20,7 @@ python setup.py sdist bdist_wheel # Setting up the local package cd release/one_click_macos_gui -pip install "../../dist/alphabase-0.2.0-py3-none-any.whl[stable]" +pip install "../../dist/alphabase-0.2.1-py3-none-any.whl[stable]" # Creating the stand-alone pyinstaller folder pip install pyinstaller @@ -40,5 +40,5 @@ cp ../../LICENSE.txt Resources/LICENSE.txt cp ../logos/alpha_logo.png Resources/alpha_logo.png chmod 777 scripts/* -pkgbuild --root dist/alphabase --identifier de.mpg.biochem.alphabase.app --version 0.2.0 --install-location /Applications/AlphaBase.app --scripts scripts AlphaBase.pkg +pkgbuild --root dist/alphabase --identifier de.mpg.biochem.alphabase.app --version 0.2.1 --install-location /Applications/AlphaBase.app --scripts scripts AlphaBase.pkg productbuild --distribution distribution.xml --resources Resources --package-path AlphaBase.pkg dist/alphabase_gui_installer_macos.pkg diff --git a/release/one_click_macos_gui/distribution.xml b/release/one_click_macos_gui/distribution.xml index 1732b11d..da2a19cb 100644 --- a/release/one_click_macos_gui/distribution.xml +++ b/release/one_click_macos_gui/distribution.xml @@ -1,6 +1,6 @@ - AlphaBase 0.2.0 + AlphaBase 0.2.1 diff --git a/release/one_click_windows_gui/alphabase_innoinstaller.iss b/release/one_click_windows_gui/alphabase_innoinstaller.iss index adb9cc19..fcc24f3e 100644 --- a/release/one_click_windows_gui/alphabase_innoinstaller.iss +++ b/release/one_click_windows_gui/alphabase_innoinstaller.iss @@ -2,7 +2,7 @@ ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! #define MyAppName "AlphaBase" -#define MyAppVersion "0.2.0" +#define MyAppVersion "0.2.1" #define MyAppPublisher "Max Planck Institute of Biochemistry and the University of Copenhagen, Mann Labs" #define MyAppURL "https://github.com/MannLabs/alphabase" #define MyAppExeName "alphabase_gui.exe" diff --git a/release/one_click_windows_gui/create_installer_windows.sh b/release/one_click_windows_gui/create_installer_windows.sh index 27629d8c..4fae8de6 100644 --- a/release/one_click_windows_gui/create_installer_windows.sh +++ b/release/one_click_windows_gui/create_installer_windows.sh @@ -17,7 +17,7 @@ python setup.py sdist bdist_wheel # Setting up the local package cd release/one_click_windows_gui # Make sure you include the required extra packages and always use the stable or very-stable options! -pip install "../../dist/alphabase-0.2.0-py3-none-any.whl[stable]" +pip install "../../dist/alphabase-0.2.1-py3-none-any.whl[stable]" # Creating the stand-alone pyinstaller folder pip install pyinstaller diff --git a/requirements/requirements.txt b/requirements/requirements.txt index beaeccae..a41d47df 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -7,4 +7,6 @@ contextlib2 mmh3 biopython psutil -tqdm \ No newline at end of file +tqdm +scikit-learn +regex \ No newline at end of file diff --git a/requirements/requirements_development.txt b/requirements/requirements_development.txt index 22a41174..a0d89550 100644 --- a/requirements/requirements_development.txt +++ b/requirements/requirements_development.txt @@ -1,13 +1,22 @@ jupyter jupyter_contrib_nbextensions -autodocsumm -sphinx-rtd-theme twine bumpversion pipdeptree ipykernel nbdev pyteomics +scikit-learn +matplotlib + +#sphinx +autodocsumm +myst_parser +sphinx +nbsphinx +jinja2 +contextfilter +furo tqdm psutil @@ -19,5 +28,6 @@ pandas h5py contextlib2 mmh3 +regex pydivsufsort pyahocorasick \ No newline at end of file diff --git a/settings.ini b/settings.ini index f990f899..cc0ee73c 100644 --- a/settings.ini +++ b/settings.ini @@ -1,16 +1,15 @@ [DEFAULT] -# All sections below are required unless otherwise specified. -# See https://github.com/fastai/nbdev/blob/master/settings.ini for examples. +# Legacy. Used by nbdev_test. ### Python library ### repo = alphabase lib_name = alphabase -version = 0.2.0 +version = 0.2.1 min_python = 3.7 license = apache2 ### nbdev ### -doc_path = docs +doc_path = _docs lib_path = %(lib_name)s nbs_path = nbdev_nbs recursive = True diff --git a/setup.py b/setup.py index 86df90bb..cedec034 100644 --- a/setup.py +++ b/setup.py @@ -8,10 +8,10 @@ import alphabase as package2install #nbdev2 -from configparser import ConfigParser -nbdev_config = ConfigParser(delimiters=['=']) -nbdev_config.read('settings.ini') -nbdev_cfg = nbdev_config['DEFAULT'] +# from configparser import ConfigParser +# nbdev_config = ConfigParser(delimiters=['=']) +# nbdev_config.read('settings.ini') +# nbdev_cfg = nbdev_config['DEFAULT'] def get_long_description(): with open("README.md", "r") as readme_file: @@ -37,8 +37,11 @@ def get_requirements(): extra_requirements[extra] = [] for line in requirements_file: extra_requirements[extra_stable].append(line) + # conditional req like: "pywin32==xxx; sys_platform=='win32'" + line, *conditions = line.split(';') requirement, *comparison = re.split("[><=~!]", line) - requirement == requirement.strip() + requirement = requirement.strip() + requirement = ";".join([requirement] + conditions) extra_requirements[extra].append(requirement) requirements = extra_requirements.pop("") return requirements, extra_requirements @@ -63,7 +66,7 @@ def create_pip_wheel(): include_package_data=True, entry_points={ "console_scripts": package2install.__console_scripts__, - 'nbdev': [f'{nbdev_cfg.get("lib_path")}={nbdev_cfg.get("lib_path")}._modidx:d'], + # 'nbdev': [f'{nbdev_cfg.get("lib_path")}={nbdev_cfg.get("lib_path")}._modidx:d'], }, install_requires=requirements + [ # TODO Remove hardcoded requirement?