Skip to content
advancedscience

MassBank MS/MS Fragment Peaks and Formula Assignment

Pick the fragment peaks of an MS/MS spectrum and assign each a formula and a status, using ten real MassBank records with peak_picking and the peak-cnn trainer.

Get This Design

View on GitHub(opens in a new tab)

Clone or download from the repository

Quick start:

bash
git clone https://github.com/davidjurgens/potato-showcase.git
cd potato-showcase/science/spectroscopy/massbank-ms2-peak-annotation
potato start config.yaml

About this dataset

MassBank is an open library of mass spectra. The library started in 2006 in Japan, and a European server followed in 2011. The current MassBank paper (Neumann et al., Nucleic Acids Research 2025) reports 119,845 spectra of 18,529 compounds from 53 contributors. Each spectrum is a text record in the MassBank Record Format, now at version 2.6.0. A record lists the compound, the instrument settings, and the precursor ion. The peak list sits in PK$PEAK as m/z, intensity, and a relative intensity from 1 to 999. The optional PK$ANNOTATION field holds the chemical annotation of peaks with molecular formula.

Contributors write the annotations themselves. Records prepared with the RMassBank software carry proposed formulas, and the format calls the automated annotation tentative. This design asks for the same judgment as a review of a deposited record. The annotator sees one MS/MS spectrum as sticks, keeps the peaks that are fragments of the compound, types a molecular formula for each, and sets a status of tentative formula, confirmed formula, or no formula fits. The status field is an addition. The record format has no per-peak status. The ten items are real records from the UFZ and University of Athens contributors, all licensed CC BY and copied unchanged. The formulas the submitters deposited sit in each item's deposited_formulas field and are withheld from annotators. The two sets of formulas can be compared afterward.

The model_training block turns training on, and the peak-cnn trainer is picked on /admin/training. The trainer learns where annotators kept peaks, using the spectrum alone, and writes predicted peak positions back as suggestions marked model on spectra nobody has finished. Positions are the only prediction. Formulas, statuses, and other peak labels are not predicted, and no model is served or deployed. Training needs five annotated spectra in the training split. Ten spectra from two laboratories therefore exercise the loop without teaching a model that generalizes to other instruments.

Spectra in MassBank (2025 paper)
119,845
Compounds
18,529
Contributors
53
Record format version
2.6.0
Records in this design
10 MS2 spectra, all CC BY
Peaks per record here
17 to 25

Configuration File

This Potato config reproduces the annotation task. Save it as config.yaml and run potato start config.yaml to try it.

