# Biome-Shiny 1.0 - Server
library(shiny)
library(shinydashboard)
library(shinyBS)
library(microbiome)
if("speedyseq" %in% rownames(installed.packages()) == TRUE){
library(speedyseq)
} else {
paste0("Biome-Shiny can use the 'speedyseq' library to speed up some phyloseq functions. If you'd like, you can install it from GitHub: https://github.com/mikemc/speedyseq")
}
library(rmarkdown)
library(DT)
library(ggplot2)
library(plotly)
library(heatmaply)
library(knitr)
library(plyr)
library(dplyr)
library(tibble)
library(ggpubr)
library(vegan)
library(hrbrthemes)
#Function to dynamically set plot width (and height) for plots
plot_width <- function(data, mult = 12, min.width = 1060, otu.or.tax = "otu"){
if(mult <= 0){
print("Error: Variable 'mult' requires a value higher than 0")
return(NULL)
}
if(min.width <= 0){
print("Error: Variable 'min.width' requires a value higher than 0")
return(NULL)
}
if(otu.or.tax == "otu"){
width <- ncol(otu_table(data))*mult
if(width <= min.width){ #Value of width needs to be higher than minimum width, default 1060px
width <- min.width
return(width)
} else {
return(width)
}
}
if(otu.or.tax == "tax"){
width <- nrow(tax_table(data))*mult
if(width <= min.width){
width <- min.width
return(width)
} else {
return(width)
}
}
}
# Modified the summarize package
summarize_phyloseq_mod <- function(x){
{
ave <- minR <- maxR <- tR <- aR <- mR <- sR <- sR1 <- sR2 <- svar <- NULL
sam_var <- zno <- comp <- NULL
ave <- sum(sample_sums(x))/nsamples(x)
comp <- length(which(colSums(abundances(x)) > 1))
if (comp == 0) {
a <- paste0("Compositional? YES")
}
else {
a <- paste0("Compositional? NO")
}
minR <- paste0("Min. number of reads = ", min(sample_sums(x)))
maxR <- paste0("Max. number of reads = ", max(sample_sums(x)))
tR <- paste0("Total number of reads = ", sum(sample_sums(x)))
aR <- paste0("Average number of reads = ", ave)
mR <- paste0("Median number of reads = ", median(sample_sums(x)))
if (any(taxa_sums(x) == 1) == TRUE) {
sR <- paste0("Singletons? ", "YES")
}
else {
sR <- paste0("Singletons? ", "NO")
}
zno <- paste0("Sparsity = ", length(which(abundances(x) ==
0))/length(abundances(x)))
sR1 <- paste0("Number of singletons = ", length(taxa_sums(x)[taxa_sums(x) ==
1]))
sR2 <- paste0("Percent of OTUs that are singletons = ",
mean(taxa_sums(x) == 1) * 100)
svar <- paste0("Number of sample variables: ", ncol(meta(x)))
list(a,minR, maxR, tR, aR, mR, zno, sR, sR1, sR2, svar)
}
}
#Function to fix the formatting on the sample variables
list_sample_variables <- function(x){
a<-colnames(sample_data(x))
as.list(a)
}
# Load sample datasets #
data("dietswap")
data("atlas1006")
# Server
server <- function(input, output, session) {
has_data_initialized <- reactiveValues()
has_data_initialized$data_initialized <- FALSE
has_data_initialized$filters_initialized <-FALSE
datasetChoice <- function(dataset){
}
datasetA <- reactive({
bur <- input$phyloseqOTUTable$datapath
return(bur)
})
datasetTest <-renderText({datasetA()})
datasetChoice <- reactive({
# Taxa Parse Function switch
taxparse <- switch(
input$taxParseFunction,
"Default" = parse_taxonomy_default,
"QIIME" = parse_taxonomy_qiime,
"Greengenes" = parse_taxonomy_greengenes
)
# Sample dataset selector
if (input$datasetChoice == "Sample dataset") {
withProgress(message = 'Loading sample dataset...', style = "notification", value = 0.5, {
has_data_initialized$data_initialized = FALSE
sampleDataset <- switch(
input$datasetSample,
"dietswap" = dietswap,
"atlas1006" = atlas1006
)
has_data_initialized$data_initialized = TRUE
return(sampleDataset)
})
return(sampleDataset)
}
# Tabular file upload
# I have no idea why this doesn't work.
if(input$datasetChoice == "Tabular files"){
otu <- input$phyloseqOTUTable$datapath
tax <- input$phyloseqTaxTable$datapath
otu.tab <- read.table(otu)
tax.tab <- read.table(tax)
# biomfile <- phyloseq( #aggs
# otu_table(otu.tab, taxa_are_rows = input$samplesAreColumnsPhyloseq), #aggs
# tax_table(as.matrix(tax.tab)) #aggs
# ) #Might get an error with taxa are rows #aggs
if(is.null(input$phyloseqMetadataTable)){ #aggs: is.null() takes 1 argument
if(input$samplesAreColumnsPhyloseq == TRUE){
samples.out <- colnames(otu_table(biomfile))
} else {
samples.out <- rownames(otu_table(biomfile))
}
subject <- sapply(strsplit(samples.out, "D"), `[`, 1)
samdf <- data.frame(Subject=subject)
rownames(samdf) <- samples.out
b <- sample_data(samdf)
pfile <- merge_phyloseq(biomfile, b)
has_data_initialized$data_initialized = TRUE
return(biomfile)
} else {
if(input$headerCheck == TRUE){
meta.tab.path <- as.data.frame(read.table(input$phyloseqMetadataTable$datapath, header = TRUE), skipNul = TRUE) #aggs
} else {
meta.tab.path <- as.data.frame(read.table(input$phyloseqMetadataTable$datapath), skipNul = TRUE) #aggs
}
if(input$rowCheck == TRUE){
rownames(meta.tab.path) <- meta.tab.path[,1]
}
#meta.tab <- sample_data(meta.tab.path) #aggs
#biomfile <- merge(biomfile, meta.tab) #aggs
}
######################################################################################
# aggs
biomfile <- phyloseq(
otu_table(otu.tab, taxa_are_rows = input$samplesAreColumnsPhyloseq),
tax_table(as.matrix(tax.tab)),
sample_data(meta.tab.path)
)
#######################################################################################
has_data_initialized$data_initialized = TRUE
return(biomfile)
}
# Biom file upload
if(input$datasetChoice == "Biom file") {
req(input$dataset)
withProgress(message = 'Loading biom file...', style = "notification", value = 0.5, {
tryCatch({
has_data_initialized$data_initialized = FALSE
datapath <- input$dataset$datapath
a <- import_biom(datapath, parseFunction = taxparse)
}, error = function(e){
simpleError("Error importing the .biom file.")
})})
if(input$datasetType == ".biom file with sample variables") {
has_data_initialized$data_initialized = TRUE
return(a)
}
if(input$datasetType == ".biom file with .csv metadata file"){
withProgress(message = 'Loading metadata...', style = "notification", value = 0.5, {
datapathMetadata <- input$datasetMetadata$datapath
b <- as.data.frame(read.csv(datapathMetadata, skipNul = TRUE))
setProgress(value = 0.7, message = "Merging metadata and biom file...")
rownames(b) <- b[, 1]
c <- sample_data(b)
setProgress(value = 0.9, message = "Merging metadata and biom file...")
biomfile <- merge_phyloseq(a,c)
setProgress(value = 1, message = "Loading complete!")
})
has_data_initialized$data_initialized = TRUE
return(biomfile)
}
if(input$datasetType == ".biom file without .csv metadata file"){
withProgress(message = 'Generating metadata...', style = "notification", value = 0.5, {
tryCatch({
if(input$samplesAreColumns == TRUE){
samples.out <- colnames(otu_table(a))
}
if(input$samplesAreColumns == FALSE){
samples.out <- rownames(otu_table(a))
otu_table(a) <- phyloseq::t(otu_table(a))
}
subject <- sapply(strsplit(samples.out, "D"), `[`, 1)
samdf <- data.frame(Subject=subject)
rownames(samdf) <- samples.out
b <- sample_data(samdf)
}, error = function(e){
simpleError("Error generating sample variables")
})})
tryCatch({
biomfile <- merge_phyloseq(a, b)
has_data_initialized$data_initialized = TRUE
return(biomfile)
}, error = function(e){
simpleError("Error merging sample variables with .biom file")
})
}
}
})
# uploadDataTableParams <- reactive(
# req(datasetInput),
# table <- as.data.frame(input$datasetInput$datapath),
# return(table)
# )
#
# output$uploadDataTable <- renderTable(
# uploadDataTableParams()
# )
#
# New DatasetInput function works as an intermediary that checks if the dataset has been altered
datasetInput <- reactive({
if(input$coreFilterDataset == TRUE ){ # Filters the dataset
dataset <- filterData()
}
if(input$coreFilterDataset == FALSE ) { # Standard dataset input without filtering applied
dataset <- datasetChoice()
}
return(dataset)
})
## Dynamic Menu ##
output$dynamicMenu <- renderMenu(
if( has_data_initialized$data_initialized == FALSE){
sidebarMenu(
br(),
strong(paste0("Waiting for dataset..."))
)
} else {
sidebarMenu(
menuItem("Filtering and Transformations (2/3)", tabName="dataprocessing"),
menuItem("Phyloseq Summary (3/3)", tabName="phyloseqsummary"),
br(),
paste("Microbiome analysis"),
menuItem("Core microbiota", tabName = "coremicrobiota"),
menuItem("Community composition", tabName = "communitycomposition"),
menuItem("Alpha diversity", tabName = "alphadiversity"),
menuItem("Beta diversity", tabName = "betadiversity"),
br(),
paste0("Statistical analysis"),
menuItem("PERMANOVA", tabName = "permanova"),
br(),
paste("Outputs and Results"),
menuItem("Results", tabName = "results"),
br(),
paste("Settings"),
uiOutput("decimalSlider")
)
}
)
## Dataset Filtering ##
## Populate SelectInput with taxonomic ranks ##
observeEvent(input$datasetUpdate, {
tryCatch({
updateSelectInput(session, "subsetTaxaByRank",
choices = colnames(tax_table(datasetInput())))
}, error = function(e) {
simpleError(e)
})
}, ignoreNULL = FALSE)
## Update Checkbox Group based on the chosen taxonomic rank ##
observeEvent(input$subsetTaxaByRank, {
tryCatch({
withProgress(message = 'Filtering and Transformations', detail = "Updating Taxonomic Ranks", style = "notification", min = 0, max = 1, value = 0.1, {
updateCheckboxGroupInput(session, "subsetTaxaByRankTaxList",
choices = levels(data.frame(tax_table(datasetChoice()))[[input$subsetTaxaByRank]]),
selected = levels(data.frame(tax_table(datasetChoice()))[[input$subsetTaxaByRank]]),
inline = TRUE
)})
}, error = function(e) {
simpleError(e)
})
})
## Update subsetSamples Checkbox Group ##
observeEvent(input$datasetUpdate, {
tryCatch({
withProgress(message = 'Filtering and Transformations', detail = "Updating Samples", style = "notification", min = 0, max = 1, value = 0.1, {
updateCheckboxGroupInput(session, "subsetSamples",
choices = colnames(otu_table(datasetChoice())),
selected = colnames(otu_table(datasetChoice())),
inline = TRUE
)})
}, error = function(e) {
simpleError(e)
})
})
#Check all samples
observeEvent(input$subsetSamplesTickAll, {
tryCatch({
updateCheckboxGroupInput(session, "subsetSamples",
choices = colnames(otu_table(datasetChoice())),
selected = colnames(otu_table(datasetChoice())),
inline = TRUE
)
}, error = function(e) {
simpleError(e)
})
})
#Check all taxa
observeEvent(input$subsetTaxaByRankTickAll, {
tryCatch({
updateCheckboxGroupInput(
session, "subsetTaxaByRankTaxList",
choices = levels(data.frame(tax_table(datasetChoice()))[[input$subsetTaxaByRank]]),
selected = levels(data.frame(tax_table(datasetChoice()))[[input$subsetTaxaByRank]]),
inline = TRUE
)
}, error = function(e) {
simpleError(e)
}
)
})
#Uncheck all taxa
observeEvent(input$subsetTaxaByRankUntickAll, {
tryCatch({
updateCheckboxGroupInput(
session, "subsetTaxaByRankTaxList",
choices = levels(data.frame(tax_table(datasetChoice()))[[input$subsetTaxaByRank]]),
selected = NULL,
inline = TRUE
)
}, error = function(e) {
simpleError(e)
}
)
})
#Uncheck all samples
observeEvent(input$subsetSamplesUntickAll, {
tryCatch({
updateCheckboxGroupInput(
session, "subsetSamples",
choices = colnames(otu_table(datasetChoice())),
selected = NULL,
inline = TRUE
)
}, error = function(e) {
simpleError(e)
}
)
})
## Function to apply filters to the dataset ##
filterData <- reactive({
withProgress(message = 'Applying filters to the dataset', detail = "Please wait...", style = "notification", min = 0, max = 1, value = 0.1, {
physeq <- datasetChoice()
# Rarefy data
if(input$rarefactionCheck == TRUE) {
setProgress(message = "Applying rarefaction...", value = 0.2)
physeqRare <- rarefy_even_depth(physeq, sample.size = min(sample_sums(physeq)),
replace = input$rarefactionReplace,
rngseed = input$rarefactionSeed )
physeq <- physeqRare
}
# Subset data by taxonomic rank - commented out for now since I'm having issues implementing it
if (input$subsetTaxaByRankCheck == TRUE){
setProgress(message = "Filtering out taxa...", value = 0.3)
oldMA <- tax_table(physeq)
oldDF <- data.frame(oldMA)
newMA <- prune_taxa(oldDF[[input$subsetTaxaByRank]] %in% input$subsetTaxaByRankTaxList, oldMA)
tax_table(physeq) <- tax_table(newMA)
}
#Filter out non-top taxa
if (input$pruneTaxaCheck == TRUE){
setProgress(message = "Removing non-top taxa...", value = 0.6)
filterTaxa <- names(sort(taxa_sums(physeq), decreasing = TRUE)[1:input$pruneTaxa])
physeq <- prune_taxa(filterTaxa, physeq)
}
#Filter out samples
if (input$subsetSamplesCheck == TRUE){
setProgress(message = "Removing unwanted samples...", value = 0.8)
oldDF <- as(sample_data(physeq), "data.frame")
newDF <- subset(oldDF, colnames(otu_table(physeq)) %in% input$subsetSamples)
sample_data(physeq) <- sample_data(newDF)
}})
setProgress(message = "Finishing...", value = 0.9)
return(physeq)
})
output$corePhyloSummary <- renderPrint({ # Summary of corePhylo file
summarize_phyloseq(filterData)
})
output$coreTaxa <- renderPrint({ # Reports the taxa in corePhylo
taxa(filterData)
})
output$prevalenceAbsoluteOutput <- renderDT({
datatable(prevalenceAbsolute())
})
output$downloadPrevalenceAbsolute <- downloadHandler(
filename = function() {
paste("PrevalenceAbsolute", ".csv", sep = "")
},
content = function(file) {
write.csv(prevalenceAbsolute(), file, row.names = TRUE)
}
)
output$prevalenceRelativeOutput <- renderDT({
datatable(prevalenceRelative())
})
output$downloadPrevalenceRelative <- downloadHandler(
filename = function() {
paste("PrevalenceRelative", ".csv", sep = "")
},
content = function(file) {
write.csv(prevalenceRelative(), file, row.names = TRUE)
}
)
## Core Microbiota ##
coreHeatmapParams <- reactive({
if ( input$samplesAreColumns == TRUE ) {
if ( nrow(otu_table(datasetInput())) > 1000 ){
simpleError("A maximum of 1000 OTUs are permitted. Please filter the dataset and try again.")
} else {
withProgress(message = 'Generating plot...', detail = "This may take a bit.", style = "notification", min = 0, max = 1, value = 0.1, {
# for(i in 1:30){
# incProgress(1/30)
# Sys.sleep(1)
# }
b <- heatmaply(otu_table(datasetInput()),
key.title = "Abundance", plot_method = "ggplot", height = "100%", width = "100%",
heatmap_layers = theme(
panel.background = element_rect(fill = "transparent"),
plot.background = element_rect(fill = "transparent"),
legend.background = element_rect(fill = "transparent")
)
)}) }
} else {
if (ncol(otu_table(datasetInput())) > 1000){
simpleError("A maximum of 1000 OTUs are permitted. Please filter the dataset and try again.")
} else {
withProgress(message = 'Generating plot...', detail = "This may take a bit.", style = "notification", min = 0, max = 1, value = 0.1, {
b <- heatmaply(otu_table(datasetInput()),
key.title = "Abundance", plot_method = "ggplot",
heatmap_layers = theme(
panel.background = element_rect(fill = "transparent"),
plot.background = element_rect(fill = "transparent"),
legend.background = element_rect(fill = "transparent")
)
)
})
}
incProgress(amount = 0.1, message = "Plot is being generated.", detail = "This may take a bit.")
return(b)
}
})
output$coreHeatmap <- renderPlotly({
ggplotly(coreHeatmapParams()) %>% config(editable = T, autosizable = T)
})
## Community Composition ##
# Updating SelectInputs when database changes #
observeEvent(input$datasetUpdate, {
tryCatch({
updateSelectInput(session, "z1",
choices = colnames(meta(datasetInput())))
updateSelectInput(session, "z2",
choices = colnames(meta(datasetInput())))
updateSelectInput(session, "z3",
choices = colnames(meta(datasetInput())))
updateSelectInput(session, "v4",
choices = colnames(tax_table(datasetInput())))
updateSelectInput(session, "z1Average",
choices = colnames(meta(datasetInput())))
updateSelectInput(session, "v4Plot",
choices = colnames(tax_table(datasetInput())))
}, error = function(e) {
simpleError(e)
})
}, ignoreNULL = FALSE)
#Update metadata value selectInputs for CC Analysis
observeEvent(input$z1, {
updateSelectInput(session, "v1",
choices = (sample_data(datasetInput())[[input$z1]]))
})
observeEvent(input$z2, {
updateSelectInput(session, "v2",
choices = (sample_data(datasetInput())[[input$z2]]))
})
observeEvent(input$z3, {
updateSelectInput(session, "v3",
choices = (sample_data(datasetInput())[[input$z3]]))
})
# Abundance of taxa in sample variable by taxa
communityPlotParams <- reactive ({
withProgress(message = 'Generating plot...', detail = "This may take a bit.", style = "notification", min = 0, max = 1, value = 0.1, {
taxglom <- tax_glom(datasetInput(), taxrank=input$v4)
compositionplot <- plot_bar(taxglom, x=input$z1, y="Abundance", fill=input$v4, title=paste0("Abundance by ", input$v4, " in ", input$z1)) + geom_bar(stat="identity") + theme_pubr(base_size = 10, margin = TRUE, legend = "right", x.text.angle = 90) + rremove("xlab") + rremove("ylab")
if(input$communityPlotFacetWrap == TRUE){
compositionplot <- compositionplot + facet_grid(paste('~',input$z2), scales = "free", space = "free")
}
if(input$transparentCommunityPlot == TRUE){
compositionplot <- compositionplot +
theme(panel.background = element_rect(fill = "transparent", colour = NA), plot.background = element_rect(fill = "transparent", colour = NA), legend.background = element_rect(fill = "transparent", colour = NA), legend.box.background = element_rect(fill = "transparent", colour = NA))
}
p <- ggplotly(compositionplot, height = 500, width = plot_width(datasetInput())) %>% layout(xaxis = list(title = input$z1, automargin = TRUE), yaxis = list(title = "Abundance", automargin = TRUE))
})
return(p)
})
output$communityPlot <- renderPlotly({
communityPlotParams() %>% config(editable = T, autosizable = T)
})
communityPlotGenusParams <- reactive({
withProgress(message = 'Generating plot...', detail = "This may take a bit.", style = "notification", min = 0, max = 1, value = 0.1, {
taxglom <- tax_glom(microbiome::transform(datasetInput(), "compositional"), taxrank=input$v4)
compositionplot <- plot_bar(taxglom, x=input$z1, fill=input$v4, title=paste0("Relative abundance by ", input$v4, " in ", input$z1)) + geom_bar(stat="identity") +
guides(fill = guide_legend(ncol = 1)) +
scale_y_percent() +
theme_pubr(base_size = 10, margin = TRUE, legend = "right", x.text.angle = 90) + rremove("xlab") + rremove("ylab")
if(input$communityPlotFacetWrap == TRUE){
compositionplot <- compositionplot + facet_grid(paste('~',input$z2),scales = "free", space = "free")
}
if(input$transparentCommunityPlot == TRUE){
compositionplot <- compositionplot +
theme(panel.background = element_rect(fill = "transparent", colour = NA), plot.background = element_rect(fill = "transparent", colour = NA), legend.background = element_rect(fill = "transparent", colour = NA), legend.box.background = element_rect(fill = "transparent", colour = NA))
}
p <- ggplotly(compositionplot, height = 500, width = plot_width(datasetInput())) %>% layout(xaxis = list(title = input$z1, automargin = TRUE), yaxis = list(title = "Abundance", automargin = TRUE))
})
return(p)
})
output$communityPlotGenus <- renderPlotly({
communityPlotGenusParams()
})
# Taxa prevalence plot
communityPrevalenceParams <- reactive({
prevplot <- plot_taxa_prevalence(compositionalInput(), input$v4) + theme_pubr(base_size = 10, margin = TRUE, legend = "right", x.text.angle = 90) + #If OTUs > 25 it fails
rremove("xlab") + rremove("ylab")
if(input$transparentCommunityPlot == TRUE){
prevplot <- prevplot +
theme(panel.background = element_rect(fill = "transparent", colour = NA), plot.background = element_rect(fill = "transparent", colour = NA), legend.background = element_rect(fill = "transparent", colour = NA), legend.box.background = element_rect(fill = "transparent", colour = NA))
}
p <- ggplotly(prevplot, height = 500, width = 1000) %>% layout(xaxis = list(title = "Average count abundance (log scale)", automargin = TRUE), yaxis = list(title = "Taxa prevalence", automargin = TRUE))
return(p)
})
output$communityPrevalence <- renderPlotly({
communityPrevalenceParams()
})
# Phyloseq Summary #
summaryParams <- reactive({
req(datasetInput())
withProgress(message = 'Generating summary...', style = "notification", min = 0, max = 1, value = 0.1, {
as.character(summarize_phyloseq_mod(datasetInput()))})
})
output$summary <- renderPrint({
summaryParams()
})
sampleVarsParams <- reactive({
list_sample_variables(datasetInput())
})
output$sampleVars <- renderPrint({
withProgress(message = 'Printing sample variables...', style = "notification", value = 0.1, {
as.character(sampleVarsParams())
})
})
## Alpha Diversity ##
# Slider for adjusting number of decimal cases
output$decimalSlider <- renderUI({
sliderInput(
"decimalCases",
"Tables: Number of decimal cases:",
min = 1,
max = 15,
step = 1,
value = 5,
width = "80%"
)
})
output$standardizationPick <- renderUI({
checkboxInput("dataTransformation", strong("Dataset: Standardize data with Hellinger method"), value = TRUE, width = "80%")
})
decimalCalc <- eventReactive(input$decimalCases, ignoreNULL = TRUE, {
input$decimalCases
})
#Abundance and Evenness tables#
evennessParams <- reactive({
withProgress(message = 'Generating table...', style = "notification", min = 0, max = 1, value = 0.1, {
a <- evenness(datasetInput()) %>% round(digits = decimalCalc())
setProgress(message = "Rounding values...", value = 0.4)
colnames(a) <- c("Camargo","Pielou","Simpson","Smith and Wilson's Evar","Bulla")
setProgress(message = "Rendering table...", value = 0.7)
})
datatable(a, options = list(scrollX = TRUE))
})
output$evennessTable <- renderDataTable({
evennessParams()
})
output$downloadEvenness <- downloadHandler(
filename = function() {
paste("evenness", ".csv", sep = "")
},
content = function(file) {
a <- evenness(datasetInput()) %>% round(digits = input$decimalCases)
write.csv(a, file, row.names = TRUE)
}
)
absoluteAbundanceParams <- reactive({
withProgress(message = 'Generating table...', style = "notification", min = 0, max = 1, value = 0.1, {
a <- abundances(datasetInput())
})
datatable(a, options = list(scrollX = TRUE))
})
output$absoluteAbundanceTable <- renderDataTable( server = FALSE, {
absoluteAbundanceParams()
})
output$downloadAbundance <- downloadHandler(
filename = function() {
paste("evenness", ".csv", sep = "")
},
content = function(file) {
write.csv(abundances(datasetInput()), file, row.names = TRUE)
}
)
relativeAbundanceParams <- reactive({
withProgress(message = 'Generating table...', style = "notification", min = 0, max = 1, value = 0.1, {
a <- abundances(datasetInput(), transform = "compositional") %>% round(digits = input$decimalCases)
})
datatable(a, options = list(scrollX = TRUE))
})
output$relativeAbundanceTable <- renderDataTable( server = FALSE, {
relativeAbundanceParams()
})
output$downloadRelativeAbundance <- downloadHandler(
filename = function() {
paste("relativeAbundance", ".csv", sep = "")
},
content = function(file) {
a <- abundances(datasetInput(), transform = "compositional") %>% round(digits = input$decimalCases)
write.csv(a, file, row.names = TRUE)
}
)
# Updating SelectInputs when database changes #
observeEvent(input$datasetUpdate, {
tryCatch({
updateSelectInput(session, "x",
choices = colnames(meta(datasetInput())))
updateSelectInput(session, "x2", choices = colnames(meta(datasetInput())))
updateSelectInput(session, "x3", choices = colnames(meta(datasetInput())))
updateSelectInput(session, "y",
choices = colnames(alpha(datasetInput())))
}, error = function(e){
simpleError(e)
})
}, ignoreNULL = FALSE)
# Metadata table#
metaTableParams <- reactive({
withProgress(message = 'Generating table...', style = "notification", min = 0, max = 1, value = 0.1, {})
datatable(sample_data(datasetInput()), options = list(scrollX = TRUE))
})
#Diversity measures table
diversityMeasuresTableParams <- reactive({
withProgress(message = 'Generating table...', style = "notification", min = 0, max = 1, value = 0.1, {
a <- estimate_richness(datasetInput(), measures = c("Observed","Chao1","Ace","Shannon","Simpson","InvSimpson","Fisher")) %>% round(digits = input$decimalCases)
setProgress(message = "Rounding values...", value = 0.5)
colnames(a) <- c("Observed species", "Chao1", "Standard error (Chao1)", "ACE", "Standard error (ACE)", "Shannon's diversity index","Simpson's diversity index","Inverse Simpson","Fisher's alpha")
setProgress(message = "Rendering table...", value = 0.8)
})
datatable(a, options = list(scrollX = TRUE))
})
output$metaTable <- DT::renderDataTable({
metaTableParams()
})
output$downloadMetaTable <- downloadHandler(
filename = function() {
paste("MetadataTable", ".csv", sep = "")
},
content = function(file) {
write.csv(meta(datasetInput()), file, row.names = TRUE)
}
)
output$diversityMeasuresTable <- DT::renderDataTable({
diversityMeasuresTableParams()
})
output$downloadDiversityMeasuresTable <- downloadHandler(
filename = function() {
paste("DiversityMeasuresTable", ".csv", sep = "")
},
content = function(file) {
write.csv(meta(datasetInput()), file, row.names = TRUE)
}
)
# Alpha Diversity Richness Plot #
richnessPlotParams <- reactive({
withProgress(message = 'Generating plot...', style = "notification", min = 0, max = 1, value = 0.1, {
if(input$richnessPlotGridWrap == FALSE){
setProgress(message = "Generating plot...", value = 0.3)
richnessplot <- plot_richness(
datasetInput(),
x = input$x2,
measures = input$richnessChoices,
color = input$x3
) + theme_pubr(base_size = 10, margin = TRUE, legend = "right", x.text.angle = 90)
} else {
setProgress(message = "Generating plot...", value = 0.3)
richnessplot <- plot_richness(
datasetInput(),
x = input$x2,
measures = input$richnessChoices,
color = input$x3 ) +
facet_grid(paste('~',input$x),scales = "free", space = "free") + theme_pubr(base_size = 10, margin = TRUE, legend = "right", x.text.angle = 90)
}
setProgress(message = "Generating plot...", value = 0.5)
if(input$transparentRichness == TRUE){
richnessplot <- richnessplot +
theme(panel.background = element_rect(fill = "transparent", colour = NA), plot.background = element_rect(fill = "transparent", colour = NA), legend.background = element_rect(fill = "transparent", colour = NA), legend.box.background = element_rect(fill = "transparent", colour = NA))
}
setProgress(message = "Generating plot...", value = 0.7)
richnessplot <- richnessplot + rremove("xlab") + rremove("ylab")
p <- ggplotly(richnessplot, height = 500, width = plot_width(datasetInput())) %>% layout(xaxis = list(title = input$x2, automargin = TRUE), yaxis = list(title = paste("Alpha Diversity Measure (", input$richnessChoices , ")"), automargin = TRUE))
setProgress(message = "Generating plot...", value = 0.9)
})
print(p)
})
output$richnessPlot <- renderPlotly({
richnessPlotParams() %>% config(editable = T, autosizable = T)
})
## Beta Diversity ##
# Updating SelectInputs when dataset changes#
observeEvent(input$datasetUpdate, {
tryCatch({
updateSelectInput(session, "xb",
choices = colnames(meta(datasetInput())))
updateSelectInput(session, "xb2",
choices = colnames(meta(datasetInput())))
updateSelectInput(session, "xb3",
choices = colnames(meta(datasetInput())))
updateSelectInput(session, "yb",
choices = colnames(meta(datasetInput())))
updateSelectInput(session, "zb",
choices = colnames(tax_table(datasetInput())))
updateSelectInput(session, "zbsplit",
choices = colnames(tax_table(datasetInput())))
}, error = function(e){
simpleError(e)
})
}, ignoreNULL = FALSE)
compositionalInput <- reactive({
a <- microbiome::transform(datasetInput(), transform = "compositional", target = "OTU")
return(a)
})
#Function to prepare
betaDiversityInput <- reactive({
if(input$dataTransformation == TRUE){
a <- microbiome::transform(datasetInput(), transform = "hellinger", target = "OTU")
} else {
a <- compositionalInput()
}
return(a)
})
# Perform ordination
ordinateData <- reactive({
ordinate(
betaDiversityInput(),
method = input$ordinate.method,
distance = input$ordinate.distance
)
})
ordinateDataTaxa <- reactive({
ordinate(
betaDiversityInput(),
method = input$ordinate.method.taxa,
distance = input$ordinate.distance.taxa
)
})
# Hack solution to add samples names to ordination plots
# ordinateSamplesColumn <- reactive({
# if(input$datasetChoice == "Sample dataset"){
# samplesCol <- colnames(otu_table(datasetInput()))
# }
# if(input$datasetChoice == "Biom file"){
# if(input$samplesAreColumns == TRUE){
# samplesCol <- colnames(otu_table(datasetInput()))
# } else {
# samplesCol <- rownames(otu_table(datasetInput()))
# }
# }
# return(samplesCol)
# })
ordinatePlotParams <- reactive({
withProgress(message = 'Generating plot...', style = "notification", value = 0.2, min = 0, max = 1, {
a <- datasetInput()
if (ncol(sample_data(datasetInput())) > 1){
setProgress("Generating plot...", value = 0.5)
p <- phyloseq::plot_ordination(a, ordinateData(), color = input$xb, label = NULL, title = "Ordination Plot") + geom_point(size = input$geom.size) + theme_pubr(base_size = 10, margin = TRUE, legend = "right")
} else {
setProgress("Preparing data...", value = 0.4)
sample_data(a)[,2] <- sample_data(a)[,1]
setProgress("Generating plot...", value = 0.5)
p <- phyloseq::plot_ordination(a, ordinateData(), color = input$xb, label = NULL, title = "Ordination Plot") + geom_point(size = input$geom.size) + theme_pubr(base_size = 10, margin = TRUE, legend = "right")
}
# if(input$polygonOrdinatePlot){
# setProgress("Adding lines...", value = 0.7)
# p <- p + geom_line(aes(fill=input$xb))
# }
if(input$transparentOrdinatePlot){
setProgress("Adding transparency...", value = 0.8)
p <- p +
theme(panel.background = element_rect(fill = "transparent", colour = NA), plot.background = element_rect(fill = "transparent", colour = NA), legend.background = element_rect(fill = "transparent", colour = NA), legend.box.background = element_rect(fill = "transparent", colour = NA))
}
setProgress("Generating plot...", value = 0.9)
})
ggplotly(p, height = 500, width = 1050)
})
output$ordinatePlot <- renderPlotly({
ordinatePlotParams() %>% config(editable = T, autosizable = T)
})
taxaOrdParams <- reactive({
withProgress(message = 'Generating plot...', style = "notification", value = 0.5, {
taxaOrdplot <-
plot_ordination(
datasetInput(),
ordinateDataTaxa(),
type = "taxa",
title = "Ordination Plot",
color = input$zb,
label = input$xb
) + geom_point(size = input$geom.size.taxa) + theme_pubr(base_size = 10, margin = TRUE, legend = "right")
setProgress("Generating plot...", value = 0.8)
if(input$transparentTaxaOrd){
setProgress("Adding transparency...", value = 0.9)
taxaOrdplot <- taxaOrdplot +
theme(panel.background = element_rect(fill = "transparent", colour = NA), plot.background = element_rect(fill = "transparent", colour = NA), legend.background = element_rect(fill = "transparent", colour = NA), legend.box.background = element_rect(fill = "transparent", colour = NA))
}
if(input$splitTaxaOrd){
taxaOrdplot <- taxaOrdplot + facet_wrap(paste('~',input$zb), 3)
}
setProgress("Generating plot...", value = 0.9)
})
ggplotly(taxaOrdplot, height = 500, width = 1050)
})
output$taxaOrd <- renderPlotly({
taxaOrdParams() %>% config(editable = T, autosizable = T)
})
###########################
## Statistical analysis ###
###########################
## PERMANOVA ##
#Update metadata column when dataset changes
observeEvent(input$datasetUpdate, {
tryCatch({
updateSelectInput(session, "permanovaColumn",
choices = colnames(meta(datasetInput())))
updateSelectInput(session, "permanovaColumnP",
choices = colnames(meta(datasetInput())))
updateSelectInput(session, "permanovaColumnFac",
choices = colnames(meta(datasetInput())))
updateSelectInput(session, "permanovaMetadataNet",
choices = colnames(meta(datasetInput())))
updateSelectInput(session, "permanovaMetaShapeNet",
choices = colnames(meta(datasetInput())))
}, error = function(e){
simpleError(e)
})
}, ignoreNULL = FALSE)
permanova <- reactive({
withProgress(message = 'Calculating PERMANOVA...', style = "notification", value = 0.5, {
otu <- abundances(compositionalInput())
meta <- meta(compositionalInput())
permnumber <- input$permanovaPermutationsP
metadata <- input$permanovaColumnP
m <- meta[[metadata]]
setProgress("Calculating PERMANOVA...", value = 0.6)
a <- adonis(t(otu) ~ m,
data = meta, permutations = permnumber, method = input$permanovaDistanceMethodP, parallel = getOption("mc.cores")
)
setProgress("Calculating PERMANOVA...", value = 0.8)
b <- as.data.frame(a$aov.tab) %>% round(digits = input$decimalCases)
names(b) <- c(metadata, "Df", "Sum Sq", "Mean Sq", "F value", "P value")
setProgress("Generating plot...", value = 0.9)
})
print(b)
})
output$pValue <- renderDataTable({
permanova()
})
output$downloadPValue <- downloadHandler(
filename = function() {
paste("P-ValueTable", ".csv", sep = "")
},
content = function(file) {
write.csv(permanova(), file, row.names = TRUE)
}
)
homogenietyParams <- reactive({
otu <- abundances(compositionalInput())
meta <- meta(compositionalInput())
dist <- vegdist(t(otu))
metadata <- input$permanovaColumnP
anova(betadisper(dist, meta[[metadata]])) %>% round(digits = input$decimalCases)
})
output$homogeniety <- renderDataTable({
homogenietyParams()
})
output$downloadHomogeniety <- downloadHandler(
filename = function() {
paste("HomogenietyTable", ".csv", sep = "")
},
content = function(file) {
write.csv(homogenietyParams(), file, row.names = TRUE)
}
)
topFactorPlotParams <- reactive({
withProgress(message = 'Generating plot...', style = "notification", value = 0.5, {
otu <- abundances(compositionalInput())
meta <- meta(compositionalInput())
permnumber <- input$permanovaPermutationsFac
metadata <- input$permanovaColumnFac
column <- meta[[metadata]]
incProgress(message = 'Running PERMANOVA...', amount = 0.1)
permanova <- adonis(t(otu) ~ column,
data = meta, permutations = permnumber, method = input$permanovaDistanceMethodFac
)
incProgress(message = "Printing plot...", amount = 0.2)
coef <- coefficients(permanova)["column1",]
top.coef <- coef[rev(order(abs(coef)))[1:20]] #top 20 coefficients
par(mar = c(3, 14, 2, 1))
p <- barplot(sort(top.coef), horiz = T, las = 1, main = "Top taxa")
})
print(p)
})
output$topFactorPlot <- renderPlot({
topFactorPlotParams()
})
netPlotParams <- reactive({
withProgress(message = 'Making network...', style = "notification", value = 0.3, {
n <- make_network(compositionalInput(), type = "samples", distance = input$permanovaDistanceMethodNet, max.dist = 0.2)
incProgress(message = "Plotting network...", amount = 0.3)
p <- plot_network(n, compositionalInput(), type = "samples", shape = input$permanovaMetaShapeNet, color = input$permanovaMetadataNet, line_weight = 0.4)
if(input$transparentPermanova == TRUE){
incProgress(message = "Adding transparency...", amount = 0.3)
p <- p + theme(panel.background = element_rect(fill = "transparent", colour = NA), plot.background = element_rect(fill = "transparent", colour = NA), legend.background = element_rect(fill = "transparent", colour = NA), legend.box.background = element_rect(fill = "transparent", colour = NA))
}
})
ggplotly(p, height = 500, width = 1050)
})
output$netPlot <- renderPlotly({
netPlotParams() %>% config(editable = T, autosizable = T)
})
### RESULTS ### # Needs a serious rewrite all around
output$downloadReportAlpha <- downloadHandler(
filename = function() {
paste('report', sep = '.', switch(
input$format, PDF = 'pdf', HTML = 'html'
))
},
content = function(file) {
withProgress(message = 'Generating report...', detail = 'This may take a bit.',style = "notification", value = 0.2, {
src <- normalizePath('final_report.Rmd')
setProgress(message = 'Setting temporary path...', value = 0.5)
# temporarily switch to the temp dir, in case you do not have write
# permission to the current working directory
owd <- setwd(tempdir())
on.exit(setwd(owd))
file.copy(src, 'final_report.Rmd', overwrite = TRUE)
setProgress(message = "Rendering report...", value = 0.8)
out <- rmarkdown::render('final_report.Rmd',
switch(input$format,
PDF = pdf_document(),
HTML = html_document()
))
})
file.rename(out, file)
}
)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.