mia 1.0.8
mia
implements tools for microbiome analysis based on the
SummarizedExperiment
(Morgan et al. 2020), SingleCellExperiment
(Amezquita et al. 2020) and
TreeSummarizedExperiment
(Huang 2021) infrastructure. Data wrangling and analysis
are the main scope of this package.
To install mia
, install BiocManager
first, if it is not installed.
Afterwards use the install
function from BiocManager
.
if (!requireNamespace("BiocManager", quietly = TRUE))
install.packages("BiocManager")
BiocManager::install("mia")
library("mia")
TreeSummarizedExperiment
objectA few example datasets are available via mia
. For this vignette the
GlobalPatterns
dataset is loaded first.
data(GlobalPatterns, package = "mia")
se <- GlobalPatterns
se
## class: TreeSummarizedExperiment
## dim: 19216 26
## metadata(0):
## assays(1): counts
## rownames(19216): 549322 522457 ... 200359 271582
## rowData names(7): Kingdom Phylum ... Genus Species
## colnames(26): CL3 CC1 ... Even2 Even3
## colData names(7): X.SampleID Primer ... SampleType Description
## reducedDimNames(0):
## mainExpName: NULL
## altExpNames(0):
## rowLinks: a LinkDataFrame (19216 rows)
## rowTree: 1 phylo tree(s) (19216 leaves)
## colLinks: NULL
## colTree: NULL
One of the main topics for analysing microbiome data is the application of taxonomic data to describe features measured. The interest lies in the connection between individual bacterial species and their relation to each other.
mia
does not rely on a specific object type to hold taxonomic data, but
uses specific columns in the rowData
of a SummarizedExperiment
object.
taxonomyRanks
can be used to construct a character
vector of available
taxonomic levels. This can be used, for example, for subsetting.
# print the available taxonomic ranks
colnames(rowData(se))
## [1] "Kingdom" "Phylum" "Class" "Order" "Family" "Genus" "Species"
taxonomyRanks(se)
## [1] "Kingdom" "Phylum" "Class" "Order" "Family" "Genus" "Species"
# subset to taxonomic data only
rowData(se)[,taxonomyRanks(se)]
## DataFrame with 19216 rows and 7 columns
## Kingdom Phylum Class Order Family
## <character> <character> <character> <character> <character>
## 549322 Archaea Crenarchaeota Thermoprotei NA NA
## 522457 Archaea Crenarchaeota Thermoprotei NA NA
## 951 Archaea Crenarchaeota Thermoprotei Sulfolobales Sulfolobaceae
## 244423 Archaea Crenarchaeota Sd-NA NA NA
## 586076 Archaea Crenarchaeota Sd-NA NA NA
## ... ... ... ... ... ...
## 278222 Bacteria SR1 NA NA NA
## 463590 Bacteria SR1 NA NA NA
## 535321 Bacteria SR1 NA NA NA
## 200359 Bacteria SR1 NA NA NA
## 271582 Bacteria SR1 NA NA NA
## Genus Species
## <character> <character>
## 549322 NA NA
## 522457 NA NA
## 951 Sulfolobus Sulfolobusacidocalda..
## 244423 NA NA
## 586076 NA NA
## ... ... ...
## 278222 NA NA
## 463590 NA NA
## 535321 NA NA
## 200359 NA NA
## 271582 NA NA
The columns are recognized case insensitive. Additional functions are available to check for validity of taxonomic information or generate labels based on the taxonomic information.
table(taxonomyRankEmpty(se, "Species"))
##
## FALSE TRUE
## 1413 17803
head(getTaxonomyLabels(se))
## [1] "Class:Thermoprotei" "Class:Thermoprotei_1"
## [3] "Species:Sulfolobusacidocaldarius" "Class:Sd-NA"
## [5] "Class:Sd-NA_1" "Class:Sd-NA_2"
For more details see the man page ?taxonomyRanks
.
Agglomeration of data based on these taxonomic descriptors can be performed
using functions implemented in mia
. In addition to the aggValue
functions
provide by TreeSummarizedExperiment
agglomerateByRank
is available.
agglomerateByRank
does not require tree data to be present.
agglomerateByRank
constructs a factor
to guide merging from the available
taxonomic information. For more information on merging have a look at the man
page via ?mergeRows
.
# agglomerate at the Family taxonomic rank
x1 <- agglomerateByRank(se, rank = "Family")
## How many taxa before/after agglomeration?
nrow(se)
## [1] 19216
nrow(x1)
## [1] 603
Tree data can also be shrunk alongside agglomeration, but this is turned of by default.
# with agglomeration of the tree
x2 <- agglomerateByRank(se, rank = "Family",
agglomerateTree = TRUE)
nrow(x2) # same number of rows, but
## [1] 603
rowTree(x1) # ... different
##
## Phylogenetic tree with 19216 tips and 19215 internal nodes.
##
## Tip labels:
## 549322, 522457, 951, 244423, 586076, 246140, ...
## Node labels:
## , 0.858.4, 1.000.154, 0.764.3, 0.995.2, 1.000.2, ...
##
## Rooted; includes branch lengths.
rowTree(x2) # ... tree
##
## Phylogenetic tree with 496 tips and 260 internal nodes.
##
## Tip labels:
## Family:Cenarchaeaceae, Family:SAGMA-X, Family:Nitrososphaeraceae, Family:Sulfolobaceae, Family:Halobacteriaceae, Family:MSBL1, ...
## Node labels:
## root:ALL, Kingdom:Archaea, Phylum:Crenarchaeota, Class:C2, Class:Sd-NA, Class:Thaumarchaeota, ...
##
## Rooted; includes branch lengths.
For agglomerateByRank
to work, taxonomic data must be present. Even though
only one rank is available for the enterotype
dataset, agglomeration can be
performed effectively de-duplicating entries for the genus level.
data(enterotype, package = "mia")
taxonomyRanks(enterotype)
## [1] "Genus"
agglomerateByRank(enterotype)
## class: TreeSummarizedExperiment
## dim: 552 280
## metadata(0):
## assays(1): counts
## rownames(552): -1 Prosthecochloris ... Syntrophococcus Mogibacterium
## rowData names(1): Genus
## colnames(280): AM.AD.1 AM.AD.2 ... TS98_V2 TS99.2_V2
## colData names(9): Enterotype Sample_ID ... Age ClinicalStatus
## reducedDimNames(0):
## mainExpName: NULL
## altExpNames(0):
## rowLinks: NULL
## rowTree: NULL
## colLinks: NULL
## colTree: NULL
To keep data tidy, the agglomerated data can be stored as an alternative experiment in the object of origin. With this synchronized sample subsetting becomes very easy.
altExp(se, "family") <- x2
Keep in mind, that if you set na.rm = TRUE
, rows with NA
or similar value
(defined via the empty.fields
argument) will be removed. Depending on these
settings different number of rows will be returned.
x1 <- agglomerateByRank(se, rank = "Species", na.rm = TRUE)
altExp(se,"species") <- agglomerateByRank(se, rank = "Species", na.rm = FALSE)
dim(x1)
## [1] 944 26
dim(altExp(se,"species"))
## [1] 2307 26
For convenience the function splitByRanks
is available, which agglomerates
data on all ranks
selected. By default all available ranks will be used.
The output is compatible to be stored as alternative experiments.
altExps(se) <- splitByRanks(se)
se
## class: TreeSummarizedExperiment
## dim: 19216 26
## metadata(0):
## assays(1): counts
## rownames(19216): 549322 522457 ... 200359 271582
## rowData names(7): Kingdom Phylum ... Genus Species
## colnames(26): CL3 CC1 ... Even2 Even3
## colData names(7): X.SampleID Primer ... SampleType Description
## reducedDimNames(0):
## mainExpName: NULL
## altExpNames(7): Kingdom Phylum ... Genus Species
## rowLinks: a LinkDataFrame (19216 rows)
## rowTree: 1 phylo tree(s) (19216 leaves)
## colLinks: NULL
## colTree: NULL
altExpNames(se)
## [1] "Kingdom" "Phylum" "Class" "Order" "Family" "Genus" "Species"
Constructing a taxonomic tree from taxonomic data stored in rowData
is quite
straightforward and uses mostly functions implemented in
TreeSummarizedExperiment
.
taxa <- rowData(altExp(se,"Species"))[,taxonomyRanks(se)]
taxa_res <- resolveLoop(as.data.frame(taxa))
taxa_tree <- toTree(data = taxa_res)
taxa_tree$tip.label <- getTaxonomyLabels(altExp(se,"Species"))
rowNodeLab <- getTaxonomyLabels(altExp(se,"Species"), make_unique = FALSE)
altExp(se,"Species") <- changeTree(altExp(se,"Species"),
rowTree = taxa_tree,
rowNodeLab = rowNodeLab)
Transformation of count data stored in assays
is also a main task when work
with microbiome data. transformCounts
can be used for this and offers a few
choices of available transformations. A modified object is returned and the
transformed counts are stored in a new assay
.
assayNames(enterotype)
## [1] "counts"
anterotype <- transformCounts(enterotype, method = "log10", pseudocount = 1)
assayNames(enterotype)
## [1] "counts"
For more details have a look at the man page ?transformCounts
.
In the field of microbiome ecology several indices to describe samples and community of samples are available. In this vignette we just want to give a very brief introduction.
Functions for calculating alpha and beta diversity indices are available.
Using estimateDiversity
multiple diversity indices are calculated by default
and results are stored automatically in colData
. Selected indices can be
calculated individually by setting index = "shannon"
for example.
se <- estimateDiversity(se)
colnames(colData(se))[8:ncol(colData(se))]
## [1] "coverage" "fisher" "gini_simpson"
## [4] "inverse_simpson" "log_modulo_skewness" "shannon"
## [7] "faith"
Beta diversity indices are used to describe inter-sample connections.
Technically they are calculated as dist
object and reduced dimensions can
be extracted using cmdscale
. This is wrapped up in the runMDS
function
of the scater
package, but can be easily used to calculated beta diversity
indices using the established functions from the vegan
package or any other
package using comparable inputs.
library(scater)
altExp(se,"Genus") <- runMDS(altExp(se,"Genus"),
FUN = vegan::vegdist,
method = "bray",
name = "BrayCurtis",
ncomponents = 5,
exprs_values = "counts",
keep_dist = TRUE)
JSD and UniFrac are implemented in mia
as well. calculateJSD
can be used
as a drop-in replacement in the example above (omit the method
argument as
well) to calculate the JSD. For calculating the UniFrac distance via
calculateUniFrac
either a TreeSummarizedExperiment
must be used or a tree
supplied via the tree
argument. For more details see ?calculateJSD
,
?calculateUniFrac
or ?calculateDPCoA
.
runMDS
performs the decomposition. Alternatively runNMDS
can also be used.
estimateDominance
and estimateEvenness
implement other sample-wise indices.
The function behave equivalently to estimateDiversity
. For more information
see the corresponding man pages.
To make migration and adoption as easy as possible several utility functions are available.
Functions to load data from biom
files, QIIME2
output, DADA2
objects
(Callahan et al. 2016) or phyloseq
objects are available.
data(esophagus, package = "phyloseq")
esophagus
## phyloseq-class experiment-level object
## otu_table() OTU Table: [ 58 taxa and 3 samples ]
## phy_tree() Phylogenetic Tree: [ 58 tips and 57 internal nodes ]
esophagus <- makeTreeSummarizedExperimentFromphyloseq(esophagus)
esophagus
## class: TreeSummarizedExperiment
## dim: 58 3
## metadata(0):
## assays(1): counts
## rownames(58): 59_8_22 59_5_13 ... 65_9_9 59_2_6
## rowData names(0):
## colnames(3): B C D
## colData names(0):
## reducedDimNames(0):
## mainExpName: NULL
## altExpNames(0):
## rowLinks: a LinkDataFrame (58 rows)
## rowTree: 1 phylo tree(s) (58 leaves)
## colLinks: NULL
## colTree: NULL
For more details have a look at the man page, for examples
?makeTreeSummarizedExperimentFromphyloseq
.
getAbundanceFeature
and getAbundanceSample
are wrappers on row-wise or
column-wise assay data subsetting.
abund <- getAbundanceSample(se, "CC1", abund_values = "counts")
all(abund == assay(se, "counts")[,"CC1"])
## [1] TRUE
abund <- getAbundanceFeature(se, "522457", abund_values = "counts")
all(abund == assay(se, "counts")["522457",])
## [1] TRUE
getTopTaxa
returns a vector of the most top
abundant feature IDs.
top_taxa <- getTopTaxa(se,
method = "mean",
top = 5,
abund_values = "counts")
top_taxa
## [1] "549656" "331820" "279599" "360229" "317182"
To generate tidy data as used and required in most of the tidyverse,
meltAssay
can be used. A data.frame
in the long format will be returned.
molten_data <- meltAssay(se,
add_row_data = TRUE,
add_col_data = TRUE,
abund_values = "counts")
molten_data
## # A tibble: 499,616 × 24
## FeatureID SampleID counts Kingdom Phylum Class Order Family Genus Species
## <fct> <fct> <dbl> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
## 1 549322 CL3 0 Archaea Crenarc… Thermo… <NA> <NA> <NA> <NA>
## 2 549322 CC1 0 Archaea Crenarc… Thermo… <NA> <NA> <NA> <NA>
## 3 549322 SV1 0 Archaea Crenarc… Thermo… <NA> <NA> <NA> <NA>
## 4 549322 M31Fcsw 0 Archaea Crenarc… Thermo… <NA> <NA> <NA> <NA>
## 5 549322 M11Fcsw 0 Archaea Crenarc… Thermo… <NA> <NA> <NA> <NA>
## 6 549322 M31Plmr 0 Archaea Crenarc… Thermo… <NA> <NA> <NA> <NA>
## 7 549322 M11Plmr 0 Archaea Crenarc… Thermo… <NA> <NA> <NA> <NA>
## 8 549322 F21Plmr 0 Archaea Crenarc… Thermo… <NA> <NA> <NA> <NA>
## 9 549322 M31Tong 0 Archaea Crenarc… Thermo… <NA> <NA> <NA> <NA>
## 10 549322 M11Tong 0 Archaea Crenarc… Thermo… <NA> <NA> <NA> <NA>
## # … with 499,606 more rows, and 14 more variables: X.SampleID <fct>,
## # Primer <fct>, Final_Barcode <fct>, Barcode_truncated_plus_T <fct>,
## # Barcode_full_length <fct>, SampleType <fct>, Description <fct>,
## # coverage <int>, fisher <dbl>, gini_simpson <dbl>, inverse_simpson <dbl>,
## # log_modulo_skewness <dbl>, shannon <dbl>, faith <dbl>
sessionInfo()
## R version 4.1.0 (2021-05-18)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 20.04.2 LTS
##
## Matrix products: default
## BLAS: /home/biocbuild/bbs-3.13-bioc/R/lib/libRblas.so
## LAPACK: /home/biocbuild/bbs-3.13-bioc/R/lib/libRlapack.so
##
## 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
##
## attached base packages:
## [1] parallel stats4 stats graphics grDevices utils datasets
## [8] methods base
##
## other attached packages:
## [1] phyloseq_1.36.0 scater_1.20.1
## [3] ggplot2_3.3.5 scuttle_1.2.0
## [5] mia_1.0.8 TreeSummarizedExperiment_2.0.2
## [7] Biostrings_2.60.1 XVector_0.32.0
## [9] SingleCellExperiment_1.14.1 SummarizedExperiment_1.22.0
## [11] Biobase_2.52.0 GenomicRanges_1.44.0
## [13] GenomeInfoDb_1.28.1 IRanges_2.26.0
## [15] S4Vectors_0.30.0 BiocGenerics_0.38.0
## [17] MatrixGenerics_1.4.0 matrixStats_0.60.0
## [19] BiocStyle_2.20.2
##
## loaded via a namespace (and not attached):
## [1] ggbeeswarm_0.6.0 colorspace_2.0-2
## [3] ellipsis_0.3.2 BiocNeighbors_1.10.0
## [5] bit64_4.0.5 fansi_0.5.0
## [7] decontam_1.12.0 codetools_0.2-18
## [9] splines_4.1.0 sparseMatrixStats_1.4.0
## [11] cachem_1.0.5 knitr_1.33
## [13] ade4_1.7-17 jsonlite_1.7.2
## [15] cluster_2.1.2 BiocManager_1.30.16
## [17] compiler_4.1.0 assertthat_0.2.1
## [19] Matrix_1.3-4 fastmap_1.1.0
## [21] lazyeval_0.2.2 cli_3.0.1
## [23] BiocSingular_1.8.1 htmltools_0.5.1.1
## [25] tools_4.1.0 igraph_1.2.6
## [27] rsvd_1.0.5 gtable_0.3.0
## [29] glue_1.4.2 GenomeInfoDbData_1.2.6
## [31] reshape2_1.4.4 dplyr_1.0.7
## [33] Rcpp_1.0.7 jquerylib_0.1.4
## [35] rhdf5filters_1.4.0 vctrs_0.3.8
## [37] multtest_2.48.0 ape_5.5
## [39] nlme_3.1-152 DECIPHER_2.20.0
## [41] iterators_1.0.13 DelayedMatrixStats_1.14.0
## [43] xfun_0.24 stringr_1.4.0
## [45] beachmat_2.8.0 lifecycle_1.0.0
## [47] irlba_2.3.3 zlibbioc_1.38.0
## [49] MASS_7.3-54 scales_1.1.1
## [51] biomformat_1.20.0 rhdf5_2.36.0
## [53] yaml_2.2.1 memoise_2.0.0
## [55] gridExtra_2.3 sass_0.4.0
## [57] stringi_1.7.3 RSQLite_2.2.7
## [59] foreach_1.5.1 ScaledMatrix_1.0.0
## [61] tidytree_0.3.4 permute_0.9-5
## [63] BiocParallel_1.26.1 rlang_0.4.11
## [65] pkgconfig_2.0.3 bitops_1.0-7
## [67] evaluate_0.14 lattice_0.20-44
## [69] Rhdf5lib_1.14.2 purrr_0.3.4
## [71] treeio_1.16.1 bit_4.0.4
## [73] tidyselect_1.1.1 plyr_1.8.6
## [75] magrittr_2.0.1 bookdown_0.22
## [77] R6_2.5.0 generics_0.1.0
## [79] DelayedArray_0.18.0 DBI_1.1.1
## [81] pillar_1.6.2 withr_2.4.2
## [83] mgcv_1.8-36 survival_3.2-11
## [85] RCurl_1.98-1.3 tibble_3.1.3
## [87] crayon_1.4.1 utf8_1.2.2
## [89] rmarkdown_2.9 viridis_0.6.1
## [91] grid_4.1.0 data.table_1.14.0
## [93] blob_1.2.2 vegan_2.5-7
## [95] digest_0.6.27 tidyr_1.1.3
## [97] munsell_0.5.0 DirichletMultinomial_1.34.0
## [99] beeswarm_0.4.0 viridisLite_0.4.0
## [101] vipor_0.4.5 bslib_0.2.5.1
Amezquita, Robert, Aaron Lun, Etienne Becht, Vince Carey, Lindsay Carpp, Ludwig Geistlinger, Federico Marini, et al. 2020. “Orchestrating Single-Cell Analysis with Bioconductor.” Nature Methods 17: 137–45. https://www.nature.com/articles/s41592-019-0654-x.
Callahan, Benjamin J, Paul J McMurdie, Michael J Rosen, Andrew W Han, Amy Jo A Johnson, and Susan P Holmes. 2016. “DADA2: High-Resolution Sample Inference from Illumina Amplicon Data.” Nature Methods 13: 581–83. https://doi.org/10.1038/nmeth.3869.
Huang, Ruizhu. 2021. TreeSummarizedExperiment: TreeSummarizedExperiment: A S4 Class for Data with Tree Structures.
Morgan, Martin, Valerie Obenchain, Jim Hester, and Hervé Pagès. 2020. SummarizedExperiment: SummarizedExperiment Container. https://bioconductor.org/packages/SummarizedExperiment.