yaml
# yaml-language-server: $schema=https://potatoannotator.readthedocs.io/en/latest/schemas/potato-config.schema.json
#
# MassBank: pick the fragment peaks of an MS/MS spectrum and assign each a
# molecular formula.
#
# Dataset: MassBank/MassBank-data, the open records of the MassBank mass
# spectral library, in MassBank Record Format 2.6.0 (MassBank Consortium).
# Paper (describes the record format, its validation pipeline and the
# current library):
#   @article{Neumann_2025,
#     title     = {MassBank: an open and FAIR mass spectral data resource},
#     author    = {Neumann, Steffen and Meier, Ren{\'e} and Wenk, Michael and Elapavalore, Anjana and Nishioka, Takaaki and Schulze, Tobias and Stravs, Michael and Tsugawa, Hiroshi and Matsuda, Fumio and Schymanski, Emma L},
#     journal   = {Nucleic Acids Research},
#     volume    = {54}, number = {D1}, pages = {D601--D606}, year = {2025},
#     publisher = {Oxford University Press (OUP)},
#     doi       = {10.1093/nar/gkaf1193}
#   }
# DOI: 10.1093/nar/gkaf1193
# Dataset DOI: 10.5281/zenodo.3378723 (MassBank/MassBank-data, CC BY 4.0 for
# the repository)
# Dataset URL: https://github.com/MassBank/MassBank-data
# Record format: https://github.com/MassBank/MassBank-documentation/blob/dev/MassBankRecordFormat.md
#
# Licence: every MassBank record carries its own LICENSE line. The record
# format allows CC0, CC BY, CC BY-NC, CC BY-NC-SA and CC BY-SA. The ten
# records in sample-data.json are all CC BY and are real, copied unchanged
# (m/z and relative intensity) from the records named in each item's
# "credit" line. The item fields accession, license, source_url, authors and
# copyright repeat the record header.
#
# What a record holds, quoted from the MassBank Record Format 2.6.0:
#   PK$PEAK: "Peak Data. Mandatory and Multiple line Information"
#     "PK$PEAK: m/z int. rel.int."
#     "M/Z: m/z of the peak. INT: intensity of the peak. REL: an integer from
#     1 to 999 which denotes relative intensity of the peak."
#   PK$ANNOTATION: "Chemical Annotation of Peaks with Molecular Formula.
#     Optional and Multiple Line Information. Line 1 defines the record format
#     of the annotation blocks. Contributors freely define the record format
#     by using appropriate terms."
#     The UFZ and Athens records here use the RMassBank layout
#     "PK$ANNOTATION: m/z tentative_formula formula_count mass error(ppm)".
#     The format says "The automated annotation by RMassBank is currently
#     tentative."
#
# How this design maps onto a record:
#   - The spectrum display draws the PK$PEAK list as sticks (x is m/z, y is
#     the REL column, 1 to 999).
#   - The peak_picking scheme records the peaks the annotator keeps, and the
#     peak_fields record a formula (the PK$ANNOTATION tentative_formula
#     column) and a status for each.
#   - The formulas the submitters deposited are kept in each item's
#     "deposited_formulas" field (m/z to formula). The page does not show
#     them, so the annotator assigns formulas independently and the two sets
#     can be compared afterward.
#
# Adaptations:
#   - Real records, but a small sample: ten MS2 spectra of ten compounds, 17
#     to 25 peaks each, from the UFZ and University of Athens contributors,
#     all with LICENSE CC BY. They are not a sample of MassBank.
#   - MassBank annotations are written by the contributors, with RMassBank
#     software, not by a crowd protocol. This design asks for the same
#     judgment (is this a fragment peak, and which formula fits) as a
#     review of a deposited record.
#   - The status field (tentative formula, confirmed formula, no formula
#     fits) is added here. The record format has no per-peak status; the
#     RMassBank annotations are all "tentative" as a whole.
#   - Only peaks and formulas are collected. Ion type, mass error and formula
#     count (the other PK$ANNOTATION columns) are left out.
#   - Suggested peaks come from the display's peak detector (and from a
#     trained peak-cnn model once one has run), not from the submitters'
#     annotations.
#
# Model-assisted peak picking (peak-cnn). Open /admin/training with the
# admin key below, pick peak-cnn for the "peaks" scheme, and train (pip
# install "potato-annotation[train-vision]"). It learns where the annotators
# kept peaks, from the spectrum alone, and suggests peak POSITIONS (m/z) on
# spectra nobody has finished, marked "model". It does not predict formulas,
# statuses or any other peak label, and it does not serve or deploy a model.
# It needs 5 annotated spectra in its training split (min_instances); ten
# spectra from two labs exercise the loop and do not teach a model that
# generalizes to other instruments.
#
# Run: potato start config.yaml -p 8000

port: 8000
annotation_task_name: "MassBank: pick MS2 fragment peaks and assign formulas"
task_dir: "."

data_files:
  - sample-data.json

item_properties:
  id_key: id
  text_key: context
  private_keys: [deposited_formulas]

output_annotation_dir: annotation_output
export_annotation_format: jsonl

require_password: false
admin_api_key: "demo-admin-key"

user_config:
  allow_all_users: true

instance_display:
  fields:
    - key: context
      type: text
      label: "Record"
    - key: spectrum
      type: spectrum
      label: "MS2 spectrum"
      display_options:
        height: 380
        spectrum_type: ms
        mode: sticks
        x_label: "m/z"
        y_label: "Relative intensity (1 to 999)"
        # Suggested peaks: the peak detector at first, a trained peak-cnn
        # model's predictions once one has run (method auto).
        prepick:
          method: auto
          prominence: 0.05
          max_peaks: 30
    - key: credit
      type: text
      label: "Source and licence"

annotation_schemes:
  - annotation_type: peak_picking
    name: peaks
    description: "Keep the fragment peaks and assign each a molecular formula. Click a stick to pick it, click it again to remove it, drag to zoom. Accept or reject every suggested peak."
    viewer_field: spectrum
    peak_fields:
      - name: formula
        label: "Formula"
        type: text
        placeholder: "e.g. C6H14N+"
      - name: status
        label: "Status"
        type: choice
        options: ["tentative formula", "confirmed formula", "no formula fits"]
    min_peaks: 1
    require_review: true
    label_requirement: {required: true}

