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
)3 Feature Annotation
This chapter describes Step 2 of the FeatureMAP pipeline: feature-level metabolite annotation using annotate_feature().
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:
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.
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).
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).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.
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 |
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")
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.2This 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.00000This 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.
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.