From 4818da9a081f1704a63af4c8a48851ed045de0f7 Mon Sep 17 00:00:00 2001 From: RalfG Date: Tue, 5 Dec 2023 13:43:11 +0100 Subject: [PATCH 1/5] Add start for docs --- .gitignore | 4 + CONTRIBUTING.rst | 55 ++++ README.md | 85 ++++- docs/.readthedocs.yaml | 21 ++ docs/LICENSE.txt | 435 ++++++++++++++++++++++++++ docs/_static/css/custom.css | 20 ++ docs/conf.py | 74 +++++ docs/contributing.rst | 1 + docs/implementations/index.rst | 11 + docs/implementations/json/index.rst | 36 +++ docs/implementations/python/api.rst | 7 + docs/implementations/python/index.rst | 20 ++ docs/index.rst | 13 + docs/requirements.txt | 7 + docs/specification/index.rst | 5 + 15 files changed, 786 insertions(+), 8 deletions(-) create mode 100644 .gitignore create mode 100644 CONTRIBUTING.rst create mode 100644 docs/.readthedocs.yaml create mode 100644 docs/LICENSE.txt create mode 100644 docs/_static/css/custom.css create mode 100644 docs/conf.py create mode 100644 docs/contributing.rst create mode 100644 docs/implementations/index.rst create mode 100644 docs/implementations/json/index.rst create mode 100644 docs/implementations/python/api.rst create mode 100644 docs/implementations/python/index.rst create mode 100644 docs/index.rst create mode 100644 docs/requirements.txt create mode 100644 docs/specification/index.rst diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0726389 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.venv/ +.github/ +docs/_build/ +specification/annotation-schema.md diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst new file mode 100644 index 0000000..fb9e4f5 --- /dev/null +++ b/CONTRIBUTING.rst @@ -0,0 +1,55 @@ +############ +Contributing +############ + +This document briefly describes how to contribute to +`mzPAF `_. + + + +Before you begin +################ + +If you have an idea for a feature, use case to add or an approach for a bugfix, +you are welcome to communicate it with the community by opening a +thread in `GitHub Issues `_. + + + +Documentation local setup +######################### + +To work on the documentation and get a live preview, install the requirements +and run ``sphinx-autobuild``: + +.. code-block:: sh + + pip install -r ./docs/requirements.txt + sphinx-autobuild ./docs/ ./docs/_build/ + +Then browse to http://localhost:8000 to watch the live preview. + + + +How to contribute +################# + +- Fork `mzPAF `_ on GitHub to + make your changes. +- Commit and push your changes to your + `fork `_. +- Ensure that the tests and documentation (both Python docstrings and files in + ``/docs/``) have been updated according to your changes. Python + docstrings are formatted in the + `numpydoc style `_. +- Open a + `pull request `_ + with these changes. You pull request message ideally should include: + + - A description of why the changes should be made. + - A description of the implementation of the changes. + - A description of how to test the changes. + +- The pull request should pass all the continuous integration tests which are + automatically run by + `GitHub Actions `_. diff --git a/README.md b/README.md index f504428..16bf026 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,86 @@ # mzPAF Peak Annotation Format -The mzPAF proposed standard is a specification for a fragment ion peak annotation format for mass spectra, focused on peptides. This provides for a standardized format for describing the origin of fragment ions to be used in spectral libraries, other formats that aim to describe fragment ions, and software tools that annotate fragment ions. +## About -The main home page for mzPAF is at the PSI web site: https://psidev.info/mzPAF +The mzPAF proposed standard is a specification for a fragment ion peak annotation format for mass spectra, focused on +peptides. This provides for a standardized format for describing the origin of fragment ions to be used in spectral +libraries, other formats that aim to describe fragment ions, and software tools that annotate fragment ions. -# Status +- Official mzPAF homepage: [psidev.info/mzPAF](https://psidev.info/mzPAF) +- mzPAF documentation: [mzpaf.readthedocs.io](https://mzpaf.readthedocs.io) -Updated: 2023-02-25 -The specification has been submitted to the PSI Document Process and is undergoing review. It will take several months starting January 2023 to undergo rigorous review before potentially becoming a PSI standard. +## Specification status -# Available Materials -- The current DRAFT specification: https://github.com/HUPO-PSI/mzPAF/blob/main/specification/mzPAF_specification_v1.0-draft10.docx?raw=true +Updated: 2023-09-01 + +The specification has been resubmitted to the PSI Document Process and is undergoing final community review. Ratification to formally become a PSI standard is anticipated near the end of 2023. + +Your comments and suggestions are still very much welcome. Please submit an issue at the repo to +provide your feedback and send an e-mail to the HUPO-PSI editor Sylvie Ricard-Blum +(sylvie.ricard-blum@univ-lyon1.fr). + + +## In short + +- mzPAF is a single string of characters, case sensitive, without length limit +- Multiple possible explanations are separated with a comma +- Deltas of observed – theoretical *m/z* values are prefixed with a slash (`/`) +- Confidences can be provided for different annotations prefixed with an asterisk (`*`) + +The basic format of each annotation is: + +``` +annotation1/delta,annotation2/delta,... +``` + +or: + +``` +annotation1/delta*confidence,annotation2/delta*confidence,... +``` + +For example: + +``` +b2-H2O/3.2ppm,b4-H2O^2/3.2ppm +``` + +or: + +``` +b2-H2O/3.2ppm*0.75,b4-H2O^2/3.2ppm*0.25 +``` + +mzPAF supports: + +- Annotations of multiple analytes: `1@y12/0.13,2@b9-NH3/0.23` +- Mass deltas in ppm instead of *m/z* unit: `y1/-1.4ppm` +- Confidence levels per annotation: `y1/-1.4ppm*0.75` +- Advanced ion notation: `[ion type](neutral loss)(isotope)(adduct type)(charge)`, e.g.: `y4-H2O+2i[M+H+Na]^2`: + - Ion types: + - Peptide ion series (a, b, c, x, y, z): `y4` + - Unknown ions: `?` + - Immonium ions: `IY` + - Internal fragment ions: `m3:6` + - Intact precursor ions: `p^2` + - A set of reference ions: `r[TMT127N]` + - Named compounds: `_{Urocanic Acid}` + - Chemical formulas: `f{C16H22O}` + - Smiles: `s{CN=C=O}[M+H]` + - Embedded ProForma annotations: `0@b2{LC[Carbamidomethyl]}` + - Neutral gains and losses: `y2+CO-H2O` + - Isotopes: `y2+2i` + - Adduct types: `y2[M+H]` + - Charge states: `^2` +- Multiple peaks per annotation: `&y7/-0.001` and `y7/0.000*0.95` + +Read the [full specificiation](https://mzpaf.readthedocs.io/specification) for more details and +examples. + + +### Available Materials +- The current DRAFT specification: https://github.com/HUPO-PSI/mzPAF/blob/main/specification/mzPAF_specification_v1.0-draft14.docx?raw=true - The GitHub repo associated with mzPAF: https://github.com/HUPO-PSI/mzPAF -- The GitHub repo assocated with the related mzSpecLib standard: https://github.com/HUPO-PSI/mzSpecLib +- The GitHub repo associated with the related mzSpecLib standard: https://github.com/HUPO-PSI/mzSpecLib diff --git a/docs/.readthedocs.yaml b/docs/.readthedocs.yaml new file mode 100644 index 0000000..31c93e2 --- /dev/null +++ b/docs/.readthedocs.yaml @@ -0,0 +1,21 @@ +version: 2 + +build: + os: ubuntu-22.04 + tools: + python: "3.11" + +sphinx: + configuration: docs/conf.py + builder: dirhtml + +formats: + - pdf + - epub + +python: + install: + - method: pip + path: implementations/python + extra_requirements: + - docs diff --git a/docs/LICENSE.txt b/docs/LICENSE.txt new file mode 100644 index 0000000..1eaa3b0 --- /dev/null +++ b/docs/LICENSE.txt @@ -0,0 +1,435 @@ +Attribution-NonCommercial-ShareAlike 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More_considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International +Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution-NonCommercial-ShareAlike 4.0 International Public License +("Public License"). To the extent this Public License may be +interpreted as a contract, You are granted the Licensed Rights in +consideration of Your acceptance of these terms and conditions, and the +Licensor grants You such rights in consideration of benefits the +Licensor receives from making the Licensed Material available under +these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. BY-NC-SA Compatible License means a license listed at + creativecommons.org/compatiblelicenses, approved by Creative + Commons as essentially the equivalent of this Public License. + + d. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + e. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + f. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + g. License Elements means the license attributes listed in the name + of a Creative Commons Public License. The License Elements of this + Public License are Attribution, NonCommercial, and ShareAlike. + + h. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + i. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + j. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + k. NonCommercial means not primarily intended for or directed towards + commercial advantage or monetary compensation. For purposes of + this Public License, the exchange of the Licensed Material for + other material subject to Copyright and Similar Rights by digital + file-sharing or similar means is NonCommercial provided there is + no payment of monetary compensation in connection with the + exchange. + + l. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + m. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + n. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for + NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. Additional offer from the Licensor -- Adapted Material. + Every recipient of Adapted Material from You + automatically receives an offer from the Licensor to + exercise the Licensed Rights in the Adapted Material + under the conditions of the Adapter's License You apply. + + c. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties, including when + the Licensed Material is used other than for NonCommercial + purposes. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + b. ShareAlike. + + In addition to the conditions in Section 3(a), if You Share + Adapted Material You produce, the following conditions also apply. + + 1. The Adapter's License You apply must be a Creative Commons + license with the same License Elements, this version or + later, or a BY-NC-SA Compatible License. + + 2. You must include the text of, or the URI or hyperlink to, the + Adapter's License You apply. You may satisfy this condition + in any reasonable manner based on the medium, means, and + context in which You Share Adapted Material. + + 3. You may not offer or impose any additional or different terms + or conditions on, or apply any Effective Technological + Measures to, Adapted Material that restrict exercise of the + rights granted under the Adapter's License You apply. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database for NonCommercial purposes + only; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material, + including for purposes of Section 3(b); and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + +======================================================================= + +Creative Commons is not a party to its public licenses. +Notwithstanding, Creative Commons may elect to apply one of its public +licenses to material it publishes and in those instances will be +considered the "Licensor." Except for the limited purpose of indicating +that material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the public +licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/docs/_static/css/custom.css b/docs/_static/css/custom.css new file mode 100644 index 0000000..01f2deb --- /dev/null +++ b/docs/_static/css/custom.css @@ -0,0 +1,20 @@ +@import url('https://fonts.googleapis.com/css2?family=Open+Sans&family=Roboto+Slab:wght@500&display=swap'); + +html { + --pst-font-family-base: 'Open Sans', sans-serif; + --pst-font-family-heading: 'Roboto Slab', serif; + --pst-font-weight-heading: 500; +} + +html[data-theme="light"] { + --pst-color-primary: #3b5880; +} + +html[data-theme="dark"] { + --pst-color-primary: #5c87c2; + +} + +a:visited { + color: var(--pst-color-link); +} diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..78c58bf --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,74 @@ +"""Configuration file for the Sphinx documentation builder.""" + +# Scripts +import json +import jsonschema2md + +def get_jsonschema_docs(input_json, output_markdown): + """Generate markdown documentation from a JSON schema.""" + parser = jsonschema2md.Parser() + with open(input_json, encoding="utf-8") as f_in: + output_md = parser.parse_schema(json.load(f_in)) + + with open(output_markdown, "w", encoding="utf-8") as f_out: + f_out.writelines(output_md) + +get_jsonschema_docs( + "../specification/annotation-schema.json", + "../specification/annotation-schema.md" +) + + +# Project information +project = "mzPAF" +author = "HUPO-PSI" +github_project_url = "https://github.com/HUPO-PSI/mzPAF" +github_doc_root = "https://github.com/HUPO-PSI/mzPAF/tree/master/docs" + +# General configuration +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.autosectionlabel", + "sphinx.ext.autosummary", + "sphinx.ext.napoleon", + "sphinx.ext.intersphinx", + "sphinx_click.ext", + "myst_parser", +] +source_suffix = [".rst", ".md"] +master_doc = "index" +exclude_patterns = ["_build"] + +# Options for HTML output +html_theme = "pydata_sphinx_theme" +html_static_path = ["_static"] +html_css_files = ["css/custom.css"] +html_theme_options = { + "icon_links": [ + { + "name": "GitHub", + "url": "https://github.com/HUPO-PSI/mzPAF", + "icon": "fa-brands fa-github", + "type": "fontawesome", + } + ] +} + +# Autodoc options +autodoc_default_options = {"members": True, "show-inheritance": True} +autodoc_member_order = "bysource" +autodoc_typehints = "description" +autoclass_content = "init" + +# Intersphinx options +intersphinx_mapping = { + "python": ("https://docs.python.org/3", None), + "psims": ("https://mobiusklein.github.io/psims/docs/build/html/", None), + "pyteomics": ("https://pyteomics.readthedocs.io/en/stable/", None), +} + + +def setup(app): + config = {"enable_eval_rst": True} # noqa: F841 + + diff --git a/docs/contributing.rst b/docs/contributing.rst new file mode 100644 index 0000000..a021d3e --- /dev/null +++ b/docs/contributing.rst @@ -0,0 +1 @@ +.. include:: ../CONTRIBUTING.rst diff --git a/docs/implementations/index.rst b/docs/implementations/index.rst new file mode 100644 index 0000000..ebb51a9 --- /dev/null +++ b/docs/implementations/index.rst @@ -0,0 +1,11 @@ +############### +Implementations +############### + +.. toctree:: + :caption: Contents + :maxdepth: 2 + :glob: + + */index + diff --git a/docs/implementations/json/index.rst b/docs/implementations/json/index.rst new file mode 100644 index 0000000..c4ec07d --- /dev/null +++ b/docs/implementations/json/index.rst @@ -0,0 +1,36 @@ +########### +JSON Schema +########### + +About +===== + +Instead of representing mzPAF as a single string, it can alternatively be expressed as a JSON +object. This format is more compatible for inter-program communication, especially through web +APIs. You can find the JSON schema for mzPAF on GitHub via the following link: + +https://raw.githubusercontent.com/HUPO-PSI/mzPAF/main/specification/annotation-schema.json + +Replace ``main`` in the URL with the desired version tag to access the schema for a particular +version. + +Examples +======== + +.. literalinclude:: ../../../specification/annotation-example-1.json + :language: json + +.. literalinclude:: ../../../specification/annotation-example-2.json + :language: json + +.. literalinclude:: ../../../specification/annotation-example-3.json + :language: json + + + +Full schema documentation +========================= + +.. include:: ../../../specification/annotation-schema.md + :parser: myst_parser.sphinx_ + :start-line: 4 diff --git a/docs/implementations/python/api.rst b/docs/implementations/python/api.rst new file mode 100644 index 0000000..f88fe3c --- /dev/null +++ b/docs/implementations/python/api.rst @@ -0,0 +1,7 @@ +********** +Python API +********** + +.. automodule:: mzpaf + :members: + :imported-members: diff --git a/docs/implementations/python/index.rst b/docs/implementations/python/index.rst new file mode 100644 index 0000000..fb7e568 --- /dev/null +++ b/docs/implementations/python/index.rst @@ -0,0 +1,20 @@ +##################### +Python implementation +##################### + +About +===== + +.. include:: ../../../implementations/python/README.md + :parser: myst_parser.sphinx_ + + +Full API documentation +====================== + +.. toctree:: + :caption: Contents + :maxdepth: 2 + :glob: + + * diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..b9b2c5a --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,13 @@ +.. include:: ../README.md + :parser: myst_parser.sphinx_ + +.. toctree:: + :caption: About + :hidden: + :includehidden: + :glob: + + Home + specification/index + implementations/index + contributing diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..62e5ab6 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,7 @@ +sphinx +pydata-sphinx-theme +numpydoc +sphinx_click +myst-parser +sphinx-autobuild +jsonschema2md diff --git a/docs/specification/index.rst b/docs/specification/index.rst new file mode 100644 index 0000000..18f0806 --- /dev/null +++ b/docs/specification/index.rst @@ -0,0 +1,5 @@ +#################### +Format specification +#################### + +[TODO: Add when released] From ba5f0a03a5aa2219b361cd5d880c9a21bb25bef9 Mon Sep 17 00:00:00 2001 From: RalfG Date: Fri, 8 Dec 2023 18:15:39 +0100 Subject: [PATCH 2/5] More documentation --- README.md | 98 ++++++++++++------- docs/_static/img/lark-railroad-diagram.svg | 1 + docs/conf.py | 30 ++++++ docs/implementations/lark/index.rst | 17 ++++ docs/implementations/python/api.rst | 12 +++ docs/implementations/regex/index.rst | 25 +++++ docs/index.rst | 6 +- docs/requirements.txt | 1 + docs/specification/index.rst | 20 +++- docs/specification/reference-molecules.rst | 35 +++++++ specification/reference_data/README.md | 17 ++-- .../reference_data/reference_mol_to_md.py | 7 -- .../reference_molecule_schema.md | 34 +++++++ 13 files changed, 246 insertions(+), 57 deletions(-) create mode 100644 docs/_static/img/lark-railroad-diagram.svg create mode 100644 docs/implementations/lark/index.rst create mode 100644 docs/implementations/regex/index.rst create mode 100644 docs/specification/reference-molecules.rst delete mode 100644 specification/reference_data/reference_mol_to_md.py create mode 100644 specification/reference_data/reference_molecule_schema.md diff --git a/README.md b/README.md index 16bf026..7a8a674 100644 --- a/README.md +++ b/README.md @@ -9,24 +9,12 @@ libraries, other formats that aim to describe fragment ions, and software tools - Official mzPAF homepage: [psidev.info/mzPAF](https://psidev.info/mzPAF) - mzPAF documentation: [mzpaf.readthedocs.io](https://mzpaf.readthedocs.io) - -## Specification status - -Updated: 2023-09-01 - -The specification has been resubmitted to the PSI Document Process and is undergoing final community review. Ratification to formally become a PSI standard is anticipated near the end of 2023. - -Your comments and suggestions are still very much welcome. Please submit an issue at the repo to -provide your feedback and send an e-mail to the HUPO-PSI editor Sylvie Ricard-Blum -(sylvie.ricard-blum@univ-lyon1.fr). - - ## In short - mzPAF is a single string of characters, case sensitive, without length limit -- Multiple possible explanations are separated with a comma -- Deltas of observed – theoretical *m/z* values are prefixed with a slash (`/`) -- Confidences can be provided for different annotations prefixed with an asterisk (`*`) +- Multiple possible explanations are comma-separated +- Deltas of observed – theoretical _m/z_ values are prefixed with a slash (`/`) +- Confidence of annotations are prefixed with an asterisk (`*`) The basic format of each annotation is: @@ -55,32 +43,70 @@ b2-H2O/3.2ppm*0.75,b4-H2O^2/3.2ppm*0.25 mzPAF supports: - Annotations of multiple analytes: `1@y12/0.13,2@b9-NH3/0.23` -- Mass deltas in ppm instead of *m/z* unit: `y1/-1.4ppm` +- Mass deltas in ppm instead of _m/z_ unit: `y1/-1.4ppm` - Confidence levels per annotation: `y1/-1.4ppm*0.75` - Advanced ion notation: `[ion type](neutral loss)(isotope)(adduct type)(charge)`, e.g.: `y4-H2O+2i[M+H+Na]^2`: - - Ion types: - - Peptide ion series (a, b, c, x, y, z): `y4` - - Unknown ions: `?` - - Immonium ions: `IY` - - Internal fragment ions: `m3:6` - - Intact precursor ions: `p^2` - - A set of reference ions: `r[TMT127N]` - - Named compounds: `_{Urocanic Acid}` - - Chemical formulas: `f{C16H22O}` - - Smiles: `s{CN=C=O}[M+H]` - - Embedded ProForma annotations: `0@b2{LC[Carbamidomethyl]}` - - Neutral gains and losses: `y2+CO-H2O` - - Isotopes: `y2+2i` - - Adduct types: `y2[M+H]` - - Charge states: `^2` + - Ion types: + - Peptide ion series (a, b, c, x, y, z): `y4` + - Unknown ions: `?` + - Immonium ions: `IY` + - Internal fragment ions: `m3:6` + - Intact precursor ions: `p^2` + - A set of reference ions: `r[TMT127N]` + - Named compounds: `_{Urocanic Acid}` + - Chemical formulas: `f{C16H22O}` + - Smiles: `s{CN=C=O}[M+H]` + - Embedded ProForma annotations: `0@b2{LC[Carbamidomethyl]}` + - Neutral gains and losses: `y2+CO-H2O` + - Isotopes: `y2+2i` + - Adduct types: `y2[M+H]` + - Charge states: `^2` - Multiple peaks per annotation: `&y7/-0.001` and `y7/0.000*0.95` -Read the [full specificiation](https://mzpaf.readthedocs.io/specification) for more details and -examples. +Read the +[full DRAFT specificiation](https://github.com/HUPO-PSI/mzPAF/blob/main/specification/mzPAF_specification_v1.0-draft14.docx?raw=true) +for more details and examples. + +## Getting started + +### mzPAF in Python + +The [mzPAF Python package](https://mzpaf.readthedocs.io/en/latest/implementations/python/) can +parse mzPAF strings into their components, convert to the JSON representation, or serialize back +to an mzPAF string. + +```python +>>> import mzpaf +>>> annotations = mzpaf.parse_annotation("b2-H2O/3.2ppm*0.75,b4-H2O^2/3.2ppm*0.25") +>>> print(annotations[0].to_json()) +{'neutral_losses': ['-H2O'], 'isotope': 0, 'adducts': [], 'charge': 1, 'analyte_reference': None, 'mass_error': {'value': 3.2, 'unit': 'ppm'}, 'confidence': 0.75, 'molecule_description': {'series_label': 'peptide', 'series': 'b', 'position': 2, 'sequence': None}} +>>> print(anno[0].serialize()) +'b2-H2O/3.2ppm*0.75' +``` +Learn more at the +[package documentation](https://mzpaf.readthedocs.io/en/latest/implementations/python/). + +### mzPAF regular expressions + +[todo] + +### mzPAF Lark grammar + +[todo] + +## Specification status + +Updated: 2023-09-01 + +The specification has been resubmitted to the PSI Document Process and is undergoing final +community review. Ratification to formally become a PSI standard is anticipated near the end of 2023. + +Your comments and suggestions are still very much welcome. Please submit an issue at the repo to +provide your feedback and send an e-mail to the HUPO-PSI editor [Sylvie Ricard-Blum](mailto:sylvie.ricard-blum@univ-lyon1.fr). + +### Links -### Available Materials -- The current DRAFT specification: https://github.com/HUPO-PSI/mzPAF/blob/main/specification/mzPAF_specification_v1.0-draft14.docx?raw=true - The GitHub repo associated with mzPAF: https://github.com/HUPO-PSI/mzPAF - The GitHub repo associated with the related mzSpecLib standard: https://github.com/HUPO-PSI/mzSpecLib - +- HUPO-PSI homepage: https://www.psidev.info/ diff --git a/docs/_static/img/lark-railroad-diagram.svg b/docs/_static/img/lark-railroad-diagram.svg new file mode 100644 index 0000000..339ad25 --- /dev/null +++ b/docs/_static/img/lark-railroad-diagram.svg @@ -0,0 +1 @@ + & Is Auxiliary ORDINAL @ Analyte Identifier a b c x y z ORDINAL { ANY ProForma 2.0 Sequence } Peptide Ion m ORDINAL : ORDINAL { ANY ProForma 2.0 Sequence } Internal Peptide Ion I AMINO_ACID [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] Immonium Ion r [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] Reporter Ion p Precursor Ion f { ATOM_COUNTATOM_COUNTATOM_COUNT ATOM_COUNTATOM_COUNTATOM_COUNT ATOM_COUNTATOM_COUNTATOM_COUNT } Formula Ion _ { CHARACTER } Named Compound s { /[^}]/ } SMILES Ion ? DIGIT Unknown Ion Ion Type SIGN ATOM_COUNTATOM_COUNTATOM_COUNT ATOM_COUNTATOM_COUNTATOM_COUNT ATOM_COUNTATOM_COUNTATOM_COUNT [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] Neutral Loss(es) SIGN ORDINAL i Isotope [ M SIGN ATOM_COUNTATOM_COUNTATOM_COUNT ATOM_COUNTATOM_COUNTATOM_COUNT ATOM_COUNTATOM_COUNTATOM_COUNT ] Adducts ^ ORDINAL Charge State / NUMBER ppm Mass Error * NUMBER Confidence Estimate \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 78c58bf..df4cf5b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -2,7 +2,12 @@ # Scripts import json +import shutil +from pathlib import Path + import jsonschema2md +import pandas as pd + def get_jsonschema_docs(input_json, output_markdown): """Generate markdown documentation from a JSON schema.""" @@ -13,10 +18,34 @@ def get_jsonschema_docs(input_json, output_markdown): with open(output_markdown, "w", encoding="utf-8") as f_out: f_out.writelines(output_md) + +def get_reference_molecules_md(input_json, output_markdown): + """Generate a markdown table of reference molecules.""" + df = pd.read_json(input_json).T + buf = df.to_markdown().replace(' nan ', ' ') + with open(output_markdown, 'wt') as fh: + fh.write(buf) + + get_jsonschema_docs( "../specification/annotation-schema.json", "../specification/annotation-schema.md" ) +get_jsonschema_docs( + "../specification/reference_data/reference_molecule_schema.json", + "../specification/reference_data/reference_molecule_schema.md" +) + +get_reference_molecules_md( + "../specification/reference_data/reference_molecules.json", + "../specification/reference_data/reference_molecules.md" +) + +if not Path("_static/img/lark-railroad-diagram.svg").exists(): + shutil.copy( + "../specification/grammars/schema_images/Annotation.svg", + "_static/img/lark-railroad-diagram.svg" + ) # Project information @@ -65,6 +94,7 @@ def get_jsonschema_docs(input_json, output_markdown): "python": ("https://docs.python.org/3", None), "psims": ("https://mobiusklein.github.io/psims/docs/build/html/", None), "pyteomics": ("https://pyteomics.readthedocs.io/en/stable/", None), + "mzspeclib": ("https://mzspeclib.readthedocs.io/en/latest/", None), } diff --git a/docs/implementations/lark/index.rst b/docs/implementations/lark/index.rst new file mode 100644 index 0000000..a309c39 --- /dev/null +++ b/docs/implementations/lark/index.rst @@ -0,0 +1,17 @@ +############ +Lark grammar +############ + + +About +===== + +[todo] + + +Railroad diagram +================ + +.. figure:: ../../_static/img/lark-railroad-diagram.svg + :alt: Lark grammar + diff --git a/docs/implementations/python/api.rst b/docs/implementations/python/api.rst index f88fe3c..c8e34d7 100644 --- a/docs/implementations/python/api.rst +++ b/docs/implementations/python/api.rst @@ -2,6 +2,18 @@ Python API ********** +.. manually documented as parse_annotation is undocumented (returned by the AnnotationStringParser + class) + +.. function:: mzpaf.parse_annotation(annotation_string: str) + + Parses an mzPAF string into a list of ion annotations. + + :param annotation_string: mzPAF string with peak annotations. + :type annotation_string: str + :returns: A list of annotations. + :rtype: list[mzpaf.IonAnnotationBase] + .. automodule:: mzpaf :members: :imported-members: diff --git a/docs/implementations/regex/index.rst b/docs/implementations/regex/index.rst new file mode 100644 index 0000000..8178b3e --- /dev/null +++ b/docs/implementations/regex/index.rst @@ -0,0 +1,25 @@ +################### +Regular expressions +################### + +mzPAF has been defined in several regular expression dialects. + +.. tip:: + + Regex101.com is a great tool to test regular expressions. Try out the mzPAF regex there: + `regex101.com/r/gDPlJu/1 `_. + +Python +====== + +.. literalinclude:: ../../../specification/grammars/regex_sre.py + :language: python + :linenos: + + +Javascript ECMA +=============== + +.. literalinclude:: ../../../specification/grammars/regex_ecma.js + :language: javascript + :linenos: diff --git a/docs/index.rst b/docs/index.rst index b9b2c5a..da495cf 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -8,6 +8,6 @@ :glob: Home - specification/index - implementations/index - contributing + Specification + Implementations + Contributing diff --git a/docs/requirements.txt b/docs/requirements.txt index 62e5ab6..7ee5714 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -5,3 +5,4 @@ sphinx_click myst-parser sphinx-autobuild jsonschema2md +pandas diff --git a/docs/specification/index.rst b/docs/specification/index.rst index 18f0806..3fc076a 100644 --- a/docs/specification/index.rst +++ b/docs/specification/index.rst @@ -1,5 +1,17 @@ -#################### -Format specification -#################### +###################### +Specification document +###################### + +.. toctree:: + :hidden: + :glob: + + Specification document + ./* + +.. + TODO: Add when released + +The latest draft of the specification can be found on +`GitHub `_. -[TODO: Add when released] diff --git a/docs/specification/reference-molecules.rst b/docs/specification/reference-molecules.rst new file mode 100644 index 0000000..8efce1e --- /dev/null +++ b/docs/specification/reference-molecules.rst @@ -0,0 +1,35 @@ +################### +Reference molecules +################### + +About +===== + +.. include:: ../../specification/reference_data/README.md + :parser: myst_parser.sphinx_ + :start-line: 2 + :end-line: -1 +.. + skip including title and last line with reference to this page + +See :ref:`Reference molecule ions` in the specification document for more information. + + +Reference molecule table +======================== + +The following analytes can be annotated as reference molecules with the ``r`` prefix and the +listed name between square brackets (e.g. ``r[TMT127N]``). + +.. include:: ../../specification/reference_data/reference_molecules.md + :parser: myst_parser.sphinx_ + + +JSON schema +=========== + +The ``reference_molecules.json`` file is defined by the following schema: + +.. include:: ../../specification/reference_data/reference_molecule_schema.md + :parser: myst_parser.sphinx_ + :start-line: 3 diff --git a/specification/reference_data/README.md b/specification/reference_data/README.md index 66ee22a..4bd14a4 100644 --- a/specification/reference_data/README.md +++ b/specification/reference_data/README.md @@ -1,13 +1,16 @@ # mzPAF specification reference data files -The mzPAF specification uses these files as auxiliary reference data so that enumerated values can be extended without altering the specification document. +The mzPAF specification uses `specification/reference_data/reference_molecules.json` as auxiliary +reference data. In this way, the set of reference molecules can be extended without updating the +specification document itself. -- reference_molecules.json - Easily software parsable list of "reference molecules" often seen in peptide fragmentation spectra, but - not normal peptide fragments, including isobaric labeling reagent related molecules, monosaccharides, nucleotides, etc. These - molecules may be inidividual charged ions (typically protonated), or may be used as neutral losses as appropriate. +The following files are available: -- reference_molecules.md - Human-readable markdown tabular version of reference_molecules.json +- `reference_molecules.json`: Software parsable list of "reference molecules" often seen in + peptide fragmentation spectra, but not normal peptide fragments. This includes isobaric labeling + reagent related molecules, monosaccharides, nucleotides, etc. These molecules may be individual + charged ions (typically protonated), or may be used as neutral losses as appropriate. -- reference_molecule_schema.json - JSON schema for reference_molecules.json +- `reference_molecule_schema.json`: JSON schema defining the structure of the JSON file -- reference_mol_to_md.py - Python script to transform reference_molecules.json into a markdown table \ No newline at end of file +A human-readable table with all reference molecules is available on https://mzpaf.readthedocs.io. diff --git a/specification/reference_data/reference_mol_to_md.py b/specification/reference_data/reference_mol_to_md.py deleted file mode 100644 index 8d9005a..0000000 --- a/specification/reference_data/reference_mol_to_md.py +++ /dev/null @@ -1,7 +0,0 @@ -import pandas as pd - -df = pd.read_json("reference_molecules.json").T -buf = df.to_markdown().replace(' nan ', ' ') - -with open('./reference_molecules.md', 'wt') as fh: - fh.write(buf) \ No newline at end of file diff --git a/specification/reference_data/reference_molecule_schema.md b/specification/reference_data/reference_molecule_schema.md new file mode 100644 index 0000000..8e99c95 --- /dev/null +++ b/specification/reference_data/reference_molecule_schema.md @@ -0,0 +1,34 @@ +# HUPO-PSI mzSpecLib reference molecule and ion list + +*Describe reference molecules or ions found in spectral libraries* + +## Pattern Properties + +- **`.{1,}`**: Refer to *[#/definitions/molecule](#definitions/molecule)*. +## Definitions + +- **`molecule`** *(object)*: A single molecule that may be present as a reporter ion or signature ion, or be a component of a neutral loss. + - **`name`** *(string)*: The formal name for this molecule by which it should be referenced. + - **`cv_term`** *(array)* + - **Items** *(string)* + - **`neutral_mass`** *(number)*: The neutral mass of the molecule not including any charge or charge carrier. + - **`molecule_type`** *(string)*: A categorical label for this molecule. + + Examples: + ```json + "monosaccharide" + ``` + + ```json + "reporter" + ``` + + ```json + "reporter+balance" + ``` + + - **`ion_mz`** *(number)*: The m/z of the molecule if it is expected to be reasonably different from the uncharged version. + - **`chemical_formula`** *(string)*: The elemental formula of the neutral molecule. + - **`ion_chemical_formula`** *(string)*: The chemical formula of the charged molecule. + - **`references`** *(array)*: An array of sources and references describing this entity. + - **Items** *(string)* From 4fcf3d804aace3c7dc138c8994a926ed147bd7ad Mon Sep 17 00:00:00 2001 From: RalfG Date: Mon, 11 Nov 2024 14:35:18 +0100 Subject: [PATCH 3/5] Merge branch 'main' of https://github.com/HUPO-PSI/mzPAF into add-sphinx-docs --- .gitignore | 1 + Makefile | 6 + README.md | 39 +-- docs/.gitignore | 1 + docs/conf.py | 2 - docs/implementations/python/api.rst | 17 +- docs/implementations/python/examples.rst | 14 + docs/specification/index.rst | 5 +- implementations/python/mzpaf/__init__.py | 2 +- implementations/python/mzpaf/annotation.py | 246 ++++++++++++++++-- .../mzpaf/data/reference_molecules.json | 181 +++++++++++-- implementations/python/mzpaf/reference.py | 8 +- implementations/python/setup.py | 21 +- .../python/tests/test_annotations.py | 7 +- specification/annotation-schema.json | 2 +- specification/grammars/annotation.lark | 8 +- specification/grammars/grammar.py | 159 +++++------ specification/grammars/regex_ecma.js | 2 +- specification/grammars/regex_sre.py | 13 +- .../grammars/schema_images/Annotation.svg | 2 +- .../mzPAF_specification_v1.0-draft15.docx | Bin 0 -> 5635375 bytes .../mzPAF_specification_v1.0-draft15.pdf | Bin 0 -> 564222 bytes .../reference_data/reference_molecules.json | 181 +++++++++++-- .../reference_data/reference_molecules.md | 119 +++++---- 24 files changed, 769 insertions(+), 267 deletions(-) create mode 100644 Makefile create mode 100644 docs/.gitignore create mode 100644 docs/implementations/python/examples.rst create mode 100644 specification/mzPAF_specification_v1.0-draft15.docx create mode 100644 specification/mzPAF_specification_v1.0-draft15.pdf diff --git a/.gitignore b/.gitignore index 0726389..22b5c14 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.python-version .venv/ .github/ docs/_build/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..31dc404 --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ + +all: publish-references + +publish-references: + cp ./specification/reference_data/reference_molecules.json ./implementations/python/mzpaf/data/reference_molecules.json + cd ./specification/reference_data/ && python reference_mol_to_md.py \ No newline at end of file diff --git a/README.md b/README.md index 7a8a674..126e38e 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,21 @@ ## About -The mzPAF proposed standard is a specification for a fragment ion peak annotation format for mass spectra, focused on -peptides. This provides for a standardized format for describing the origin of fragment ions to be used in spectral -libraries, other formats that aim to describe fragment ions, and software tools that annotate fragment ions. +mzPAF is a specification for a fragment ion peak annotation format for mass spectra, focused on +peptides. This provides for a standardized format for describing the origin of fragment ions to be +used in spectral libraries, other formats that aim to describe fragment ions, and software tools +that annotate fragment ions. - Official mzPAF homepage: [psidev.info/mzPAF](https://psidev.info/mzPAF) - mzPAF documentation: [mzpaf.readthedocs.io](https://mzpaf.readthedocs.io) +## Status + +_Updated: 2024-10-15_ + +The specification has been resubmitted to the PSI Document Process and is undergoing final +community review. It is anticipated to become a formal PSI standard near the end of 2024. + ## In short - mzPAF is a single string of characters, case sensitive, without length limit @@ -89,24 +97,19 @@ Learn more at the ### mzPAF regular expressions -[todo] - -### mzPAF Lark grammar +The mzPAF specification includes regular expressions for parsing mzPAF strings. These can be used +in any programming language that supports regular expressions. -[todo] - -## Specification status - -Updated: 2023-09-01 +Learn more at the +[mzPAF regex documentation](https://mzpaf.readthedocs.io/en/latest/implementations/regex/). -The specification has been resubmitted to the PSI Document Process and is undergoing final -community review. Ratification to formally become a PSI standard is anticipated near the end of 2023. +### mzPAF Lark grammar -Your comments and suggestions are still very much welcome. Please submit an issue at the repo to -provide your feedback and send an e-mail to the HUPO-PSI editor [Sylvie Ricard-Blum](mailto:sylvie.ricard-blum@univ-lyon1.fr). +mzPAF has also been defined as a +[Lark grammar](https://mzpaf.readthedocs.io/en/latest/implementations/lark/). ### Links -- The GitHub repo associated with mzPAF: https://github.com/HUPO-PSI/mzPAF -- The GitHub repo associated with the related mzSpecLib standard: https://github.com/HUPO-PSI/mzSpecLib -- HUPO-PSI homepage: https://www.psidev.info/ +- The mzPAF GitHub repo: [github.com/HUPO-PSI/mzPAF](https://github.com/HUPO-PSI/mzPAF) +- The GitHub repo for the related mzSpecLib standard: [github.com/HUPO-PSI/mzSpecLib](https://github.com/HUPO-PSI/mzSpecLib) +- HUPO-PSI homepage: [psidev.info](https://www.psidev.info/) diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..9c5f578 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +_build \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index df4cf5b..5aa2081 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -100,5 +100,3 @@ def get_reference_molecules_md(input_json, output_markdown): def setup(app): config = {"enable_eval_rst": True} # noqa: F841 - - diff --git a/docs/implementations/python/api.rst b/docs/implementations/python/api.rst index c8e34d7..860b993 100644 --- a/docs/implementations/python/api.rst +++ b/docs/implementations/python/api.rst @@ -2,18 +2,13 @@ Python API ********** -.. manually documented as parse_annotation is undocumented (returned by the AnnotationStringParser - class) +.. automodule:: mzpaf + :members: + :imported-members: -.. function:: mzpaf.parse_annotation(annotation_string: str) - Parses an mzPAF string into a list of ion annotations. + .. manually documented as parse_annotation is undocumented - :param annotation_string: mzPAF string with peak annotations. - :type annotation_string: str - :returns: A list of annotations. - :rtype: list[mzpaf.IonAnnotationBase] + .. autofunction:: parse_annotation -.. automodule:: mzpaf - :members: - :imported-members: + Parse a string into one or more :class:`IonAnnotationBase` instances. diff --git a/docs/implementations/python/examples.rst b/docs/implementations/python/examples.rst new file mode 100644 index 0000000..25f2162 --- /dev/null +++ b/docs/implementations/python/examples.rst @@ -0,0 +1,14 @@ +************* +Example Usage +************* + +.. code-block:: python + + import mzpaf + + annotations: list[mzpaf.IonAnnotationBase] = mzpaf.parse_annotation("y1") + + annot: mzpaf.PeptideFragmentIonAnnotation = annotation[0] + assert annot.series == 'y' + assert annot.position == 1 + assert annot.charge == 1 \ No newline at end of file diff --git a/docs/specification/index.rst b/docs/specification/index.rst index 3fc076a..bba8ec3 100644 --- a/docs/specification/index.rst +++ b/docs/specification/index.rst @@ -12,6 +12,5 @@ Specification document .. TODO: Add when released -The latest draft of the specification can be found on -`GitHub `_. - +The mzPAF specification drafts can be found on +`GitHub `_. diff --git a/implementations/python/mzpaf/__init__.py b/implementations/python/mzpaf/__init__.py index c23ab9d..f82dc77 100644 --- a/implementations/python/mzpaf/__init__.py +++ b/implementations/python/mzpaf/__init__.py @@ -13,4 +13,4 @@ "PrecursorIonAnnotation", "ReferenceIonAnnotation", "NamedCompoundIonAnnotation", "FormulaAnnotation", "SMILESAnnotation", "Unannotated", "MassError", "InvalidAnnotation", "parse_annotation" -] \ No newline at end of file +] diff --git a/implementations/python/mzpaf/annotation.py b/implementations/python/mzpaf/annotation.py index 33d048f..b135d1f 100644 --- a/implementations/python/mzpaf/annotation.py +++ b/implementations/python/mzpaf/annotation.py @@ -5,23 +5,31 @@ and serializing. """ import re +from enum import Flag, auto as enauto +from dataclasses import dataclass from sys import intern from typing import Any, List, Optional, Pattern, Dict, Tuple, Union import warnings try: - from pyteomics.proforma import ProForma + from pyteomics.mass import Composition +except ImportError: + Composition = None +try: + from pyteomics.proforma import (ProForma, FormulaModification, UnimodModification) except ImportError: ProForma = None + FormulaModification = None from .reference import ReferenceMolecule JSONDict = Dict[str, Union[List, Dict, int, float, str, bool, None]] -annotation_pattern = re.compile(r""" +annotation_pattern = re.compile( + r""" ^(?P&)? (?:(?P\d+)@)? - (?:(?:(?P[axbycz]\.?)(?P\d+)(?:\{(?P.+)\})?)| + (?:(?:(?P(?:da|db|wa|wb)|[axbyczdwv]\.?)(?P\d+)(?:\{(?P.+)\})?)| (?P[m](?P\d+):(?P\d+)(?:\{(?P.+)\})?)| (?Pp)| (:?I(?P[ARNDCEQGHKMFPSTWYVIL])(?:\[(?P(?:[^\]]+))\])?)| @@ -30,7 +38,7 @@ (?P[^\]]+) \]) ))| - (?:f\{(?P[A-Za-z0-9]+)\})| + (?:f\{(?P[A-Za-z0-9\[\]]+)\})| (?:_\{ (?P[^\{\}\s,/]+) \})| @@ -41,7 +49,7 @@ (?:(?:[A-Z][A-Za-z0-9]*)| (?:\[ (?: - (?:[A-Za-z0-9:\.]+) + (?:[A-Za-z0-9:\.]+)(?:\[(?:[A-Za-z0-9\.:\-\ ]+)\])? ) \]) ) @@ -51,12 +59,23 @@ (?:\^(?P[+-]?\d+))? (?:/(?P[+-]?\d+(?:\.\d+)?)(?Pppm)?)? (?:\*(?P\d*(?:\.\d+)?))? -""", re.X) +""", + re.X, +) -# At the time of first writing, this pattern could be translated into the equivalent -# ECMAScript compliant regex: -# ^(?&)?(?:(?\d+)@)?(?:(?:(?[axbycz]\.?)(?\d+)(?:\{(?.+)\})?)|(?[m](?\d+):(?\d+)(?:\{(?.+)\})?)|(?p)|(:?I(?[ARNDCEQGHKMFPSTWYVIL])(?:\[(?(?:[^\]]+))\])?)|(?r(?:(?:\[(?[^\]]+)\])))|(?:f\{(?[A-Za-z0-9]+)\})|(?:_\{(?[^\{\}\s,\/]+)\})|(?:s\{(?[^\}]+)\})|(?:(?\?)(?\d+)?))(?(?:[+-]\d*(?:(?:[A-Z][A-Za-z0-9]*)|(?:\[(?:(?:[A-Za-z0-9:\.]+))\])))+)?(?:(?[+-]\d*)i)?(?:\[(?M(:?[+-]\d*[A-Z][A-Za-z0-9]*)+)\])?(?:\^(?[+-]?\d+))?(?:\/(?[+-]?\d+(?:\.\d+)?)(?ppm)?)?(?:\*(?\d*(?:\.\d+)?))? -# Line breaks not introduced to preserve syntactic correctness. + +neutral_loss_pattern = re.compile( + r"""\s*(?P(?:(?P[+-])?\s*(?P\d*)\s* + (?:(?P[A-Z][A-Za-z0-9]*)| + (?P\[ + (?: + (?:[A-Za-z0-9:\.]+)(?:\[(?:[A-Za-z0-9\.:\-\ ]+)\])? + ) + \]) + ) +))""", + re.X, +) def _sre_to_ecma(pattern): @@ -121,6 +140,8 @@ def combine_formula(tokens: List[str], leading_sign: bool = False) -> str: """ if not tokens: return '' + if not isinstance(tokens[0], str): + tokens = [str(t) for t in tokens] if not tokens[0].startswith("-") and leading_sign: out = ['+' + tokens[0]] else: @@ -133,10 +154,142 @@ def combine_formula(tokens: List[str], leading_sign: bool = False) -> str: return ''.join(out) +class NeutralNameType(Flag): + """:class:`NeutralName` classification""" + + Reference = enauto() + Formula = enauto() + BracedName = enauto() + Unknown = enauto() + + +@dataclass +class NeutralName(object): + """ + Describe an entity that may appear in the neutral loss list. + + Attributes + ---------- + name : str + The name of the neutral loss which may be a formula or braced name + denoting either a "reference molecule" or a UNIMOD name + delta_type : :class:`NeutralNameType` + The kind of thing :attr:`name` denotes + coefficient : int + A signed multiplicative coefficient of the entity + """ + + name: str + delta_type: NeutralNameType = NeutralNameType.Unknown + coefficient: int = 1 + + def __post_init__(self): + self.delta_type = self._infer_type() + + def format_name(self, leading_sign: bool = True) -> str: + name = self.name + if self.delta_type == NeutralNameType.Reference or self.delta_type == NeutralNameType.BracedName: + name = f"[{name}]" + if self.coefficient >= 0 and leading_sign: + if self.coefficient > 1: + return f'+{self.coefficient}{name}' + else: + return f"+{name}" + elif self.coefficient < 0: + if self.coefficient < -1: + return f"{self.coefficient}{name}" + else: + return f"-{name}" + else: + if self.coefficient > 1: + return f"{self.coefficient}{name}" + else: + return f"{name}" + + def __str__(self): + return self.format_name() + + def _infer_type(self): + if self.name.startswith('[') and self.name.endswith(']'): + inner_name = self.name = self.name[1:-1] + if ReferenceMolecule.is_reference(inner_name): + tp = NeutralNameType.Reference + else: + tp = NeutralNameType.BracedName + self.name = inner_name + return tp + else: + return NeutralNameType.Formula + + def mass(self) -> float: + """ + Calculcate the neutral mass. + + This may involve loading the UNIMOD controlled vocabulary from a remote + source. See :mod:`pyteomics.proforma` for more information. + """ + mass: float = 0.0 + if self.delta_type == NeutralNameType.Formula: + mass = FormulaModification(self.name).mass + elif self.delta_type == NeutralNameType.Reference: + mass = ReferenceMolecule.get(self.name[1:-1]).neutral_mass + elif self.delta_type == NeutralNameType.BracedName: + mass = UnimodModification(self.name[1:-1]).mass + else: + raise ValueError(f"Cannot interpret {self.name} with type {self.delta_type}") + return self.coefficient * mass + + def __eq__(self, other): + if other is None: + return False + if isinstance(other, str): + if other.startswith("+"): + return self.format_name(True) + else: + return self.format_name(False) == other + return self.name == other.name and self.coefficient == other.coefficient + + @classmethod + def parse(cls, string: str) -> List['NeutralName']: + """ + Parse a string of expressions into a list of :class:`NeutralName` using the tokenizer + from the main parser. + """ + if not string: + return [] + names = [] + for match in neutral_loss_pattern.finditer(string): + groups = match.groupdict() + coef = int(groups['coefficient'] or 1) + sign = groups['sign'] or '+' + if sign == '-': + coef = -1 * coef + names.append(NeutralName(groups["formula"] or groups["braced_name"], coefficient=coef)) + return names + + @classmethod + def combine(cls, tokens: List["NeutralName"], leading_sign: bool) -> str: + """ + Combine a list of :class:`NeutralName` into an expression string that is compatible + with :meth:`parse`. + """ + if not tokens: + return "" + if tokens[0].coefficient >= 0 and leading_sign: + out = [tokens[0].format_name(leading_sign=leading_sign)] + else: + out = [tokens[0].format_name(leading_sign=False)] + for token in tokens[1:]: + out.append(token.format_name(leading_sign=True)) + return "".join(out) + + class MassError(object): """ Represent the mass error of a peak annotation. + Attributes + ---------- unit : str The unit of the mass error, may be Da (daltons) or ppm (parts-per-million) mass_error : float @@ -255,7 +408,7 @@ class IonAnnotationBase(object, metaclass=_SeriesLabelSubclassRegisteringMeta): isotope: int adducts: List charge: int - analyte_reference: str + analyte_reference: Optional[int] mass_error: MassError confidence: float rest: Any @@ -308,7 +461,7 @@ def serialize(self) -> str: parts.append(f"{self.analyte_reference}@") parts.append(self._format_ion()) if self.neutral_losses: - parts.append(combine_formula( + parts.append(NeutralName.combine( self.neutral_losses, leading_sign=True)) if self.isotope != 0: sign = "+" if self.isotope > 0 else "-" @@ -351,9 +504,9 @@ def to_json(self, exclude_missing=False) -> JSONDict: ------- dict """ - #TODO: When neutral losses and adducts are formalized types, convert to string/JSON here + # TODO: When neutral losses and adducts are formalized types, convert to string/JSON here d = {} - skips = ('series', 'rest', 'is_auxiliary') + skips = ('series', 'rest', 'is_auxiliary', 'neutral_losses') for key in IonAnnotationBase.__slots__: if key in skips: continue @@ -363,18 +516,29 @@ def to_json(self, exclude_missing=False) -> JSONDict: value = getattr(self, key) if (value is not None) or not exclude_missing: d[key] = value + d['neutral_losses'] = [str(s) for s in self.neutral_losses] d['molecule_description'] = self._molecule_description() # if d['analyte_reference'] is None: # d['analyte_reference'] = return d def _populate_from_dict(self, data) -> 'IonAnnotationBase': - #TODO: When neutral losses and adducts are formalized types, parse from string here + # TODO: When neutral losses and adducts are formalized types, parse from string here for key, value in data.items(): if key == 'molecule_description': continue elif key == 'mass_error' and value is not None: self.mass_error = MassError(value['value'], value['unit']) + elif key == "neutral_losses" and value is not None: + if isinstance(value, str): + self.neutral_losses = NeutralName.parse(value) + elif isinstance(value, (list, tuple)): + self.neutral_losses = [] + for tok in value: + self.neutral_losses.extend(NeutralName.parse(tok)) + else: + self.neutral_losses = [] + warnings.warn(f"Failed to coerce {value} to neutral losses") else: setattr(self, key, value) self.rest = None @@ -719,6 +883,11 @@ def _populate_from_dict(self, data): self.formula = descr['formula'] return self + def to_composition(self) -> "Composition": + if Composition is None: + raise ImportError("Cannot use `to_composition` without `pyteomics`") + return FormulaModification(self.formula).resolve()['composition'] + class SMILESAnnotation(IonAnnotationBase): __slots__ = ("smiles", ) @@ -844,12 +1013,37 @@ def int_or_sign(string: str) -> int: class AnnotationStringParser(object): + """ + An annotation string parser using a specific parser pattern. + + This class organizes the parsing of common and type-specific components of a + string into one or more peak annotations. + + Instances are :class:`Callable`, with :obj:`parse_annotation` being the reference + parser. + """ + pattern: Pattern def __init__(self, pattern): self.pattern = pattern - def __call__(self, annotation_string: str, *, wrap_errors=False, **kwargs) -> List[IonAnnotationBase]: + def __call__(self, annotation_string: str, *, wrap_errors: bool = False, **kwargs) -> List[IonAnnotationBase]: + """ + Parse a string into one or more :class:`IonAnnotationBase` instances. + + Parameters + ---------- + annotation_string : str + The string to be parsed + wrap_errors : bool, optional + Whether or not to capture parsing errors as :class:`InvalidAnnotation` or not. Defaults to :const:`False`. + + Returns + ------- + list[:class:`IonAnnotationBase`] : + The annotations parsed + """ try: return self.parse_annotation(annotation_string, **kwargs) except ValueError as err: @@ -889,7 +1083,8 @@ def _coerce_analyte_reference(self, data: Dict[str, str]) -> str: return data.get("analyte_reference", '1') def _coerce_neutral_losses(self, data: Dict[str, str]) -> List: - return tokenize_signed_symbol_list(data.get("neutral_losses")) + tokens = NeutralName.parse(data.get("neutral_losses", '')) + return tokens def _coerce_mass_error(self, data: Dict[str, str]) -> MassError: mass_error = data.get("mass_error") @@ -908,6 +1103,22 @@ def _coerce_confidence(self, data: Dict[str, str]) -> float: return confidence def parse_annotation(self, annotation_string: str, **kwargs) -> List[IonAnnotationBase]: + """ + Parse a string into one or more :class:`IonAnnotationBase` instances. + + Parameters + ---------- + annotation_string : str + The string to be parsed + **kwargs + Passed to the :meth:`_dispatch` which in turn creates :class:`IonAnnotationBase` + instances + + Returns + ------- + list[:class:`IonAnnotationBase`] : + The annotations parsed + """ if not annotation_string: return [] @@ -1073,4 +1284,5 @@ def _dispatch_smiles(self, data, adducts, charge, isotope, neutral_losses, analy mass_error, confidence) +#: The reference parser parse_annotation = AnnotationStringParser(annotation_pattern) diff --git a/implementations/python/mzpaf/data/reference_molecules.json b/implementations/python/mzpaf/data/reference_molecules.json index e162be2..b4ac0b6 100644 --- a/implementations/python/mzpaf/data/reference_molecules.json +++ b/implementations/python/mzpaf/data/reference_molecules.json @@ -1,254 +1,383 @@ { - "Hex": { - "molecule_type": "monosaccharide", - "neutral_mass": 162.0528234185, - "chemical_formula": "C6H10O5" - }, - "HexNAc": { - "molecule_type": "monosaccharide", - "neutral_mass": 203.07937251951, - "chemical_formula": "C8H13N1O5" - }, - "dHex": { - "molecule_type": "monosaccharide", - "neutral_mass": 146.05790879894, - "chemical_formula": "C6H10O4" - }, - "NeuAc": { - "molecule_type": "monosaccharide", - "neutral_mass": 291.09541650647, - "chemical_formula": "C11H17N1O8" - }, - "NeuGc": { - "molecule_type": "monosaccharide", - "neutral_mass": 307.09033112603, - "chemical_formula": "C11H17N1O9" - }, "TMT126": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C8N1H15", "ion_mz": 126.127726 }, "TMT127N": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C8[15N1]H15", "ion_mz": 127.124761 }, "TMT127C": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C7[13C1]N1H15", "ion_mz": 127.131081 }, "TMT128N": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C7[13C1][15N1]H15", "ion_mz": 128.128116 }, "TMT128C": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C6[13C2]N1H15", "ion_mz": 128.134436 }, "TMT129N": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C6[13C2][15N1]H15", "ion_mz": 129.131471 }, "TMT129C": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C5[13C3]N1H15", "ion_mz": 129.13779 }, "TMT130N": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C5[13C3][15N1]H15", "ion_mz": 130.134825 }, "TMT130C": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C4[13C4]N1H15", "ion_mz": 130.141145 }, "TMT131N": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C4[13C4][15N1]H15", "ion_mz": 131.13818 }, "TMT131C": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C3[13C5]N1H15", "ion_mz": 131.1445 }, "TMT132N": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C3[13C5][15N1]H15", "ion_mz": 132.141535 }, "TMT132C": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C2[13C6]N1H15", "ion_mz": 122.147855 }, "TMT133N": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C2[13C6][15N1]H15", "ion_mz": 133.14489 }, "TMT133C": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C1[13C7]N1H15", "ion_mz": 133.15121 }, "TMT134N": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C1[13C7][15N1]H15", "ion_mz": 134.148245 }, "TMT134C": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "[13C8]N1H15", "ion_mz": 134.154565 }, "TMT135N": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "[13C8][15N1]H15", "ion_mz": 135.1516 }, "TMTzero": { "label_type": "TMTzero", "molecule_type": "reporter+balance", + "chemical_formula": "C12H20N2O2", "neutral_mass": 224.152478, "ion_mz": 225.15975447 }, "TMTpro_zero": { "label_type": "TMTpro_zero", "molecule_type": "reporter+balance", + "chemical_formula": "C15H25N3O3", "neutral_mass": 295.189592, "ion_mz": 296.1968685 }, "TMT2plex": { "label_type": "TMT2plex", "molecule_type": "reporter+balance", + "chemical_formula": "C11[13C1]H20N2O2", "neutral_mass": 225.155833, "ion_mz": 226.16310947 }, "TMT6plex": { "label_type": "TMT6plex", "molecule_type": "reporter+balance", + "chemical_formula": "C8[13C5]H20N1[15N1]O2", "neutral_mass": 229.162932, "ion_mz": 230.17020847 }, "TMTpro": { "label_type": "TMTpro", "molecule_type": "reporter+balance", + "chemical_formula": "C8[13C7]H25[15N2]N1O3", "neutral_mass": 304.207146, "ion_mz": 305.21442247 }, "iTRAQ113": { "label_type": "iTRAQ", "molecule_type": "reporter", + "chemical_formula": "C6N2H12", "ion_mz": 113.1078 }, "iTRAQ114": { "label_type": "iTRAQ", "molecule_type": "reporter", + "chemical_formula": "C5[13C1]N2H12", "ion_mz": 114.1112 }, "iTRAQ115": { "label_type": "iTRAQ", "molecule_type": "reporter", + "chemical_formula": "C5[13C1]N1[15N1]H12", "ion_mz": 115.1082 }, "iTRAQ116": { "label_type": "iTRAQ", "molecule_type": "reporter", + "chemical_formula": "C4[13C2]N1[15N1]H12", "ion_mz": 116.1116 }, "iTRAQ117": { "label_type": "iTRAQ", "molecule_type": "reporter", + "chemical_formula": "C3[13C3]N1[15N1]H12", "ion_mz": 117.1149 }, "iTRAQ118": { "label_type": "iTRAQ", "molecule_type": "reporter", + "chemical_formula": "C3[13C3][15N2]H12", "ion_mz": 118.112 }, "iTRAQ119": { "label_type": "iTRAQ", "molecule_type": "reporter", + "chemical_formula": "C2[13C4][15N2]H12", "ion_mz": 119.1153 }, "iTRAQ121": { "label_type": "iTRAQ", "molecule_type": "reporter", + "chemical_formula": "[13C6][15N2]H12", "ion_mz": 121.122 }, "iTRAQ4plex": { "label_type": "iTRAQ4plex", "molecule_type": "reporter+balance", + "chemical_formula": "C4[13C3]N1[15N1]O1H12", "neutral_mass": 144.102063, "ion_mz": 145.10933947 }, "iTRAQ8plex": { "label_type": "iTRAQ8plex", "molecule_type": "reporter+balance", + "chemical_formula": "C7[13C7]N3[15N1]O3H24", "neutral_mass": 304.205360, "ion_mz": 305.21263647 }, "TMT126-ETD": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C7N1H15", "ion_mz": 114.127725 }, "TMT127N-ETD": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C7[15N1]H15", "ion_mz": 115.12476 }, "TMT127C-ETD": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C6[13C1]N1H15", "ion_mz": 114.127725 }, "TMT128N-ETD": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C6[13C1][15N1]H15", "ion_mz": 115.12476 }, "TMT128C-ETD": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C5[13C2]N1H15", "ion_mz": 116.134433 }, "TMT129N-ETD": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C5[13C2][15N1]H15", "ion_mz": 117.131468 }, "TMT129C-ETD": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C4[13C3]N1H15", "ion_mz": 116.134433 }, "TMT130N-ETD": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C4[13C3][15N1]H15", "ion_mz": 117.131468 }, "TMT130C-ETD": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C3[13C4]N1H15", "ion_mz": 118.141141 }, "TMT131N-ETD": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C3[13C4][15N1]H15", "ion_mz": 119.138176 }, "TMT131C-ETD": { "label_type": "TMT", "molecule_type": "reporter", + "chemical_formula": "C2[13C5]N1H15", "ion_mz": 118.141141 + }, + "sidechain_A": { + "molecule_type": "sidechain", + "chemical_formula": "C1H3", + "neutral_mass": 15.023475 + }, + "sidechain_C": { + "molecule_type": "sidechain", + "chemical_formula": "C1H3S1", + "neutral_mass": 46.995546 + }, + "sidechain_D": { + "molecule_type": "sidechain", + "chemical_formula": "C2H2O2", + "neutral_mass": 58.005479 + }, + "sidechain_E": { + "molecule_type": "sidechain", + "chemical_formula": "C3H4O2", + "neutral_mass": 72.021129 + }, + "sidechain_F": { + "molecule_type": "sidechain", + "chemical_formula": "C7H7", + "neutral_mass": 91.054775 + }, + "sidechain_G": { + "molecule_type": "sidechain", + "chemical_formula": "H1", + "neutral_mass": 1.007825 + }, + "sidechain_H": { + "molecule_type": "sidechain", + "chemical_formula": "C4H5N2", + "neutral_mass": 81.045273 + }, + "sidechain_I": { + "molecule_type": "sidechain", + "chemical_formula": "C4H9", + "neutral_mass": 57.070425 + }, + "sidechain_J": { + "molecule_type": "sidechain", + "chemical_formula": "C4H9", + "neutral_mass": 57.070425 + }, + "sidechain_K": { + "molecule_type": "sidechain", + "chemical_formula": "C4H10N1", + "neutral_mass": 72.081324 + }, + "sidechain_L": { + "molecule_type": "sidechain", + "chemical_formula": "C4H9", + "neutral_mass": 57.070425 + }, + "sidechain_M": { + "molecule_type": "sidechain", + "chemical_formula": "C3H7S1", + "neutral_mass": 75.026846 + }, + "sidechain_N": { + "molecule_type": "sidechain", + "chemical_formula": "C2H4N1O1", + "neutral_mass": 58.029289 + }, + "sidechain_O": { + "molecule_type": "sidechain", + "chemical_formula": "C9H17N2O1", + "neutral_mass": 169.134088 + }, + "sidechain_Q": { + "molecule_type": "sidechain", + "chemical_formula": "C3H6N1O1", + "neutral_mass": 72.044939 + }, + "sidechain_R": { + "molecule_type": "sidechain", + "chemical_formula": "C4H10N3", + "neutral_mass": 100.087472 + }, + "sidechain_S": { + "molecule_type": "sidechain", + "chemical_formula": "C1H3O1", + "neutral_mass": 31.018390 + }, + "sidechain_T": { + "molecule_type": "sidechain", + "chemical_formula": "C2H5O1", + "neutral_mass": 45.034040 + }, + "sidechain_U": { + "molecule_type": "sidechain", + "chemical_formula": "C1H3Se1", + "neutral_mass": 94.939997 + }, + "sidechain_V": { + "molecule_type": "sidechain", + "chemical_formula": "C3H7", + "neutral_mass": 43.054775 + }, + "sidechain_W": { + "molecule_type": "sidechain", + "chemical_formula": "C9H8N1", + "neutral_mass": 130.065674 + }, + "sidechain_Y": { + "molecule_type": "sidechain", + "chemical_formula": "C7H7O1", + "neutral_mass": 107.049690 } -} +} \ No newline at end of file diff --git a/implementations/python/mzpaf/reference.py b/implementations/python/mzpaf/reference.py index 2866f38..2e0733f 100644 --- a/implementations/python/mzpaf/reference.py +++ b/implementations/python/mzpaf/reference.py @@ -2,10 +2,11 @@ from importlib.resources import open_text from dataclasses import dataclass, field, asdict -from typing import Any, List, Optional, Pattern, Dict, Tuple, Type, Union, ClassVar +from typing import List, Optional, Dict, ClassVar PROTON = 1.00727646677 + def _neutral_mass(mz, z, charge_carrier=PROTON): return (mz * abs(z)) - (z * charge_carrier) @@ -64,6 +65,11 @@ def get(cls, name: str) -> 'ReferenceMolecule': cls._load_registry() return cls._registry[name] + @classmethod + def is_reference(cls, name: str) -> bool: + if cls._registry is None: + cls._load_registry() + return name in cls._registry def load_json(stream) -> Dict[str, ReferenceMolecule]: diff --git a/implementations/python/setup.py b/implementations/python/setup.py index 6584c90..1520b6d 100644 --- a/implementations/python/setup.py +++ b/implementations/python/setup.py @@ -3,15 +3,26 @@ from setuptools import setup, find_packages setup( - name='mzpaf', - packages=find_packages(exclude=('tests',)), + name="mzpaf", + packages=find_packages(exclude=("tests",)), requires=["pyteomics"], - version='0.1.0-alpha', - description='HUPO-PSI Peptide peak annotation format', + extras_require=dict( + docs=[ + "sphinx", + "sphinx-rtd-theme", + "numpydoc>=1,<2", + "sphinx_click", + "myst-parser", + "sphinx-autobuild", + "pydata-sphinx-theme", + ], + ), + version="0.2.0-alpha", + description="HUPO-PSI Peptide peak annotation format", classifiers=[ "Intended Audience :: Science/Research", "Programming Language :: Python :: 3 :: Only", "Topic :: Scientific/Engineering :: Bio-Informatics", - "Development Status :: 3 - Alpha" + "Development Status :: 3 - Alpha", ], ) diff --git a/implementations/python/tests/test_annotations.py b/implementations/python/tests/test_annotations.py index c16ef89..3578982 100644 --- a/implementations/python/tests/test_annotations.py +++ b/implementations/python/tests/test_annotations.py @@ -1,6 +1,5 @@ import unittest import json -import json from pathlib import Path import warnings @@ -37,6 +36,12 @@ def test_parse_unannotated(self): assert isinstance(x, Unannotated) self._matches_schema(x) + def test_satellite_ion_series(self): + base = "da32" + parsed = parse_annotation(base)[0] + assert parsed.series == "da" + assert parsed.position == 32 + def test_parse_annotation_complex(self): base = "b14" parsed = parse_annotation(base)[0] diff --git a/specification/annotation-schema.json b/specification/annotation-schema.json index 33cb83e..81e9023 100644 --- a/specification/annotation-schema.json +++ b/specification/annotation-schema.json @@ -110,7 +110,7 @@ "series": { "description": "The peptide ion series this ion belongs to", "type": "string", - "enum": ["b", "y", "a", "x", "c", "z"] + "enum": ["b", "y", "a", "x", "c", "z", "d", "v", "w", "da", "db", "wa", "wb"] }, "position": { "description": "The position from the appropriate terminal along the peptide this ion was fragmented at (starting with 1)", diff --git a/specification/grammars/annotation.lark b/specification/grammars/annotation.lark index 6cd0571..baee0fa 100644 --- a/specification/grammars/annotation.lark +++ b/specification/grammars/annotation.lark @@ -22,7 +22,7 @@ CHARACTER : LETTER | DIGIT | SYMBOL CONTENT_IN_BRACES : LETTER | DIGIT | SYMBOL_WITHOUT_CLOSING_BRACE | " " -BRACE_ENCLOSED_CONTENT : "[" (CONTENT_IN_BRACES)+ "]" +BRACE_ENCLOSED_CONTENT : "[" (CONTENT_IN_BRACES)+ ("[" (CONTENT_IN_BRACES | " ")+ "]")? "]" ANALYTE_REFERENCE : (CHARACTER)+ @@ -30,7 +30,7 @@ is_auxiliary : "&" analyte_reference_ : (ANALYTE_REFERENCE) "@" -PEPTIDE_SERIES_SYMBOL : "a" | "x" | "b" | "y" | "c" | "z" +PEPTIDE_SERIES_SYMBOL : "da" | "db" | "wa" | "wb" | "a" | "x" | "b" | "y" | "c" | "z" | "d" | "v" | "w" ORDINAL : (DIGIT)+ @@ -78,10 +78,10 @@ series_named_compound : "_" "{" CHARACTER+ "}" series_smiles : "s" "{" SMILES+ "}" -series_unknown : "?" NUMBER* +series_unknown : "?" ORDINAL? ion_series : series_peptide | series_immonium | series_internal | series_reporter | series_formula | series_named_compound | series_smiles | series_unknown analyte_reference_ion_series : (analyte_reference_ ion_series) | ion_series -annotation : is_auxiliary? analyte_reference_? ion_series neutral_loss* isotope? adducts? charge? annotation_qualifiers? \ No newline at end of file +annotation : is_auxiliary? analyte_reference_? ion_series neutral_loss* isotope? adducts? charge? annotation_qualifiers? diff --git a/specification/grammars/grammar.py b/specification/grammars/grammar.py index d1915b0..0f74c7d 100644 --- a/specification/grammars/grammar.py +++ b/specification/grammars/grammar.py @@ -3,8 +3,18 @@ import string -from railroad import (Diagram, Choice, Group, Optional, Terminal, - NonTerminal, Sequence, OneOrMore, ZeroOrMore, Stack) +from railroad import ( + Diagram, + Choice, + Group, + Optional, + Terminal, + NonTerminal, + Sequence, + OneOrMore, + ZeroOrMore, + Stack, +) import io from pyteomics.mass import std_aa_comp @@ -25,7 +35,7 @@ ATOM_COUNT = Sequence( NonTerminal("UPPER_CASE_LETTER"), ZeroOrMore(NonTerminal("LOWER_CASE_LETTER")), - OneOrMore(NonTerminal("DIGIT")) + OneOrMore(NonTerminal("DIGIT")), ) NUMBER = Sequence( @@ -35,9 +45,9 @@ Sequence( "e", OneOrMore(NonTerminal("DIGIT")), - Optional(Sequence(".", OneOrMore(NonTerminal("DIGIT")))) + Optional(Sequence(".", OneOrMore(NonTerminal("DIGIT")))), ) - ) + ), ) ORDINAL = OneOrMore(NonTerminal("DIGIT")) @@ -46,7 +56,7 @@ 0, NonTerminal("DIGIT"), NonTerminal("UPPER_CASE_LETTER"), - NonTerminal("LOWER_CASE_LETTER") + NonTerminal("LOWER_CASE_LETTER"), ) AMINO_ACID = Choice(0, *list(std_aa_comp)[:-2]) @@ -56,7 +66,14 @@ BraceEnclosedContent = Sequence( Terminal("["), OneOrMore(Choice(0, NonTerminal("CHARACTER"), NonTerminal("SYMBOL"))), - Terminal("]") + Optional( + Sequence( + Terminal("["), + OneOrMore(Choice(0, NonTerminal("CHARACTER"), NonTerminal("SYMBOL"), Terminal(" "))), + Terminal("]"), + ) + ), + Terminal("]"), ) IsAuxiliary = Group(Optional(Terminal("&")), "Is Auxiliary") @@ -67,26 +84,20 @@ PeptideIon = Group( Sequence( - Choice(0, *list(map(Terminal, ("a", "b", "c", "x", "y", "z")))), + Choice(0, *list(map(Terminal, ("a", "b", "c", "x", "y", "z", "da", "db", "v", "wa", "wb")))), NonTerminal("ORDINAL"), Optional( Sequence( Terminal("{"), - Group(OneOrMore(NonTerminal("ANY")), 'ProForma 2.0 Sequence'), - Terminal("}") + Group(OneOrMore(NonTerminal("ANY")), "ProForma 2.0 Sequence"), + Terminal("}"), ) - ) + ), ), "Peptide Ion", ) -ReporterIon = Group( - Sequence( - Terminal("r"), - BraceEnclosedContent - ), - "Reporter Ion" -) +ReporterIon = Group(Sequence(Terminal("r"), BraceEnclosedContent), "Reporter Ion") InternalIon = Group( Sequence( @@ -96,9 +107,9 @@ NonTerminal("ORDINAL"), Sequence( Terminal("{"), - Group(NonTerminal("ANY"), 'ProForma 2.0 Sequence'), - Terminal("}") - ) + Group(NonTerminal("ANY"), "ProForma 2.0 Sequence"), + Terminal("}"), + ), ), "Internal Peptide Ion", ) @@ -108,48 +119,36 @@ "Immonium Ion", ) -PrecursorIon = Group( - Terminal("p"), - "Precursor Ion" -) +PrecursorIon = Group(Terminal("p"), "Precursor Ion") -ChemicalFormula = OneOrMore(NonTerminal('ATOM_COUNT')) +ChemicalFormula = OneOrMore(NonTerminal("ATOM_COUNT")) FormulaIon = Group( - Sequence( - Terminal("f"), - Terminal('{'), - ChemicalFormula, - Terminal('}') - ), - "Formula Ion" + Sequence(Terminal("f"), Terminal("{"), ChemicalFormula, Terminal("}")), + "Formula Ion", ) NamedCompound = Group( Sequence( Terminal("_"), - Terminal('{'), + Terminal("{"), OneOrMore(NonTerminal("CHARACTER")), - Terminal('}'), + Terminal("}"), ), - "Named Compound" + "Named Compound", ) UnknownIon = Group( - Sequence(Terminal("?"), Optional(OneOrMore(NonTerminal("DIGIT")))), - "Unknown Ion" + Sequence(Terminal("?"), Optional(OneOrMore(NonTerminal("DIGIT")))), "Unknown Ion" ) SMILESIon = Group( Sequence( - Terminal("s"), - Terminal('{'), - OneOrMore(Terminal("/[^}]/")), - Terminal('}') + Terminal("s"), Terminal("{"), OneOrMore(Terminal("/[^}]/")), Terminal("}") ), - "SMILES Ion" + "SMILES Ion", ) IonType = Group( @@ -165,15 +164,12 @@ SMILESIon, UnknownIon, ), - "Ion Type" + "Ion Type", ) NeutralLoss = Group( - Sequence( - NonTerminal('SIGN'), - Choice(0, ChemicalFormula, BraceEnclosedContent) - ), - "Neutral Loss(es)" + Sequence(NonTerminal("SIGN"), Choice(0, ChemicalFormula, BraceEnclosedContent)), + "Neutral Loss(es)", ) Isotope = Group( @@ -182,64 +178,41 @@ Optional(NonTerminal("ORDINAL")), Terminal("i"), ), - "Isotope" + "Isotope", ) -ChargeState = Group( - Sequence( - "^", - NonTerminal("ORDINAL") - ), - "Charge State" -) +ChargeState = Group(Sequence("^", NonTerminal("ORDINAL")), "Charge State") Adducts = Group( Sequence( - '[', - 'M', + "[", + "M", OneOrMore( Sequence( - NonTerminal('SIGN'), + NonTerminal("SIGN"), ChemicalFormula, ) ), - ']' + "]", ), - "Adducts" + "Adducts", ) -MassError = Group( - Sequence( - '/', - NonTerminal("NUMBER"), - Optional("ppm") - ), - "Mass Error" -) +MassError = Group(Sequence("/", NonTerminal("NUMBER"), Optional("ppm")), "Mass Error") -ConfidenceEstimate = Group( - Sequence( - "*", - NonTerminal("NUMBER") - ), - "Confidence Estimate" -) +ConfidenceEstimate = Group(Sequence("*", NonTerminal("NUMBER")), "Confidence Estimate") -Annotation = ( - Stack( - IsAuxiliary, - Optional( - AnalyteIdentifier - ), - IonType, - ZeroOrMore(NeutralLoss), - Optional(Isotope), - Optional(Adducts), - Optional(ChargeState), - Optional(MassError), - Optional(ConfidenceEstimate), - ) +Annotation = Stack( + IsAuxiliary, + Optional(AnalyteIdentifier), + IonType, + ZeroOrMore(NeutralLoss), + Optional(Isotope), + Optional(Adducts), + Optional(ChargeState), + Optional(MassError), + Optional(ConfidenceEstimate), ) @@ -255,12 +228,12 @@ def render_group_to_file(fh, name): print("Writing", name) tokens = globals()[name] pathname: pathlib.Path = (image_dir / name).with_suffix(".svg") - with pathname.open('wt') as img_fh: + with pathname.open("wt") as img_fh: img_fh.write(encode_svg(Diagram(tokens))) fh.write(f"""## {name}\n\n\n""") -with open("grammar.md", 'wt') as fh: +with open("grammar.md", "wt") as fh: fh.write("""# Peak Annotation Grammar\n\n""") render_group_to_file(fh, "DIGIT") render_group_to_file(fh, "LOWER_CASE_LETTER") diff --git a/specification/grammars/regex_ecma.js b/specification/grammars/regex_ecma.js index 1718f70..e3da460 100644 --- a/specification/grammars/regex_ecma.js +++ b/specification/grammars/regex_ecma.js @@ -1,3 +1,3 @@ -const pattern = /^(?&)?(?:(?\d+)@)?(?:(?:(?[axbycz]\.?)(?\d+)(?:\{(?.+)\})?)|(?[m](?\d+):(?\d+)(?:\{(?.+)\})?)|(?p)|(:?I(?[ARNDCEQGHKMFPSTWYVIL])(?:\[(?(?:[^\]]+))\])?)|(?r(?:(?:\[(?[^\]]+)\])))|(?:f\{(?[A-Za-z0-9]+)\})|(?:_\{(?[^\{\}\s,\/]+)\})|(?:s\{(?[^\}]+)\})|(?:(?\?)(?\d+)?))(?(?:[+-]\d*(?:(?:[A-Z][A-Za-z0-9]*)|(?:\[(?:(?:[A-Za-z0-9:\.]+))\])))+)?(?:(?[+-]\d*)i)?(?:\[(?M(:?[+-]\d*[A-Z][A-Za-z0-9]*)+)\])?(?:\^(?[+-]?\d+))?(?:\/(?[+-]?\d+(?:\.\d+)?)(?ppm)?)?(?:\*(?\d*(?:\.\d+)?))?/ +const pattern = /^(?&)?(?:(?\d+)@)?(?:(?:(?(?:da|db|wa|wb)|[axbyczdwv]\.?)(?\d+)(?:\{(?.+)\})?)|(?[m](?\d+):(?\d+)(?:\{(?.+)\})?)|(?p)|(:?I(?[ARNDCEQGHKMFPSTWYVIL])(?:\[(?(?:[^\]]+))\])?)|(?r(?:(?:\[(?[^\]]+)\])))|(?:f\{(?[A-Za-z0-9\[\]]+)\})|(?:_\{(?[^\{\}\s,/]+)\})|(?:s\{(?[^\}]+)\})|(?:(?\?)(?\d+)?))(?(?:[+-]\d*(?:(?:[A-Z][A-Za-z0-9]*)|(?:\[(?:(?:[A-Za-z0-9:\.]+)(?:\[(?:[A-Za-z0-9\.:\-\ ]+)\])?)\])))+)?(?:(?[+-]\d*)i)?(?:\[(?M(:?[+-]\d*[A-Z][A-Za-z0-9]*)+)\])?(?:\^(?[+-]?\d+))?(?:\/(?[+-]?\d+(?:\.\d+)?)(?ppm)?)?(?:\*(?\d*(?:\.\d+)?))?/ module.exports = pattern \ No newline at end of file diff --git a/specification/grammars/regex_sre.py b/specification/grammars/regex_sre.py index bbdfd74..0e0c3b2 100644 --- a/specification/grammars/regex_sre.py +++ b/specification/grammars/regex_sre.py @@ -1,9 +1,10 @@ import re -annotation_pattern = re.compile(r""" +annotation_pattern = re.compile( + r""" ^(?P&)? (?:(?P\d+)@)? - (?:(?:(?P[axbycz]\.?)(?P\d+)(?:\{(?P.+)\})?)| + (?:(?:(?P(?:da|db|wa|wb)|[axbyczdwv]\.?)(?P\d+)(?:\{(?P.+)\})?)| (?P[m](?P\d+):(?P\d+)(?:\{(?P.+)\})?)| (?Pp)| (:?I(?P[ARNDCEQGHKMFPSTWYVIL])(?:\[(?P(?:[^\]]+))\])?)| @@ -12,7 +13,7 @@ (?P[^\]]+) \]) ))| - (?:f\{(?P[A-Za-z0-9]+)\})| + (?:f\{(?P[A-Za-z0-9\[\]]+)\})| (?:_\{ (?P[^\{\}\s,/]+) \})| @@ -23,7 +24,7 @@ (?:(?:[A-Z][A-Za-z0-9]*)| (?:\[ (?: - (?:[A-Za-z0-9:\.]+) + (?:[A-Za-z0-9:\.]+)(?:\[(?:[A-Za-z0-9\.:\-\ ]+)\])? ) \]) ) @@ -33,4 +34,6 @@ (?:\^(?P[+-]?\d+))? (?:/(?P[+-]?\d+(?:\.\d+)?)(?Pppm)?)? (?:\*(?P\d*(?:\.\d+)?))? -""", re.X) +""", + re.X, +) diff --git a/specification/grammars/schema_images/Annotation.svg b/specification/grammars/schema_images/Annotation.svg index 339ad25..79d1a18 100644 --- a/specification/grammars/schema_images/Annotation.svg +++ b/specification/grammars/schema_images/Annotation.svg @@ -1 +1 @@ - & Is Auxiliary ORDINAL @ Analyte Identifier a b c x y z ORDINAL { ANY ProForma 2.0 Sequence } Peptide Ion m ORDINAL : ORDINAL { ANY ProForma 2.0 Sequence } Internal Peptide Ion I AMINO_ACID [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] Immonium Ion r [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] Reporter Ion p Precursor Ion f { ATOM_COUNTATOM_COUNTATOM_COUNT ATOM_COUNTATOM_COUNTATOM_COUNT ATOM_COUNTATOM_COUNTATOM_COUNT } Formula Ion _ { CHARACTER } Named Compound s { /[^}]/ } SMILES Ion ? DIGIT Unknown Ion Ion Type SIGN ATOM_COUNTATOM_COUNTATOM_COUNT ATOM_COUNTATOM_COUNTATOM_COUNT ATOM_COUNTATOM_COUNTATOM_COUNT [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] Neutral Loss(es) SIGN ORDINAL i Isotope [ M SIGN ATOM_COUNTATOM_COUNTATOM_COUNT ATOM_COUNTATOM_COUNTATOM_COUNT ATOM_COUNTATOM_COUNTATOM_COUNT ] Adducts ^ ORDINAL Charge State / NUMBER ppm Mass Error * NUMBER Confidence Estimate \ No newline at end of file + & Is Auxiliary ORDINAL @ Analyte Identifier a b c x y z da db v wa wb ORDINAL { ANY ProForma 2.0 Sequence } Peptide Ion m ORDINAL : ORDINAL { ANY ProForma 2.0 Sequence } Internal Peptide Ion I AMINO_ACID [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] ]]] Immonium Ion r [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] ]]] Reporter Ion p Precursor Ion f { ATOM_COUNTATOM_COUNTATOM_COUNT ATOM_COUNTATOM_COUNTATOM_COUNT ATOM_COUNTATOM_COUNTATOM_COUNT } Formula Ion _ { CHARACTER } Named Compound s { /[^}]/ } SMILES Ion ? DIGIT Unknown Ion Ion Type SIGN ATOM_COUNTATOM_COUNTATOM_COUNT ATOM_COUNTATOM_COUNTATOM_COUNT ATOM_COUNTATOM_COUNTATOM_COUNT [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] [[[ CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL CHARACTERCHARACTERCHARACTER SYMBOLSYMBOLSYMBOL ]]] ]]] Neutral Loss(es) SIGN ORDINAL i Isotope [ M SIGN ATOM_COUNTATOM_COUNTATOM_COUNT ATOM_COUNTATOM_COUNTATOM_COUNT ATOM_COUNTATOM_COUNTATOM_COUNT ] Adducts ^ ORDINAL Charge State / NUMBER ppm Mass Error * NUMBER Confidence Estimate \ No newline at end of file diff --git a/specification/mzPAF_specification_v1.0-draft15.docx b/specification/mzPAF_specification_v1.0-draft15.docx new file mode 100644 index 0000000000000000000000000000000000000000..e78e4940764e119d937c38cc02522711d469938e GIT binary patch literal 5635375 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

wc9<_3Ox>ikwaH<}zcH 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