model_training:
  enabled: true
  writeback:
    # Show peak-cnn's predicted peak positions as suggestions on the spectrum.
    schemas: ["peaks"]
    include_unlabeled: true
    min_confidence: 0.5

annotation_instructions: |
  Each item is the MS/MS spectrum of one compound, as deposited in
  MassBank. The record line gives the compound's formula and the precursor
  ion, so a fragment formula has to be a subset of the precursor's atoms.
  Pick the peaks that are fragments of the compound and skip noise. For
  each picked peak, write the fragment's molecular formula, including the
  charge sign the ion carries (C6H14N+ in positive mode, C13H8O- in
  negative mode), and set the status. Use "no formula fits" when no
  formula is consistent with the compound and the m/z.

Sample Data

json
[
  {
    "id": "massbank_001",
    "title": "Pindolol, MS2 of [M+H]+ at m/z 249.1598",
    "context": "Compound: Pindolol (C14H20N2O2). Precursor [M+H]+ at m/z 249.1598. LC-ESI-ITFT, HCD, collision energy 80 (nominal). Ion mode positive.",
    "spectrum": {
      "x": [
        72.0807,
        74.06,
        84.0808,
        98.0964,
        100.1121,
        106.0651,
        116.107,
        117.0699,
        118.0651,
        129.0699,
        130.0652,
        132.0445,
        132.0808,
        133.0523,
        134.0601,
        143.0731,
        144.0808,
        145.0646,
        146.06,
        154.0652,
        155.0605,
        157.0525,
        160.0758,
        170.0605,
        172.0759
      ],
      "y": [
        251,
        731,
        22,
        131,
        177,
        164,
        666,
        273,
        668,
        12,
        77,
        108,
        69,
        79,
        999,
        126,
        957,
        26,
        382,
        44,
        102,
        26,
        35,
        22,
        155
      ],
      "kind": "ms",
      "x_units": "M/Z",
      "sticks": true,
      "title": "Pindolol; LC-ESI-ITFT; MS2; CE: 80; R=15000; [M+H]+"
    },
    "credit": "MassBank record MSBNK-UFZ-UF409802, CC BY, Copyright (C) 2017. Schulze T, Krauss M, Department of Effect-Directed Analysis, Helmholtz Centre for Environmental Research - UFZ GmbH, Leipzig, Germany. https://github.com/MassBank/MassBank-data/blob/dev/UFZ/MSBNK-UFZ-UF409802.txt",
    "accession": "MSBNK-UFZ-UF409802",
    "license": "CC BY",
    "source_url": "https://raw.githubusercontent.com/MassBank/MassBank-data/dev/UFZ/MSBNK-UFZ-UF409802.txt",
    "authors": "Schulze T, Krauss M, Department of Effect-Directed Analysis, Helmholtz Centre for Environmental Research - UFZ GmbH, Leipzig, Germany",
    "copyright": "Copyright (C) 2017",
    "deposited_formulas": {
      "72.0807": "C4H10N+",
      "74.06": "C3H8NO+",
      "84.0808": "C5H10N+",
      "98.0964": "C6H12N+",
      "100.1121": "C6H14N+",
      "106.0651": "C7H8N+",
      "116.107": "C6H14NO+",
      "117.0699": "C9H9+",
      "118.0651": "C8H8N+",
      "129.0699": "C10H9+",
      "130.0652": "C9H8N+",
      "132.0445": "C8H6NO+",
      "132.0808": "C9H10N+",
      "133.0523": "C8H7NO+",
      "134.0601": "C8H8NO+",
      "143.0731": "C10H9N+",
      "144.0808": "C10H10N+",
      "145.0646": "C10H9O+",
      "146.06": "C9H8NO+",
      "154.0652": "C11H8N+",
      "155.0605": "C10H7N2+",
      "157.0525": "C10H7NO+",
      "160.0758": "C10H10NO+",
      "170.0605": "C11H8NO+",
      "172.0759": "C11H10NO+"
    }
  },
  {
    "id": "massbank_002",
    "title": "N-Isopropyl-N-phenyl-p-phenylenediamine, MS2 of [M+H]+ at m/z 227.1543",
    "context": "Compound: N-Isopropyl-N-phenyl-p-phenylenediamine (C15H18N2). Precursor [M+H]+ at m/z 227.1543. LC-ESI-ITFT, CID, collision energy 55 (nominal). Ion mode positive.",
    "spectrum": {
      "x": [
        103.0546,
        118.0655,
        120.0812,
        129.0704,
        143.0858,
        155.0854,
        157.1019,
        165.0707,
        168.0812,
        178.0784,
        181.102,
        182.097,
        183.1176,
        192.0928,
        193.1019,
        194.0974,
        195.105,
        208.113,
        210.1286,
        227.155
      ],
      "y": [
        1,
        1,
        999,
        8,
        2,
        1,
        2,
        1,
        1,
        58,
        2,
        8,
        3,
        1,
        129,
        2,
        47,
        8,
        57,
        1
      ],
      "kind": "ms",
      "x_units": "M/Z",
      "sticks": true,
      "title": "N-Isopropyl-N-phenyl-p-phenylenediamine; LC-ESI-ITFT; MS2; CE: 55; R=15000; [M+H]+"
    },
    "credit": "MassBank record MSBNK-UFZ-UF413704, CC BY, Copyright (C) 2017. Schulze T, Krauss M, Department of Effect-Directed Analysis, Helmholtz Centre for Environmental Research - UFZ GmbH, Leipzig, Germany. https://github.com/MassBank/MassBank-data/blob/dev/UFZ/MSBNK-UFZ-UF413704.txt",
    "accession": "MSBNK-UFZ-UF413704",
    "license": "CC BY",
    "source_url": "https://raw.githubusercontent.com/MassBank/MassBank-data/dev/UFZ/MSBNK-UFZ-UF413704.txt",
    "authors": "Schulze T, Krauss M, Department of Effect-Directed Analysis, Helmholtz Centre for Environmental Research - UFZ GmbH, Leipzig, Germany",
    "copyright": "Copyright (C) 2017",
    "deposited_formulas": {
      "103.0546": "C8H7+",
      "118.0655": "C8H8N+",
      "120.0812": "C8H10N+",
      "129.0704": "C10H9+",
      "143.0858": "C11H11+",
      "155.0854": "C12H11+",
      "157.1019": "C12H13+",
      "165.0707": "C13H9+",
      "168.0812": "C12H10N+",
      "178.0784": "C14H10+",
      "181.102": "C14H13+",
      "182.097": "C13H12N+",
      "183.1176": "C14H15+",
      "192.0928": "C15H12+",
      "193.1019": "C15H13+",
      "194.0974": "C14H12N+",
      "195.105": "C14H13N+",
      "208.113": "C15H14N+",
      "210.1286": "C15H16N+",
      "227.155": "C15H19N2+"
    }
  }
]

