This tutorial is useful for analysis of output files from (Mothur), (QIIME or QIIME2) or any tool that gives a biom file as output. There is also a simple way to read comma seperated (*.csv) files.
Simple comma seperated files:
library(microbiome)
otu.file <-
system.file("extdata/qiita1629_otu_table.csv",
package='microbiome')
tax.file <- system.file("extdata/qiita1629_taxonomy_table.csv",
package='microbiome')
meta.file <- system.file("extdata/qiita1629_mapping_subset.csv",
package='microbiome')
pseq.csv <- read_phyloseq(
otu.file=otu.file,
taxonomy.file=tax.file,
metadata.file=meta.file, type = "simple")
Biom file:
# Read the biom file
biom.file <-
system.file("extdata/qiita1629.biom",
package = "microbiome")
# Read the mapping/metadata file
meta.file <-
system.file("extdata/qiita1629_mapping.csv",
package = "microbiome")
# Make phyloseq object
pseq.biom <- read_phyloseq(otu.file = biom.file,
metadata.file = meta.file,
taxonomy.file = NULL, type = "biom")
Mothur shared OTUs and Consensus Taxonomy:
otu.file <- system.file(
"extdata/Baxter_FITs_Microbiome_2016_fit.final.tx.1.subsample.shared",
package='microbiome')
tax.file <- system.file(
"extdata/Baxter_FITs_Microbiome_2016_fit.final.tx.1.cons.taxonomy",
package='microbiome')
meta.file <- system.file(
"extdata/Baxter_FITs_Microbiome_2016_mapping.csv",
package='microbiome')
pseq.mothur <- read_phyloseq(otu.file=otu.file,
taxonomy.file =tax.file,
metadata.file=meta.file, type = "mothur")
print(pseq.mothur)
Now, we proceed to core microbiota analysis.
Here the data from Caporaso, J. Gregory, et al. “Moving pictures of the human microbiome.” Genome biology 12.5 (2011): R50. will be used which is stored as example in jeevanuDB
# install
# install.packages("devtools")
# devtools::install_github("microsud/jeevanuDB")
# check the data
library(jeevanuDB)
ps <- moving_pictures
table(meta(ps)$sample_type, meta(ps)$host_subject_id)
##
## F4 M3
## saliva 135 373
## skin 268 723
## stool 131 336
# Filter the data to include only gut samples from M3 subject
ps.m3 <- subset_samples(ps, sample_type == "stool" & host_subject_id == "M3")
print(ps.m3)
## phyloseq-class experiment-level object
## otu_table() OTU Table: [ 3644 taxa and 336 samples ]
## sample_data() Sample Data: [ 336 samples by 89 sample variables ]
## tax_table() Taxonomy Table: [ 3644 taxa by 7 taxonomic ranks ]
# keep only taxa with positive sums
ps.m3 <- prune_taxa(taxa_sums(ps.m3) > 0, ps.m3)
print(ps.m3)
## phyloseq-class experiment-level object
## otu_table() OTU Table: [ 611 taxa and 336 samples ]
## sample_data() Sample Data: [ 336 samples by 89 sample variables ]
## tax_table() Taxonomy Table: [ 611 taxa by 7 taxonomic ranks ]
# Calculate compositional version of the data
# (relative abundances)
ps.m3.rel <- microbiome::transform(ps.m3, "compositional")
Output of deblur/dada2 will most likely have seqs as rownames instead of OTU ids or taxa names
taxa_names(ps.m3.rel)[1:3]
## [1] "TACGGAGGATTCAAGCGTTATCCGGATTTATTGGGTTTAAAGGGTGCGTAGGCGGTTTGATAAGTTAGAGGTGAAATACCGGTGCTTAACACCGGAACTGCCTCTAATACTGTTGAACTAGAGAGTAGTTGCGGTAGGCGGAATGTATGG"
## [2] "TACGTAGGGTGCGAGCGTTAATCGGAATTACTGGGCGTAAAGCGTGCGCAGGCGGTTTTGTAAGTCAGATGTGAAATCCCCGAGCTCAACTTGGGAACTGCGTTTGAAACTACAAGACTAGAATATGTCAGAGGGGGGTAGAATTCCACG"
## [3] "TACGTAGGGGGCAAGCGTTATCCGGATTTACTGGGTGTAAAGGGAGCGTAGACGGCATAACAAGTCTGATGTGAAAGGCTGGGGCTTAACCCCGGGACTGCATTGGAAACTGTTAAGCTTGAGTGCCGGAGGGGTAAGCGGAATTCCTAG"
We can change it to ASVIDs
library(Biostrings)
dna <- Biostrings::DNAStringSet(taxa_names(ps.m3.rel))
names(dna) <- taxa_names(ps.m3.rel)
ps.m3.rel <- merge_phyloseq(ps.m3.rel, dna)
taxa_names(ps.m3.rel) <- paste0("ASV", seq(ntaxa(ps.m3.rel)))
# now check again
taxa_names(ps.m3.rel)[1:3]
## [1] "ASV1" "ASV2" "ASV3"
If you only need the names of the core taxa, do as follows. This returns the taxa that exceed the given prevalence and detection thresholds.
core.taxa.standard <- core_members(ps.m3.rel, detection = 0.0001, prevalence = 50/100)
core.taxa.standard
A full phyloseq object of the core microbiota is obtained as follows:
pseq.core <- core(ps.m3.rel, detection = 0.0001, prevalence = .5)
Retrieving the associated taxa names from the phyloseq object:
core.taxa <- taxa(pseq.core)
class(core.taxa)
## [1] "character"
# get the taxonomy data
tax.mat <- tax_table(pseq.core)
tax.df <- as.data.frame(tax.mat)
# add the OTus to last column
tax.df$OTU <- rownames(tax.df)
# select taxonomy of only
# those OTUs that are core memebers based on the thresholds that were used.
core.taxa.class <- dplyr::filter(tax.df, rownames(tax.df) %in% core.taxa)
knitr::kable(head(core.taxa.class))
Domain | Phylum | Class | Order | Family | Genus | Species | OTU | |
---|---|---|---|---|---|---|---|---|
ASV20 | k__Bacteria | p__Firmicutes | c__Clostridia | o__Clostridiales | f__Ruminococcaceae | g__Faecalibacterium | s__prausnitzii | ASV20 |
ASV34 | k__Bacteria | p__Firmicutes | c__Clostridia | o__Clostridiales | f__Ruminococcaceae | g__Oscillospira | s__ | ASV34 |
ASV35 | k__Bacteria | p__Bacteroidetes | c__Bacteroidia | o__Bacteroidales | f__[Odoribacteraceae] | g__Odoribacter | s__ | ASV35 |
ASV55 | k__Bacteria | p__Firmicutes | c__Clostridia | o__Clostridiales | f__Lachnospiraceae | g__ | s__ | ASV55 |
ASV66 | k__Bacteria | p__Firmicutes | c__Clostridia | o__Clostridiales | f__Lachnospiraceae | NA | NA | ASV66 |
ASV88 | k__Bacteria | p__Bacteroidetes | c__Bacteroidia | o__Bacteroidales | f__Rikenellaceae | g__ | s__ | ASV88 |
Determine core microbiota across various abundance/prevalence thresholds with the blanket analysis (Salonen et al. CMI, 2012) based on various signal and prevalences.
# With compositional (relative) abundances
det <- c(0, 0.1, 0.5, 2, 5, 20)/100
prevalences <- seq(.05, 1, .05)
plot_core(ps.m3.rel, prevalences = prevalences,
detections = det, plot.type = "lineplot") +
xlab("Relative Abundance (%)") +
theme_bw()
This visualization method has been used for instance in Intestinal microbiome landscaping: Insight in community assemblage and implications for microbial modulation strategies. Shetty et al. FEMS Microbiology Reviews fuw045, 2017.
Note that you can order the taxa on the heatmap with the order.taxa argument.
# Core with compositionals:
prevalences <- seq(.05, 1, .05)
detections <- 10^seq(log10(1e-4), log10(.2), length = 10)
# Also define gray color palette
gray <- gray(seq(0,1,length=5))
p1 <- plot_core(ps.m3.rel,
plot.type = "heatmap",
colours = gray,
prevalences = prevalences,
detections = detections, min.prevalence = .5) +
xlab("Detection Threshold (Relative Abundance (%))")
p1 <- p1 + theme_bw() + ylab("ASVs")
p1
Using viridis color palette
library(viridis)
print(p1 + scale_fill_viridis())
## Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.
As it can be seen, we see only OTu IDs and this may not be useful to interpret the data. We need to repreoccess this figure to include taxonomic information. We can do this as follows:
library(RColorBrewer)
library(knitr)
# get the data used for plotting
df <- p1$data
# get the list of OTUs
list <- df$Taxa
# check the OTU ids
# print(list)
# get the taxonomy data
tax <- as.data.frame(tax_table(ps.m3.rel))
# add the ASVs to last column
tax$ASV <- rownames(tax)
# select taxonomy of only
# those OTUs that are used in the plot
tax2 <- dplyr::filter(tax, rownames(tax) %in% list)
# head(tax2)
# We will merege all the column into one except the Doamin as all is bacteria in this case
tax.unit <- tidyr::unite(tax2, Taxa_level,c("Domain", "Phylum", "Class", "Order", "Family", "Genus", "Species", "ASV"), sep = "_;", remove = TRUE)
tax.unit$Taxa_level <- gsub(pattern="[a-z]__",replacement="", tax.unit$Taxa_level)
# add this new information into the plot data df
df$Taxa <- tax.unit$Taxa_level
# you can see now we have the taxonomic information
knitr::kable(head(df))
Taxa | DetectionThreshold | Prevalence |
---|---|---|
Bacteria_;Firmicutes_;Clostridia_;Clostridiales_;Ruminococcaceae_;Faecalibacterium_;prausnitzii_;ASV20 | 1e-04 | 0.7797619 |
Bacteria_;Firmicutes_;Clostridia_;Clostridiales_;Ruminococcaceae_;Oscillospira_;_;ASV34 | 1e-04 | 0.7886905 |
Bacteria_;Bacteroidetes_;Bacteroidia_;Bacteroidales_;[Odoribacteraceae];Odoribacter;_;ASV35 | 1e-04 | 0.8869048 |
Bacteria_;Firmicutes_;Clostridia_;Clostridiales_;Lachnospiraceae_;;;ASV55 | 1e-04 | 0.7797619 |
Bacteria_;Firmicutes_;Clostridia_;Clostridiales_;Lachnospiraceae_;NA_;NA_;ASV66 | 1e-04 | 0.5744048 |
Bacteria_;Bacteroidetes_;Bacteroidia_;Bacteroidales_;Rikenellaceae_;;;ASV88 | 1e-04 | 0.5476190 |
# replace the data in the plot object
p1$data <- df
plot(p1 + theme(axis.text.y = element_text(face="italic")))
ps.m3.rel.gen <- aggregate_taxa(ps.m3.rel, "Genus")
library(RColorBrewer)
prevalences <- seq(.05, 1, .05)
detections <- 10^seq(log10(1e-4), log10(.2), length = 10)
p1 <- plot_core(ps.m3.rel.gen,
plot.type = "heatmap",
colours = rev(brewer.pal(5, "RdBu")),
prevalences = prevalences,
detections = detections, min.prevalence = .5) +
xlab("Detection Threshold (Relative Abundance (%))")
p1 <- p1 + theme_bw() + ylab("ASVs")
p1