HuMMANet is a Bioconductor experiment data package for paired human
microbiome-metabolome studies. It provides a unified interface to curated
study-level species profiles, original and harmonized metabolite profiles,
matched sample metadata, and study-specific annotation resources, with study
data distributed through ExperimentHub.
The central motivation for the package is to provide a reusable resource for paired study species and metabolite data together with supporting annotations, so that users can work with these studies in a consistent and reproducible way. Rather than manually assembling heterogeneous files from individual studies, users can access matched tables and annotation resources through a common API in the Bioconductor ecosystem.
Typical use cases for HuMMANet include:
Each study bundle can include the following modalities:
MetadataProfile: sample-level study metadata, including sample identifiers,
subject or participant annotations, clinical covariates, longitudinal labels,
body site information, and other variables needed to interpret the study.taxaAbundanceProfile: the curated microbial abundance table for a study,
aligned to the study samples and representing taxa or related microbial
features.OriginalMetaboliteProfile: the curated metabolomics matrix prior to
HuMMANet harmonization, preserving the original study-specific metabolite
feature space.harmonizedMetaboliteProfile: the HuMMANet-processed metabolomics matrix
after harmonization, designed to support more consistent comparisons across
studies.metaboliteIdentifierMapping: metabolite identifier mapping tables that link
HuMMANet identifiers to external resources such as HMDB, PubChem, KEGG,
ChEBI, structural descriptors, and standardized metabolite names.microbialProducerAnnotations: curated annotations linking metabolites to
potential microbial producers or species-level producer evidence.metaboliteDiseaseAssociations: curated disease associations for metabolites
represented in a study.metabolitePathwayAnnotations: curated pathway annotations for study
metabolites.drugBankSimilarityMatches: DrugBank similarity matches for study
metabolites.drugCentralSimilarityMatches: DrugCentral similarity matches for study
metabolites.Each study is represented as a MultiAssayExperiment object:
colData() stores the MetadataProfileexperiments() stores assay-level containers for
taxaAbundanceProfile, OriginalMetaboliteProfile, and
harmonizedMetaboliteProfilemetadata()This representation is useful because it keeps the paired modalities for a
study synchronized through a shared sample-level metadata table while still
allowing each assay to preserve its own feature space and feature annotations.
For example, microbial taxa and metabolites do not share the same rows, but
they do share the same study samples. MultiAssayExperiment is designed
exactly for this setting.
Within each study object:
taxaAbundanceProfile is stored as a SummarizedExperiment containing a
taxa-by-sample abundance matrix.OriginalMetaboliteProfile is stored as a SummarizedExperiment containing
the original curated metabolite feature table for the study.harmonizedMetaboliteProfile is stored as a SummarizedExperiment
containing the harmonized metabolite table together with feature-level
identifier annotations in rowData().metadata() because they are
annotation tables rather than sample-by-feature assay matrices.The package is structured as a lightweight ExperimentHub interface package.
Large study bundles live outside the source tarball, while the package ships
the accessor functions, metadata, and documentation needed to discover and load
those resources reproducibly.
Install from Bioconductor:
if (!requireNamespace("BiocManager", quietly = TRUE)) {
install.packages("BiocManager")
}
BiocManager::install("HuMMANet")
Install the development version from GitHub:
if (!requireNamespace("remotes", quietly = TRUE)) {
install.packages("remotes")
}
remotes::install_github("ShivangiV-IIITD/HuMMANet")
library(HuMMANet)
library(MultiAssayExperiment)
#> Loading required package: SummarizedExperiment
#> Loading required package: MatrixGenerics
#> Loading required package: matrixStats
#>
#> Attaching package: 'MatrixGenerics'
#> The following objects are masked from 'package:matrixStats':
#>
#> colAlls, colAnyNAs, colAnys, colAvgsPerRowSet, colCollapse,
#> colCounts, colCummaxs, colCummins, colCumprods, colCumsums,
#> colDiffs, colIQRDiffs, colIQRs, colLogSumExps, colMadDiffs,
#> colMads, colMaxs, colMeans2, colMedians, colMins, colOrderStats,
#> colProds, colQuantiles, colRanges, colRanks, colSdDiffs, colSds,
#> colSums2, colTabulates, colVarDiffs, colVars, colWeightedMads,
#> colWeightedMeans, colWeightedMedians, colWeightedSds,
#> colWeightedVars, rowAlls, rowAnyNAs, rowAnys, rowAvgsPerColSet,
#> rowCollapse, rowCounts, rowCummaxs, rowCummins, rowCumprods,
#> rowCumsums, rowDiffs, rowIQRDiffs, rowIQRs, rowLogSumExps,
#> rowMadDiffs, rowMads, rowMaxs, rowMeans2, rowMedians, rowMins,
#> rowOrderStats, rowProds, rowQuantiles, rowRanges, rowRanks,
#> rowSdDiffs, rowSds, rowSums2, rowTabulates, rowVarDiffs, rowVars,
#> rowWeightedMads, rowWeightedMeans, rowWeightedMedians,
#> rowWeightedSds, rowWeightedVars
#> Loading required package: GenomicRanges
#> Loading required package: stats4
#> Loading required package: BiocGenerics
#> Loading required package: generics
#>
#> Attaching package: 'generics'
#> The following objects are masked from 'package:base':
#>
#> as.difftime, as.factor, as.ordered, intersect, is.element, setdiff,
#> setequal, union
#>
#> Attaching package: 'BiocGenerics'
#> The following objects are masked from 'package:stats':
#>
#> IQR, mad, sd, var, xtabs
#> The following object is masked from 'package:utils':
#>
#> data
#> The following objects are masked from 'package:base':
#>
#> Filter, Find, Map, Position, Reduce, anyDuplicated, aperm, append,
#> as.data.frame, basename, cbind, colnames, dirname, do.call,
#> duplicated, eval, evalq, get, grep, grepl, is.unsorted, lapply,
#> mapply, match, mget, order, paste, pmax, pmax.int, pmin, pmin.int,
#> rank, rbind, rownames, sapply, saveRDS, scale, sequence, table,
#> tapply, transform, unique, unsplit, which.max, which.min
#> Loading required package: S4Vectors
#>
#> Attaching package: 'S4Vectors'
#> The following object is masked from 'package:utils':
#>
#> findMatches
#> The following objects are masked from 'package:base':
#>
#> I, expand.grid, unname
#> Loading required package: IRanges
#> Loading required package: Seqinfo
#> Loading required package: Biobase
#> Welcome to Bioconductor
#>
#> Vignettes contain introductory material; view with
#> 'browseVignettes()'. To cite Bioconductor, see
#> 'citation("Biobase")', and for packages 'citation("pkgname")'.
#>
#> Attaching package: 'Biobase'
#> The following object is masked from 'package:MatrixGenerics':
#>
#> rowMedians
#> The following objects are masked from 'package:matrixStats':
#>
#> anyMissing, rowMedians
library(SummarizedExperiment)
studies <- HuMMANet_studies()
length(studies)
#> [1] 55
head(studies)
#> [1] "BarkerTejedaTC_2024_Targeted" "BarkerTejedaTC_2024_Untargeted"
#> [3] "CarterM_2025" "ChengT_2024_F"
#> [5] "ChengT_2024_S" "ConleyT_2024"
The study identifiers returned by HuMMANet_studies() are the main entry points
for downstream loading. These identifiers are also present in the study index,
which can be used to inspect available modalities before loading a full study
object.
idx <- HuMMANet_study_index()
head(
idx[, c(
"study",
"has_MetadataProfile",
"has_taxaAbundanceProfile",
"has_OriginalMetaboliteProfile",
"has_harmonizedMetaboliteProfile"
)]
)
#> study has_MetadataProfile has_taxaAbundanceProfile
#> 1 BarkerTejedaTC_2024_Targeted TRUE TRUE
#> 2 BarkerTejedaTC_2024_Untargeted TRUE TRUE
#> 3 CarterM_2025 TRUE TRUE
#> 4 ChengT_2024_F TRUE TRUE
#> 5 ChengT_2024_S TRUE TRUE
#> 6 ConleyT_2024 TRUE TRUE
#> has_OriginalMetaboliteProfile has_harmonizedMetaboliteProfile
#> 1 TRUE TRUE
#> 2 TRUE TRUE
#> 3 TRUE TRUE
#> 4 TRUE TRUE
#> 5 TRUE TRUE
#> 6 TRUE TRUE
The study index provides one row per study. In addition to the study identifier, it records availability flags and file-level information for the metadata, species, original metabolite, harmonized metabolite, and annotation resources. This is useful when deciding which studies and which data layers to retrieve for a particular analysis.
The study-loading examples below illustrate the intended user workflow through the package accessors.
study_id <- idx$study[[1]]
available <- HuMMANet_available_modalities(
study_id
)
available
#> [1] "MetadataProfile" "taxaAbundanceProfile"
#> [3] "OriginalMetaboliteProfile" "harmonizedMetaboliteProfile"
#> [5] "metaboliteIdentifierMapping" "microbialProducerAnnotations"
#> [7] "metaboliteDiseaseAssociations" "metabolitePathwayAnnotations"
#> [9] "drugBankSimilarityMatches" "drugCentralSimilarityMatches"
one_study <- HuMMANet_load_study(
study_id
)
class(one_study)
#> [1] "MultiAssayExperiment"
#> attr(,"package")
#> [1] "MultiAssayExperiment"
names(experiments(one_study))
#> [1] "taxaAbundanceProfile" "OriginalMetaboliteProfile"
#> [3] "harmonizedMetaboliteProfile"
colData(one_study)[1:3, 1:6]
#> DataFrame with 3 rows and 6 columns
#> sample_id study_name Age BMI seq_type
#> <character> <character> <numeric> <logical> <character>
#> Moth_50_T Moth_50_T BarkerTejedaTC_2024_.. 33 NA WGS
#> Moth_66_T Moth_66_T BarkerTejedaTC_2024_.. 28 NA WGS
#> Gran_22_T Gran_22_T BarkerTejedaTC_2024_.. 60 NA WGS
#> country
#> <character>
#> Moth_50_T ESP
#> Moth_66_T ESP
#> Gran_22_T ESP
At this point one_study is a MultiAssayExperiment. The assay names returned
by experiments(one_study) correspond to the core quantitative data layers,
while colData(one_study) contains the matched sample metadata shared across
those assays.
experiments(one_study)
#> ExperimentList class object of length 3:
#> [1] taxaAbundanceProfile: SummarizedExperiment with 677 rows and 122 columns
#> [2] OriginalMetaboliteProfile: SummarizedExperiment with 14 rows and 122 columns
#> [3] harmonizedMetaboliteProfile: SummarizedExperiment with 14 rows and 122 columns
sampleMap(one_study)
#> DataFrame with 366 rows and 3 columns
#> assay primary colname
#> <factor> <character> <character>
#> 1 taxaAbundanceProfile Moth_50_T Moth_50_T
#> 2 taxaAbundanceProfile Moth_66_T Moth_66_T
#> 3 taxaAbundanceProfile Gran_22_T Gran_22_T
#> 4 taxaAbundanceProfile Gran_49_T Gran_49_T
#> 5 taxaAbundanceProfile Gran_32_T Gran_32_T
#> ... ... ... ...
#> 362 harmonizedMetaboliteProfile Inf_22_T Inf_22_T
#> 363 harmonizedMetaboliteProfile Moth_17_T Moth_17_T
#> 364 harmonizedMetaboliteProfile Gran_09_T Gran_09_T
#> 365 harmonizedMetaboliteProfile Moth_11_T Moth_11_T
#> 366 harmonizedMetaboliteProfile Inf_07_T Inf_07_T
experiments(one_study) lists the assay-level objects stored in the study.
Each of these is a SummarizedExperiment, so standard Bioconductor accessors
such as assay(), rowData(), and colData() can be used on the individual
assays. sampleMap(one_study) records how assay-level columns map back to the
shared study-level sample metadata.
metadata_profile <- HuMMANet_load_modality(
study_id,
"MetadataProfile"
)
dim(metadata_profile)
#> [1] 122 21
head(metadata_profile[, seq_len(min(6, ncol(metadata_profile)))])
#> sample_id study_name Age BMI seq_type country
#> Moth_50_T Moth_50_T BarkerTejedaTC_2024_Targeted 33 NA WGS ESP
#> Moth_66_T Moth_66_T BarkerTejedaTC_2024_Targeted 28 NA WGS ESP
#> Gran_22_T Gran_22_T BarkerTejedaTC_2024_Targeted 60 NA WGS ESP
#> Gran_49_T Gran_49_T BarkerTejedaTC_2024_Targeted 61 NA WGS ESP
#> Gran_32_T Gran_32_T BarkerTejedaTC_2024_Targeted 58 NA WGS ESP
#> Gran_28_T Gran_28_T BarkerTejedaTC_2024_Targeted 62 NA WGS ESP
This is equivalent to inspecting as.data.frame(colData(one_study)), but the
modality accessor is convenient when you want the metadata table directly for
custom joins or downstream analysis.
original_profile <- HuMMANet_load_modality(
study_id,
"OriginalMetaboliteProfile"
)
class(original_profile)
#> [1] "SummarizedExperiment"
#> attr(,"package")
#> [1] "SummarizedExperiment"
dim(assay(original_profile))
#> [1] 14 122
head(rownames(original_profile))
#> [1] "GABA" "Choline" "Cadaverine" "Putrescine"
#> [5] "Tryptophan" "Aspartic Acid"
head(colnames(original_profile))
#> [1] "Moth_50_T" "Moth_66_T" "Gran_22_T" "Gran_49_T" "Gran_32_T" "Gran_28_T"
The quantitative assay matrix is accessed with assay(original_profile). As in
all SummarizedExperiment objects, rows correspond to features and columns
correspond to samples. This makes it straightforward to extract the original
study-specific metabolite matrix while preserving its feature identities.
harmonized_profile <- HuMMANet_load_modality(
study_id,
"harmonizedMetaboliteProfile"
)
class(harmonized_profile)
#> [1] "SummarizedExperiment"
#> attr(,"package")
#> [1] "SummarizedExperiment"
dim(assay(harmonized_profile))
#> [1] 14 122
head(
rowData(harmonized_profile)[, seq_len(min(6, ncol(rowData(harmonized_profile))))]
)
#> DataFrame with 6 rows and 6 columns
#> HuMANet_ID Query_Name Database_Source InChIKey
#> <character> <character> <character> <character>
#> (+/-)-Tryptophan NA NA NA NA
#> 1,5-Diaminopentane NA NA NA NA
#> 16.89_propanoic acid NA NA NA NA
#> 20.13_butanoic acid NA NA NA NA
#> 26.93_hexanoic acid NA NA NA NA
#> 4-Aminobutyrate NA NA NA NA
#> HMDB_ID PubChem_CID
#> <character> <numeric>
#> (+/-)-Tryptophan NA NA
#> 1,5-Diaminopentane NA NA
#> 16.89_propanoic acid NA NA
#> 20.13_butanoic acid NA NA
#> 26.93_hexanoic acid NA NA
#> 4-Aminobutyrate NA NA
The harmonized metabolite profile is especially useful for cross-study
comparison because the feature layer is paired with identifier-level annotation
in rowData(harmonized_profile). This allows users to inspect harmonized
metabolite identifiers, names, and external database mappings alongside the
quantitative matrix.
taxa_profile <- HuMMANet_load_modality(
study_id,
"taxaAbundanceProfile"
)
class(taxa_profile)
#> [1] "SummarizedExperiment"
#> attr(,"package")
#> [1] "SummarizedExperiment"
dim(assay(taxa_profile))
#> [1] 677 122
head(rownames(taxa_profile))
#> [1] "Abiotrophia_defectiva" "Abiotrophia_sp_HMSC24B09"
#> [3] "Acetobacter_sp_CAG_267" "Acholeplasma_sp_CAG_878"
#> [5] "Acidaminococcus_fermentans" "Acidaminococcus_intestini"
head(colnames(taxa_profile))
#> [1] "Moth_50_T" "Moth_66_T" "Gran_22_T" "Gran_49_T" "Gran_32_T" "Gran_28_T"
This assay stores the microbial feature abundance matrix for the study. Because
it is also represented as a SummarizedExperiment, it can be handled with the
same accessors as the metabolite assays, which keeps the study workflow
consistent across modalities.
pathway_annotations <- HuMMANet_load_modality(
study_id,
"metabolitePathwayAnnotations"
)
dim(pathway_annotations)
#> [1] 2058 11
head(pathway_annotations[, seq_len(min(6, ncol(pathway_annotations)))])
#> HuMANet_ID Query_Name Annotation_ID_Type Annotation_ID_Value
#> 1 HMAN000001 Asp HMDB|KEGG C00049|HMDB0000191
#> 2 HMAN000001 Asp HMDB|KEGG C00049|HMDB0000191
#> 3 HMAN000001 Asp HMDB|KEGG C00049|HMDB0000191
#> 4 HMAN000007 Gly HMDB|KEGG C00037|HMDB0000123
#> 5 HMAN000001 Asp HMDB|KEGG C00049|HMDB0000191
#> 6 HMAN000009 HISTIDINE HMDB|KEGG C00135|HMDB0000177
#> InChIKey PubChem_CID
#> 1 CKLJMWTZIZZHCS-REOHCLBHSA-N 5960
#> 2 CKLJMWTZIZZHCS-REOHCLBHSA-N 5960
#> 3 CKLJMWTZIZZHCS-REOHCLBHSA-N 5960
#> 4 DHMQDGOQFOQNFH-UHFFFAOYSA-N 750
#> 5 CKLJMWTZIZZHCS-REOHCLBHSA-N 5960
#> 6 HNDVDQJCIGZPNO-YFKPBYRVSA-N 6274
Unlike the assay modalities, annotation resources such as pathways, diseases,
microbial producer annotations, and drug similarity matches are long-form
tables. They are returned as data.frame objects because they are naturally
represented as annotations rather than sample-by-feature matrices.
names(metadata(one_study))
#> [1] "metaboliteIdentifierMapping" "microbialProducerAnnotations"
#> [3] "metaboliteDiseaseAssociations" "metabolitePathwayAnnotations"
#> [5] "drugBankSimilarityMatches" "drugCentralSimilarityMatches"
The metadata() slot of the study object stores the annotation resources that
were requested during loading. This is helpful when you want to keep the study
object intact and access all associated annotation layers from a single
container instead of managing separate tables manually.
harm_mat <- assay(harmonized_profile)
taxa_mat <- assay(taxa_profile)
dim(harm_mat)
#> [1] 14 122
dim(taxa_mat)
#> [1] 677 122
These extracted matrices can be used directly in downstream workflows for
ordination, association testing, machine learning, or other custom analyses.
The companion rowData() and colData() accessors preserve the feature-level
and sample-level context required for reproducible analysis.
sample_keep <- rownames(colData(one_study))[seq_len(min(5, nrow(colData(one_study))))]
study_subset <- one_study[, sample_keep]
study_subset
#> A MultiAssayExperiment object of 3 listed
#> experiments with user-defined names and respective classes.
#> Containing an ExperimentList class object of length 3:
#> [1] taxaAbundanceProfile: SummarizedExperiment with 677 rows and 5 columns
#> [2] OriginalMetaboliteProfile: SummarizedExperiment with 14 rows and 5 columns
#> [3] harmonizedMetaboliteProfile: SummarizedExperiment with 14 rows and 5 columns
#> Functionality:
#> experiments() - obtain the ExperimentList instance
#> colData() - the primary/phenotype DataFrame
#> sampleMap() - the sample coordination DataFrame
#> `$`, `[`, `[[` - extract colData columns, subset, or experiment
#> *Format() - convert into a long or wide DataFrame
#> assays() - convert ExperimentList to a SimpleList of matrices
#> exportClass() - save data to flat files
Subsetting a MultiAssayExperiment by columns subsets the shared sample space
and keeps the assay-level containers synchronized. This is one of the main
advantages of using standard Bioconductor containers for paired multi-omics
data, because users do not need to manually subset each assay and metadata
table separately.
selected_studies <- studies[seq_len(min(2, length(studies)))]
multi <- HuMMANet(
studies = selected_studies,
modalities = c("MetadataProfile", "OriginalMetaboliteProfile")
)
names(multi)
#> [1] "BarkerTejedaTC_2024_Targeted" "BarkerTejedaTC_2024_Untargeted"
class(multi[[1]])
#> [1] "MultiAssayExperiment"
#> attr(,"package")
#> [1] "MultiAssayExperiment"
names(experiments(multi[[1]]))
#> [1] "OriginalMetaboliteProfile"
The top-level HuMMANet() convenience function returns a named list of
study-level MultiAssayExperiment objects. This is useful when iterating across
multiple studies while preserving the same container structure for each one.
sessionInfo()
#> 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: /home/biocbuild/bbs-3.24-bioc/R/lib/libRblas.so
#> LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.12.0 LAPACK version 3.12.0
#>
#> locale:
#> [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
#> [3] LC_TIME=en_GB LC_COLLATE=C
#> [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: America/New_York
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats4 stats graphics grDevices utils datasets methods
#> [8] base
#>
#> other attached packages:
#> [1] MultiAssayExperiment_1.39.1 SummarizedExperiment_1.43.0
#> [3] Biobase_2.73.2 GenomicRanges_1.65.4
#> [5] Seqinfo_1.3.2 IRanges_2.47.5
#> [7] S4Vectors_0.51.10 BiocGenerics_0.59.12
#> [9] generics_0.1.4 MatrixGenerics_1.25.0
#> [11] matrixStats_1.5.0 HuMMANet_0.99.3
#> [13] BiocStyle_2.41.0
#>
#> loaded via a namespace (and not attached):
#> [1] KEGGREST_1.53.6 xfun_0.61 bslib_0.12.0
#> [4] httr2_1.3.0 lattice_0.23-1 vctrs_0.7.3
#> [7] tools_4.6.1 curl_8.0.0 tibble_3.3.1
#> [10] AnnotationDbi_1.75.2 RSQLite_3.53.3 blob_1.3.0
#> [13] pkgconfig_2.0.3 BiocBaseUtils_1.15.1 Matrix_1.7-6
#> [16] dbplyr_2.6.0 lifecycle_1.0.5 compiler_4.6.1
#> [19] Biostrings_2.81.9 htmltools_0.5.9 sass_0.4.10
#> [22] yaml_2.3.12 pillar_1.11.1 crayon_1.5.3
#> [25] jquerylib_0.1.4 DelayedArray_0.39.6 cachem_1.1.0
#> [28] abind_1.4-8 ExperimentHub_3.3.2 AnnotationHub_4.3.2
#> [31] tidyselect_1.2.1 digest_0.6.39 purrr_1.2.2
#> [34] dplyr_1.2.1 bookdown_0.48 BiocVersion_3.24.0
#> [37] grid_4.6.1 fastmap_1.2.0 SparseArray_1.13.2
#> [40] cli_3.6.6 magrittr_2.0.5 S4Arrays_1.13.0
#> [43] withr_3.0.3 filelock_1.0.3 rappdirs_0.3.4
#> [46] bit64_4.8.6 rmarkdown_2.32 XVector_0.53.0
#> [49] httr_1.4.9 bit_4.6.0 otel_0.2.0
#> [52] png_0.1-9 memoise_2.0.1 evaluate_1.0.5
#> [55] knitr_1.52 BiocFileCache_3.3.0 rlang_1.3.0
#> [58] glue_1.8.1 DBI_1.3.0 BiocManager_1.30.27
#> [61] jsonlite_2.0.0 R6_2.6.1