// ... and 8 more items

Dataset & paper

Neumann et al., Nucleic Acids Research 2025

Paper DOI
10.1093/nar/gkaf1193
Dataset DOI
10.5281/zenodo.3378723

Citation (BibTeX)

bibtex
@article{Neumann_2025,
  title     = {MassBank: an open and FAIR mass spectral data resource},
  volume    = {54},
  ISSN      = {1362-4962},
  url       = {http://dx.doi.org/10.1093/nar/gkaf1193},
  DOI       = {10.1093/nar/gkaf1193},
  number    = {D1},
  journal   = {Nucleic Acids Research},
  publisher = {Oxford University Press (OUP)},
  author    = {Neumann, Steffen and Meier, René and Wenk, Michael and Elapavalore, Anjana and Nishioka, Takaaki and Schulze, Tobias and Stravs, Michael and Tsugawa, Hiroshi and Matsuda, Fumio and Schymanski, Emma L},
  year      = {2025},
  month     = nov,
  pages     = {D601--D606}
}

Details

Annotation Types

peak_picking

Domain

Analytical chemistryMass spectrometryMetabolomics

Use Cases

Fragment peak pickingMolecular formula assignmentSpectral library curation

Tags

massbankmass spectrometryms/mstandem mass spectrometryfragment annotationmolecular formulapeak pickingrmassbankspectral library

Found an issue or want to improve this design?

Open an Issue(opens in a new tab)