3  Feature Annotation

This chapter describes Step 2 of the FeatureMAP pipeline: feature-level metabolite annotation using annotate_feature().

Important

Prerequisites: Make sure your input data follows the format in Data Preparation, especially the required feature_table columns in Section 2.1.

3.1 What annotate_feature() Does

annotate_feature() performs feature-to-metabolite candidate annotation for LC–MS data and resolves the many-to-many relationship between features and metabolites. The procedure consists of below main stages:

  1. MS1 database matching: Each LC–MS feature is matched to the FeatureMAP reference compound database using accurate mass and common ion forms. Only candidates carrying an HMDB or KEGG identifier are retained.

  2. Metabolite Feature Cluster (MFC) construction: Features annotated to the same metabolite are grouped into MFCs based on retention-time proximity and ion relationships (e.g., adducts or isotopes).

  3. Evidence-based scoring of MFCs: Each cluster is scored based on supporting evidence: user-supplied MS2 confirmation contributes the most (+150), canonical adducts ((M+H)+ in positive mode, (M-H)- in negative mode) contribute +50, and observed isotopic peaks or secondary adducts add smaller increments (+20/+10).

  4. Iterative refinement of annotations: Conflicting annotations are resolved iteratively by removing low-confidence clusters and ambiguous feature assignments until convergence.

The function returns a featuremap_result object with stage marker "feature_annotated", which is required for all downstream analyses.

Note

One merged reference namespace. Earlier versions of FeatureMAP asked you to choose between a KEGG and an HMDB namespace with a refdata argument. This is no longer needed: annotate_feature() now matches against a merged HMDB + KEGG compound database (featuremap_compound), keeps both HMDB.ID and KEGG.ID for every candidate, and sets res$refdata to "all" automatically. All downstream steps work at the structure (InChI) level, so they are independent of the original identifier namespace.

3.2 Key Parameters

Parameter Default Description
feature_table required Feature-level input table (Chapter 2 format)
ms2_table NULL Optional MS2 annotation table used as auxiliary evidence
metabolite_database NULL Optional user-supplied metid database object
column "rp" LC mode ("rp" or "hilic"), controls the adduct rules
ms1_match_ppm 15 Mass tolerance (ppm) used in MS1 matching
mfc_rt_tol 5 Retention-time tolerance used when constructing MFCs
isotope_number 3 Maximum isotope depth
workers 4 Number of parallel workers
Note

If metabolite_database = NULL, FeatureMAP loads the merged compound database automatically from the local cache, downloading it from the resource repository on first use (see Installation).

3.3 Basic Usage

data("demo_feature_table", package = "featuremap")

res <- annotate_feature(
  feature_table = demo_feature_table,
  ms2_table = NULL,
  metabolite_database = NULL,
  column = "rp",
  ms1_match_ppm = 15,
  mfc_rt_tol = 5,
  isotope_number = 3,
  workers = 4
)
data("demo_feature_table", package = "featuremap")
data("demo_ms2", package = "featuremap")

res <- annotate_feature(
  feature_table = demo_feature_table,
  ms2_table = demo_ms2,
  metabolite_database = NULL,
  column = "rp",
  ms1_match_ppm = 15,
  mfc_rt_tol = 5,
  isotope_number = 3,
  workers = 4
)

3.4 Optional: Integrate Your Own MS2 Annotation

If you already have an MS2 annotation table, pass it to ms2_table:

ms2_table <- read.csv("your_ms2_annotation.csv")

res <- annotate_feature(
  feature_table = feature_table,
  ms2_table = ms2_table,
  column = "rp"
)

Providing MS2 annotations is optional. When provided, matched feature–metabolite pairs are flagged in the ms2_confirmed column and receive a large scoring bonus, which markedly improves candidate ranking.

3.5 Result Interpretation

After running annotate_feature(), the result is stored in a featuremap_result object that contains the feature-to-metabolite annotations. First confirm that the annotation step completed successfully:

res$stage
# [1] "feature_annotated"

res$object_type
# [1] "featuremap_result"

res$refdata
# [1] "all"

names(res)
# [1] "anno_redundancy"     "anno_feature_table1" "refdata"
# [4] "feature_table"       "stage"               "object_type"
# [7] ".__enclos_env__"     "clone"               "initialize"

3.5.1 Feature-to-metabolite annotation table

The main output of this step is the refined annotation table:

dim(res$anno_feature_table1)
head(res$anno_feature_table1[, c(
  "variable_id", "Compound.name", "HMDB.ID", "KEGG.ID",
  "Adduct", "mz.error", "ms2_confirmed", "score_norm"
)])
# [1] 49770    29
#    variable_id           Compound.name     HMDB.ID KEGG.ID Adduct mz.error
# 1 M105T384_POS     S-Ethyl thioacetate HMDB0031190    <NA> (M+H)+ 8.741527
# 2 M105T384_POS S-Methyl propanethioate HMDB0031192    <NA> (M+H)+ 8.741527
# 3 M105T384_POS  3-(Methylthio)propanal HMDB0031857    <NA> (M+H)+ 8.741527
# 4 M105T384_POS   3-Mercapto-2-butanone HMDB0031982    <NA> (M+H)+ 8.741527
# 5 M105T384_POS     (Methylthio)acetone HMDB0040170    <NA> (M+H)+ 8.741527
# 6 M105T384_POS   4-Mercapto-2-butanone HMDB0041015    <NA> (M+H)+ 8.741527
#   ms2_confirmed score_norm
# 1         FALSE        0.2
# 2         FALSE        0.2
# 3         FALSE        0.2
# 4         FALSE        0.2
# 5         FALSE        0.2
# 6         FALSE        0.2

This table represents the mapping between LC–MS features and metabolite candidates after iterative refinement. Each row corresponds to a feature–metabolite relationship supported by the evidence scoring and filtering procedure described above. Key columns are:

Column Description
variable_id Feature ID from the input feature_table
Compound.name, CAS.ID, HMDB.ID, KEGG.ID, Lab.ID, Formula Metabolite candidate identity
Adduct, isotope, polarity Ion form supporting the match
mz.error, mz.match.score, RT.error, RT.match.score, Total.score, Level metid matching statistics
ms2_confirmed TRUE when the pair is supported by the supplied ms2_table
mz, rt, mean_intensity, condition, pvalue Original feature-level information
metabolite_feature_cluster MFC that this feature–metabolite pair belongs to
score Heuristic evidence score of the MFC
score_norm score rescaled to the interval [0, 1]

3.5.2 Annotation redundancy summary

To understand how annotation ambiguity was reduced, inspect:

res$anno_redundancy
#        mfc_per_metabolite metabolite_per_feature
# before           1.367885               52.46564
# after            1.292547               45.00000

This summary reports the level of annotation redundancy before and after refinement, including:

  • mfc_per_metabolite: the average number of metabolite feature clusters (MFCs) assigned to each metabolite candidate.

  • metabolite_per_feature: the average number of metabolite candidates assigned to each LC–MS feature.

Tip

The console log of annotate_feature() is labelled Step 1: Feature Annotation, because the package counts only the four analysis functions. In this tutorial we count data preparation as Step 1, so the tutorial step numbers are one ahead of the console labels.

3.6 Next Step

Once feature annotation is complete, continue to Subnetwork Extraction to refine annotations with network context and extract the metabolic subnetwork.