
mzTab-M file format: import-export of mzTab-M 2.1 files from Summarized Experiment
2026-07-17
Source:vignettes/generation_of_mzTabM_file.qmd
Introduction
The file mzTab-M is a lightweight, tab-delimited file format for reporting quantitative results from metabolomics/lipidomics approaches. This format aims to give local LIMS systems and MS metabolomics repositories a simple way to share and combine basic information.
This document shows how to export and import a mzTab-M file into R via the package RmzTabM, which provides the API and core functionality to read and write files in mzTab-M format.
The RmzTabM package supports mzTab-M version 2.1.
For a general overview of the mzTab-M format see this figure.

For a description of the mzTab-M format and the set of mandatory and optional fields refer to the official format definition.
General information on the mzTab-M format
The mzTab-M format consists of four cross-referenced data tables: metadata (MTD), Small Molecule (SML), Small Molecule Feature (SMF) and the Small Molecule Evidence (SME). The MTD section is supposed to contain all experiment and measurement relevant information. The SML section contains the final results of an analysis that should be reported, i.e., the (annotated) molecules and their respective abundances. The SMF section contains information on the measured (LC-MS) features and their abundance values. The SME section contains information on the annotation process (and reliability) of the molecules reported in the SML section. The SML is supposed to be a subset of the SMF table. The structure and relationship between rows in these different tables is defined by the mzTab-M standard and follows strict rules. All mzTab-M files are validated using either the online or local Java validator to ensure compliance. In RmzTabM, this validation is executed locally via the offline Java tool.
Package
## Data Import and handling
library(alabaster.base)
library(MsIO)
library(xcms)
library(SummarizedExperiment)Export of a SummarizedExperiment into mzTab-M file
Data import
In this document we export the preprocessed data set used in the Metabonaut end-to-end metabolomics data workflow in mzTab-M format, based on the Metabolights data set MTBLS8735. After collecting all necessary experimental metadata, we export this result object as a mzTab-M file with only the metadata and the small feature abundances (MTD+SMF).
## load preprocessed dataset
se <- readObject(system.file("extdata", "preprocessed_res",
package = "Metabonaut"))Creation of MzTabM object
The RmzTabM package defines a MzTabM() convenience function to create a mzTab-M file from a SummarizedExperiment object. Information provided in such objects is automatically converted and formatted into content for the right mzTab-M section. The user simply needs to define the columns containing information for the various mzTab-M fields and a mzTab-M is compiled. This MzTabM object should then be completed adding any missing data.
Define missing data set’s metadata (MTD)
Comprehensive data set descriptions and metadata are important to enable re-use of the data and follow FAIR principles. The mzTab-M format has stringent requirement for mandatory fields and their format. Most of the fields are CV parameters and the PSI Mass Spectrometry Controlled Vocabulary (PSI-MS) is the primary CV used to annotate mass spectrometry-specific fields in mzTab-M. It was built collaboratively by MS software vendors and academic groups working in mass spectrometry and MS informatics. The CV is community-maintained: new terms can be requested through the PSI-MS mailing list. For more details see the mzTab-M specification, section 4.2 “The PSI Mass Spectrometry Controlled Vocabulary (CV)”. We need to add/adapt some columns of the SummarizedExperiment’s colData() to complete or match the expected format:
- use a CV param for species:
"[NCBITaxon, NCBITaxon:9606, Homo sapiens, ]" - use a CV param for blood plasma:
"[BTO, BTO:0000131, blood plasma, ]" - use a CV param for blood serum:
"[BTO, BTO:0000133, blood serum, ]" - add polarity information.
- assign the same name to all sample pools.
- Add the MS instrument.
colData(se)$species <- "[NCBITaxon, NCBITaxon:9606, Homo sapiens, ]"
colData(se)$tissue <- "[BTO, BTO:0000131, blood plasma, ]"
colData(se)$tissue[colData(se)$blood_sample_type == "blood serum"] <-
"[BTO, BTO:0000133, blood serum, ]"
colData(se)$polarity <- "positive"
colData(se)$sample_name[grep("POOL", colData(se)$sample_name)] <- "POOL"
colData(se)$instrument <- "1"Note
ℹ️ ideally, CV parameters should be used as much as possible to ensure a standardized description of the data. The EMBL-EBI Ontology Lookup Service can be used to find ontology terms (CV parameters) for various controlled vocabularies.
Define Metadata (MTD) section
Now we can use the previous information to compile the data set’s metadata. To this end we define the column names in the SummarizedExperiment’s colData() that contain information for sample, measurement run and assay mzTab-M fields. This mapping of mzTab-M fields to column names can be defined with the sampleCols(), msRunCols() and assayCols() helper functions. We use for example the content of the column "sample_name" for the mzTab-M sample name. Content from the colData() columns "species", "tissue" and "sample_type" is used for mzTab-M sample fields species, tissue and sample_type.
## define mapping of `colData()` column names to mzTab-M sample fields
scols <- sampleCols(sample = "sample_name", species = "species",
tissue = "tissue", sample_type = "sample_type")Similarly we specify columns from the same colData() with information on individual MS runs (and assays):
The column "derived_spectra_data_file" contains the MS data file name which we use both to define the MS runs and assays (assuming thus a 1:1 mapping between them).
colData(se)$derived_spectra_data_file [1] "FILES/MS_QC_POOL_1_POS.mzML" "FILES/MS_A_POS.mzML"
[3] "FILES/MS_B_POS.mzML" "FILES/MS_QC_POOL_2_POS.mzML"
[5] "FILES/MS_C_POS.mzML" "FILES/MS_D_POS.mzML"
[7] "FILES/MS_QC_POOL_3_POS.mzML" "FILES/MS_E_POS.mzML"
[9] "FILES/MS_F_POS.mzML" "FILES/MS_QC_POOL_4_POS.mzML"
At last we define also the study variables of the experiment. These can be technical characteristics or phenotype(s) of the samples. The present experiment consists of plasma samples of individuals with or without a cardiovascular disease (CVD) and repeated measurements of an external (serum) sample pools that was used as quality control sample. These are defined in colData() columns "blood_sample_type", "age" and "phenotype".
| blood_sample_type | phenotype | age | |
|---|---|---|---|
| MS_QC_POOL_1_POS.mzML | blood serum | QC | NA |
| MS_A_POS.mzML | blood plasma | CVD | 53 |
| MS_B_POS.mzML | blood plasma | CTR | 30 |
| MS_QC_POOL_2_POS.mzML | blood serum | QC | NA |
| MS_C_POS.mzML | blood plasma | CTR | 66 |
| MS_D_POS.mzML | blood plasma | CVD | 36 |
| MS_QC_POOL_3_POS.mzML | blood serum | QC | NA |
| MS_E_POS.mzML | blood plasma | CTR | 66 |
| MS_F_POS.mzML | blood plasma | CVD | 44 |
| MS_QC_POOL_4_POS.mzML | blood serum | QC | NA |
With this information defined we can use the MzTabM() function to create a template mzTab-M for the present experiment. Parameter groups defines the column names of the SummarizedExperiment’s colData() to be used as mzTab-M study variable groups.
mzt <- MzTabM(se, id = "MTBLS8735", sampleCols = scols,
msRunCols = mscols, assayCols = acols,
groups = c("age", "phenotype", "blood_sample_type"))
mztObject of class MzTabM
mzTab-M version 2.1.0-M
MTD section with 189 rows.
This MzTabM object contains only metadata information, but no abundances/feature data yet. Also, some general metadata are still missing and, if exported to a mzTab-M file, it might not yet validate. We are next adding the small molecule feature (SMF) content and, in the subsequent section Completing the metadata content, adding any missing required metadata fields.
Add feature abundance matrix (SMF)
We next add feature abundance information to the mzTab-M. While the abundance values can be taken from one of the assay()s from the SummarizedExperiment, we need to provide also feature characteristics. These are usually available in the SummarizedExperiments rowData():
| mzmed | mzmin | mzmax | rtmed | rtmin | rtmax | npeaks | CTR | CVD | QC | ms_level | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| FT0001 | 50.98979 | 50.98949 | 50.99038 | 203.6001 | 203.1181 | 204.2331 | 8 | 1 | 3 | 4 | 1 |
| FT0002 | 51.05904 | 51.05880 | 51.05941 | 191.1675 | 190.8787 | 191.5050 | 9 | 2 | 3 | 4 | 1 |
| FT0003 | 51.98657 | 51.98631 | 51.98699 | 203.1467 | 202.6406 | 203.6710 | 7 | 0 | 3 | 4 | 1 |
| FT0004 | 53.02036 | 53.02009 | 53.02043 | 203.2343 | 202.5652 | 204.0901 | 10 | 3 | 3 | 4 | 1 |
| FT0005 | 53.52080 | 53.52051 | 53.52102 | 203.1936 | 202.8490 | 204.0901 | 10 | 3 | 3 | 4 | 1 |
| FT0006 | 54.01007 | 54.00988 | 54.01015 | 159.2816 | 158.8499 | 159.4484 | 6 | 1 | 3 | 2 | 1 |
For our example we use column "mzmed" which defines the features median m/z value which can be mapped to the SMF field exp_mass_to_charge and "rtmed" that reports the median retention time of the feature which can be used for the SMF field retention_time_in_seconds. We will in addition add an optional field feature_id to report and add the IDs of the individual features from the SummarizedExperiment, which we add as a column "feature_id" to the rowData():
Similar to the metadata column mappings above, we define a mapping of SMF fields to rowData() columns using the smfCols() helper function:
smf_cols <- smfCols(exp_mass_to_charge = "mzmed",
retention_time_in_seconds = "rtmed",
feature_id = "feature_id")Providing these additional SMF mapping in the MzTabM() call above will compile a MzTabM object with an MTD and SMF section from the SummarizedExperiment. Parameter assayName defines which of the SummarizedExperiment’s assays will be used the SMF section.
## Create a MTD+SMF MzTabM object from the SummarizedExperiment
mzt <- MzTabM(se, id = "MTBLS8735", sampleCols = scols,
msRunCols = mscols, assayCols = acols,
groups = c("age", "phenotype", "blood_sample_type"),
smfCols. = smf_cols, assayName = "raw_filled")
mztObject of class MzTabM
mzTab-M version 2.1.0-M
MTD section with 189 rows.
SMF section with 9068 rows and 22 columns.
Note
ℹ️ we could also use
smf(se, assayName = "raw_filled", smfCols. = smf_cols)to extract the SMF table from theSummarizedExperimentand add that manually to theMzTabMobject.
This mzt variable now contains the mzTab-M content that could be extracted from the SummarizedExperiment. The first rows of the metadata section are:
| Field | Value |
|---|---|
| mzTab-version | 2.1.0-M |
| mzTab-ID | MTBLS8735 |
| software[1] | [,,RmzTabM,RmzTabM version 0.97.18] |
| quantification_method | [MS, MS:1001834, LC-MS label-free quantitation analysis, ] |
| sample[1] | POOL |
| sample[1]-species[1] | [NCBITaxon, NCBITaxon:9606, Homo sapiens, ] |
And the first lines of the SMF section:
| SFH | SMF_ID | SME_ID_REFS | SME_ID_REF_ambiguity_code | adduct_ion | isotopomer | exp_mass_to_charge | charge | retention_time_in_seconds | retention_time_in_seconds_start | retention_time_in_seconds_end | abundance_assay[1] | abundance_assay[2] | abundance_assay[3] | abundance_assay[4] | abundance_assay[5] | abundance_assay[6] | abundance_assay[7] | abundance_assay[8] | abundance_assay[9] | abundance_assay[10] | opt_global_feature_id | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| FT0001 | SMF | 1 | null | null | null | null | 50.9897946401403 | null | 203.600077134134 | null | null | 421.6162 | 689.2422 | 411.3295 | 481.7436 | 314.7567 | 635.2732 | 439.6086 | 570.5849 | 579.9360 | 437.0340 | FT0001 |
| FT0002 | SMF | 2 | null | null | null | null | 51.059035992328 | null | 191.167453757996 | null | null | 710.8078 | 875.9192 | 457.5920 | 693.6997 | 781.2416 | 648.4344 | 700.9716 | 1054.0207 | 534.4577 | 711.0361 | FT0002 |
| FT0003 | SMF | 3 | null | null | null | null | 51.9865730172271 | null | 203.14665178874 | null | null | 445.5711 | 613.4410 | 277.5022 | 497.8866 | 425.3774 | 634.9370 | 449.0933 | 556.2544 | 461.0465 | 232.1075 | FT0003 |
| FT0004 | SMF | 4 | null | null | null | null | 53.0203569195002 | null | 203.234292327779 | null | null | 16994.5260 | 24605.7340 | 19766.7069 | 17808.0933 | 22780.6683 | 22873.1061 | 16965.7762 | 23432.1252 | 22198.4607 | 16796.4497 | FT0004 |
| FT0005 | SMF | 5 | null | null | null | null | 53.5208004472819 | null | 203.193618564868 | null | null | 3284.2664 | 4526.0531 | 3521.8221 | 3379.8909 | 4396.0762 | 4317.7734 | 3270.5290 | 4533.8667 | 4161.0132 | 3142.2268 | FT0005 |
| FT0006 | SMF | 6 | null | null | null | null | 54.0100702952703 | null | 159.281630787851 | null | null | 10681.7476 | 10009.6602 | 9599.9701 | 10800.5449 | 4792.2390 | 7296.4262 | 2382.1788 | 9236.9799 | 6817.8785 | 6911.5439 | FT0006 |
The object now has MTD and SMF sections, but some required metadata still must be added manually before export. In the next section we will complete the data adding some metadata fields that could not be derived from the result object.
Completing the metadata content
Some of the metadata information must be manually added, because it can not be extracted from the SummarizedExperiment. This depends also on the information compiled into the mzTab-M file. We used for example the BTO and NCBITaxon ontologies to describe the samples, but these two are not added by default. The getMtdCv() function can be used to get the set of defined controlled vocabularies (ontologies) in the MzTabM object:
| Field | Value |
|---|---|
| cv[1]-label | MS |
| cv[1]-full_name | PSI-MS controlled vocabulary |
| cv[1]-version | 4.1.138 |
| cv[1]-uri | https://raw.githubusercontent.com/HUPO-PSI/psi-ms-CV/master/psi-ms.obo |
| cv[2]-label | PRIDE |
| cv[2]-full_name | PRIDE PRoteomics IDEntifications (PRIDE) database controlled vocabulary |
| cv[2]-version | 16:10:2023 11:38 |
| cv[2]-uri | https://www.ebi.ac.uk/ols/ontologies/pride |
| cv[3]-label | STATO |
| cv[3]-full_name | General purpose STATistics Ontology |
| cv[3]-version | 2026-04-20 |
| cv[3]-uri | https://www.ebi.ac.uk/ols4/ontologies/stato |
We therefore need to add the two missing vocabularies:
Also, we add xcms as software to the MzTabM:
mzt <- setMtdField(mzt, "software", "[MS, MS:1001582, xcms, 4.10.0]")
getMtdField(mzt, "software") software[1] software[2]
"[,,RmzTabM,RmzTabM version 0.97.18]" "[MS, MS:1001582, xcms, 4.10.0]"
Next, we need to add instrument information to the MzTabM object.
## Adding MS instrument information.
mzt <- setMtdInstrument(mzt,
name = "[MS, MS:1002584, AB Sciex TripleTOF 5600+, ]",
source = "[MS, MS:1000073, ESI, ]",
analyzer = c(`analyzer[1]` =
"[MS, MS:1003763, quadrupole time-of-flight instrument, ]"),
detector = "[,,null,null]")Finally, we add the contact information:
mzt <- setMtdContact(mzt,
name = c("Philippine Louail", "Johannes Rainer"),
affiliation= c("Institute for Biomedicine, Eurac Research, Bolzano, Italy",
"Institute for Biomedicine, Eurac Research, Bolzano, Italy"),
email = c("philippine.louail@eurac.edu", "johannes.rainer@eurac.edu"),
orcid = c("0009-0007-5429-6846", "0000-0002-6977-7147"))Now we have a complete mzTab-M content compiled and can proceed to export it.
Export MzTabM object to an mzTab-M file
The MzTabM object, containing the MTD and SMF sections, is ready for export to an mzTab-M file. Following generation, the file is verified using the mzTab-M validator.
writeMzTabM(mzt, path = file.path(tempdir(), "MTBLS8735_mtd_smf.mzTab"))Import of a SummarizedExperiment from mzTab-M file
The mzTab-M file generated above can be read back into R using the readMzTabM() function. The file is verified using the mzTab-M validator and loaded into a MzTabM object.
mzt_r <- readMzTabM(file.path(tempdir(), "MTBLS8735_mtd_smf.mzTab"))
mzt_rObject of class MzTabM
mzTab-M version 2.1.0-M
MTD section with 210 rows.
SMF section with 9068 rows and 22 columns.
Now we have a MzTabM object with the MTD and SMF sections loaded. To make it easier to work with the data, we can convert it to a SummarizedExperiment object using the makeSummarizedExperimentFromMzTabM() function. By default, the function will use as feature IDs the values in the columns SMF_ID and keep the column names of the rowData as reported in the SMF header. In this case, we want to use the original feature IDs from the rowData of the SummarizedExperiment object that are in the optional SMF field opt_global_feature_id. We also specify the mapping of the SMF fields to the original rowData columns using the smfCols define above.
se_r <- makeSummarizedExperimentFromMzTabM(
mzt_r,
rowIdCol = "opt_global_feature_id",
smfCols. = smf_cols,
assayName = "raw_filled"
)
se_rclass: SummarizedExperiment
dim: 9068 10
metadata(0):
assays(1): raw_filled
rownames(9068): FT0001 FT0002 ... FT9067 FT9068
rowData names(4): SMF_ID mzmed rtmed opt_global_feature_id
colnames(10): MS_QC_POOL_1_POS.mzML MS_A_POS.mzML ... MS_F_POS.mzML
MS_QC_POOL_4_POS.mzML
colData names(18): id sample_ref ... phenotype blood_sample_type
The reconstructed SummarizedExperiment contains the same measurement data. Differences in rowData and colData reflect that only fields present in the SMF and MTD sections are loaded and that column names follow the mzTab-M specification.
Outlook
Exporting analysis results to mzTab-M plugs a given workflow into a broader ecosystem of standardized, interoperable metabolomics data. A few reasons why this matters:
Interoperability: mzTab-M is a community-endorsed standard developed under the HUPO Proteomics Standards Initiative (PSI). Results exported in this format can be read, compared, and re-analyzed by any tool that supports the standard, eliminating the need to write custom parsers for every combination of software.
Reproducibility and Reuse: A self-contained, well-documented results file makes it much easier for others to understand exactly how a set of features, identifications, and quantification values were derived.
FAIR Data: Exporting directly to this format lowers the barrier to sharing data following the FAIR principles, which in turn supports meta-analyses and the reuse of published datasets. It also simplifies the submission process for new datasets to online repositories.
At present, this package supports the import and export of mzTab-M files as SummarizedExperiment objects. The next step is to support exporting mzTab-M directly from xcms result objects, without an intermediate manual conversion step. This would make it straightforward to go from raw data processing in xcms to a deposition- or exchange-ready mzTab-M file in a single, reproducible pipeline.
Session information
R version 4.6.1 (2026-06-24)
Platform: x86_64-pc-linux-gnu
Running under: Ubuntu 24.04.4 LTS
Matrix products: default
BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so; LAPACK version 3.12.0
locale:
[1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
[3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
[5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
[7] LC_PAPER=en_US.UTF-8 LC_NAME=C
[9] LC_ADDRESS=C LC_TELEPHONE=C
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
time zone: Etc/UTC
tzcode source: system (glibc)
attached base packages:
[1] stats4 stats graphics grDevices utils datasets methods
[8] base
other attached packages:
[1] SummarizedExperiment_1.42.0 Biobase_2.72.0
[3] GenomicRanges_1.64.0 Seqinfo_1.2.0
[5] IRanges_2.46.0 S4Vectors_0.50.1
[7] BiocGenerics_0.58.1 generics_0.1.4
[9] MatrixGenerics_1.24.0 matrixStats_1.5.0
[11] xcms_4.10.1 BiocParallel_1.46.0
[13] MsIO_0.0.17 alabaster.base_1.12.1
[15] RmzTabM_0.97.18 BiocStyle_2.40.0
[17] quarto_1.5.1.9002 knitr_1.51
loaded via a namespace (and not attached):
[1] DBI_1.3.0 rlang_1.3.0
[3] magrittr_2.0.5 clue_0.3-68
[5] MassSpecWavelet_1.78.2 otel_0.2.0
[7] compiler_4.6.1 PTMods_1.0.0
[9] vctrs_0.7.3 reshape2_1.4.5
[11] stringr_1.6.0 ProtGenerics_1.44.0
[13] crayon_1.5.3 pkgconfig_2.0.3
[15] MetaboCoreUtils_1.20.1 fastmap_1.2.0
[17] XVector_0.52.0 rmarkdown_2.31
[19] ps_1.9.3 preprocessCore_1.74.0
[21] purrr_1.2.2 xfun_0.60
[23] MultiAssayExperiment_1.38.0 jsonlite_2.0.0
[25] progress_1.2.3 later_1.4.8
[27] rhdf5filters_1.24.0 DelayedArray_0.38.2
[29] Rhdf5lib_2.0.0 prettyunits_1.2.0
[31] parallel_4.6.1 cluster_2.1.8.2
[33] R6_2.6.1 stringi_1.8.7
[35] RColorBrewer_1.1-3 limma_3.68.4
[37] iterators_1.0.14 Rcpp_1.1.2
[39] Matrix_1.7-5 igraph_2.3.3
[41] tidyselect_1.2.1 rstudioapi_0.19.0
[43] abind_1.4-8 yaml_2.3.12
[45] doParallel_1.0.17 codetools_0.2-20
[47] affy_1.90.0 processx_3.9.0
[49] lattice_0.22-9 tibble_3.3.1
[51] plyr_1.8.9 S7_0.2.2
[53] evaluate_1.0.5 Spectra_1.22.2
[55] alabaster.schemas_1.12.0 pillar_1.11.1
[57] affyio_1.82.0 BiocManager_1.30.27
[59] foreach_1.5.2 MSnbase_2.37.0
[61] MALDIquant_1.22.3 ncdf4_1.24
[63] hms_1.1.4 ggplot2_4.0.3
[65] scales_1.4.0 MsExperiment_1.14.0
[67] alabaster.ranges_1.12.0 glue_1.8.1
[69] alabaster.matrix_1.12.0 MsFeatures_1.20.0
[71] lazyeval_0.2.3 tools_4.6.1
[73] mzID_1.50.0 data.table_1.18.4
[75] QFeatures_1.22.0 vsn_3.80.0
[77] mzR_2.46.0 fs_2.1.0
[79] XML_3.99-0.23 rhdf5_2.56.0
[81] grid_4.6.1 impute_1.86.0
[83] tidyr_1.3.2 MsCoreUtils_1.24.0
[85] PSMatch_1.16.0 HDF5Array_1.40.0
[87] cli_3.6.6 S4Arrays_1.12.0
[89] dplyr_1.2.1 AnnotationFilter_1.36.0
[91] pcaMethods_2.4.0 gtable_0.3.6
[93] alabaster.se_1.12.0 digest_0.6.39
[95] SparseArray_1.12.2 farver_2.1.2
[97] htmltools_0.5.9 lifecycle_1.0.5
[99] h5mread_1.4.0 statmod_1.5.2
[101] MASS_7.3-66