Nothing
server <- function(input, output, session) {
################################################################################
#downloads
filtering_options <- reactive({
#get the reactive inputs for downloadable file
reactive_values <- paste("min.count <- ", input$mincounts, "\n",
"min.prop <- ", input$minprop, "\n",
"max.prop <- ", input$maxprop, "\n",
"min.sum <- ", input$minsum, "\n",
"min.reads <- ", input$minreads, "\n",
"taxselect <- ", as.numeric(input$taxlevel), "\n",
"taxoncheck <- ", as.numeric(input$taxlevel), "\n",
"arrowcheck <- ", input$arrowcheckbox, "\n",
"scale.slider <- ", input$scale, "\n",
"removenames <- ", input$removesamplenames, "\n",
"var.filt <- ", input$varslider, "\n",
"abund <- ", input$abundcutoffbarplot, "\n",
"dist <- ", input$dismethod, "\n",
"clust <- ", input$clustermethod, "\n",
"vals <- ", vals$data, "\n",
"metaval <- ", metaval$data,
sep = "")
})
#combine reactive values with script for PCA biplot
metadata_script <- reactive({
info <- sessionInfo()
loaded <- loadedNamespaces()
# from sessionInfo
package <- grep("^package:", search(), value = TRUE)
keep <- vapply(package, function(x) x == "package:base" ||
!is.null(attr(as.environment(x), "path")), NA)
package <- .rmpkg(package[keep])
# get rid of non-loaded packages (i.e., base)
loaded <- loaded[!(loaded %in% package)]
packages <- list()
packages[loaded] <- loaded
for (i in seq(loaded)) {
packages[loaded[i]] <- paste(info$loadedOnly[[loaded[i]]]$Package, info$loadedOnly[[loaded[i]]]$Version, sep = "-")
}
packages.lines <- as.data.frame(unlist(packages))
colnames(packages.lines) <- "loaded_packages"
# get other packages
other <- list()
for (i in seq(info$otherPkgs)) {
other[i] <- paste(info$otherPkgs[[i]]$Package, info$loadedOnly[[loaded[i]]]$Version, sep = "-")
}
other.packages <- as.data.frame(unlist(other))
colnames(other.packages)[1] <- "other_packages"
#return all the necessary info
# generate output in the desired order
output <- c("Session Info", "\n", info$R.version$version.string, info$platform, info$running, "\n", "Loaded Packages", as.character(packages.lines$loaded_packages), "\n", "Other attached packages", as.character(other.packages$other_packages))
})
PCA_script <- reactive({
y <- filtering_options()
metadata <- metadata_script()
PCA_script <- c(metadata, "\n", "Filtering options", y, readLines("./PCA_script.R"))
})
rab_script <- reactive({
y <- filtering_options()
metadata <- metadata_script()
rab_script <- c(metadata, "\n", "Filtering options", y, readLines("./rab_script.R"))
})
effect_script <- reactive({
y <- filtering_options()
metadata <- metadata_script()
effect_script <- c(metadata, "\n", "Filtering options", y, readLines("./effect_script.R"))
})
file_name <- reactive({
inFile <- input$file1
file_name <- inFile$name
})
#download script for PCA biplot
output$PCA_download <- downloadHandler(
filename=function(){paste(file_name(), "_PCA.r", sep = "")},
content= function(file) {
writeLines(PCA_script(), file)
}
)
#download script for rab plots
output$rab_download <- downloadHandler(
filename=function(){paste(file_name(), "_rab.r", sep = "")},
content= function(file) {
writeLines(rab_script(), file)
}
)
#download script for effect plots
output$effect_download <- downloadHandler(
filename=function(){paste(file_name(), "_effect.r", sep = "")},
content= function(file) {
writeLines(effect_script(), file)
}
)
output$ebi_counts_download <- downloadHandler(
filename = "ebi_counts.txt",
content = function(file) {
write.table(vals$ebi_counts, file, sep = "\t", quote = FALSE, col.names = TRUE, row.names = FALSE)
}
)
################################################################################
#observe events
#quit button
options(shiny.maxRequestSize=70*1024^2)
observeEvent(input$stopApp, {
stopApp(returnValue = invisible())
})
#reset filter
observeEvent(input$reset, {
vals$data <- NULL
removeModal()
})
#pop up the modal
observeEvent(input$choosemeta, {
showModal(metaModal())
})
#convert input to reactive object
observeEvent(input$update, {
vals$data <-
c(input$cnname, input$cnname2, input$cnname3, input$cnname4)
metaval$data <- input$select_biplot_filter
removeModal()
})
#pop up the modal for EBI input
observeEvent(input$input_ebi_project, {
showModal(ebiModal())
})
#convert input to reactive object
observeEvent(input$update_EBI, {
# make progress bar object
progress <- shiny::Progress$new()
# close on exit
on.exit(progress$close())
# set to zero
progress$set(message = "Downloading dataset", value = 0)
# get the MGnify project ID from the input
sample_id <- input$ebi_id
# base for MGnify api
api_base = 'https://www.ebi.ac.uk/metagenomics/api/latest/'
# define link to get samples
samples_link <- paste0(api_base, "studies/", sample_id, "/samples")
# extract number of pages to collect all samples by getting
# number of pages from last page line
last_link <- jsonlite::fromJSON(paste0(samples_link, "?page=1"))$links$last
num_pages <- substr(last_link, nchar(last_link), nchar(last_link) + 1)
# initiate all samples vector
all_samples <- c()
# update progress bar
progress$inc(1/5, detail = "All samples found")
# loop through all pages to get all sample names
for (i in 1:num_pages) {
current_samples <- jsonlite::fromJSON(paste0(samples_link, "?page=", i))$data$id
all_samples <- c(all_samples, current_samples)
}
# for each sample name, get the list of runs
runs_link <- paste0(api_base, "samples/")
# loop through all samples to get all runs that are associated
all_runs <- c()
progress$inc(0, detail = "Downloading runs...")
# this loops through the samples and gets all the run numbers. it takes a while for some reason (about 25 seconds for 70 samples)
for (i in seq(all_samples)) {
current_run <- jsonlite::fromJSON(paste0(runs_link, all_samples[i], "/runs"))$data$id
all_runs <- c(all_runs, current_run)
# print status message
message(paste0("Finished getting run for sample ", all_samples[i]))
progress$inc(0, detail = paste0("Downloading runs... ", i, "/", length(all_samples)))
}
progress$inc(1/5, detail = "All runs downloaded")
# download the analysis accession for each of the runs
go_slim_link <- paste0(api_base, "runs/")
# get accession numbers for all runs
all_acc <- c()
progress$inc(0, detail = "Downloading accessions...")
for (i in seq(all_runs)) {
current_acc <- jsonlite::fromJSON(paste0(go_slim_link, all_runs[i], "/analyses"))$data$id
all_acc <- c(all_acc, current_acc)
# show message to give status
message(paste0("Finished getting accession for run ", all_runs[i]))
progress$inc(0, detail = paste0("Downloading accessions... ", i, "/", length(all_runs)))
}
progress$inc(1/5, detail = "All accessions found")
# download counts for every accession
analyses_link <- "https://www.ebi.ac.uk/metagenomics/api/v1/analyses/"
# set up the counts table with the GO terms
all_counts <- data.frame(GO = jsonlite::fromJSON(paste0(analyses_link, all_acc[i], "/go-slim"))$data$attributes$accession)
all_counts$description <- jsonlite::fromJSON(paste0(analyses_link, all_acc[i], "/go-slim"))$data$attributes$description
all_counts$category <- jsonlite::fromJSON(paste0(analyses_link, all_acc[i], "/go-slim"))$data$attributes$lineage
# add columns for each run, name appropriately (+3 is because first three columns are descriptors
all_counts[,4:(length(all_runs)+3)] <- "NA"
# rename columns with run numbers
colnames(all_counts)[4:length(all_counts)] <- all_runs
progress$inc(0, detail = "Downloading count tables...")
# add counts to the data table by column
# this downloads go-slim counts for every sample.
for (i in seq(all_acc)) {
current_count <- jsonlite::fromJSON(paste0(analyses_link, all_acc[i], "/go-slim"))$data$attributes$count
message(paste0("Finished accession ", all_acc[i]))
progress$inc(0, detail = paste0("Downloading count tables... ", i, "/", length(all_acc)))
# replace column column with counts for each accession, increments each iteration
all_counts[,3+i] <- current_count
}
progress$inc(1/5, detail = "All count tables downloaded")
vals$ebi_counts <- all_counts
# count table generated
progress$inc(0, detail = "Merged count table generated")
# remove modal
removeModal()
# give pop up for saving file
vals$download_finished <- TRUE
})
observeEvent(input$update_EBI, {
if (vals$download_finished == TRUE) {
showModal(ebi_download_modal())
}
})
observeEvent(input$select_ef_columns, {
showModal(select_columns())
})
#dendrogram brush ranges
ranges <- reactiveValues(x = NULL, y = NULL)
bp_ranges <- reactiveValues(x = NULL, y = NULL)
###########################################################################
#custom UIs
#make the pop up
metaModal <- function (x) {
modalDialog(
renderUI({
metadata <- metadata()
#message if there is nothing uploaded
if (is.null(metadata)) {
selectInput(
"select_biplot_filter",
label = h3("Filter biplot by metadata column"),
choices = list(
"Input data" = 1
),
selected = 1
)
} else {
options <- colnames(metadata)
selectInput(
"select_biplot_filter",
label = h3("Filter data by metadata column"),
choices = options,
selected = 1
)
}
}),
textInput("cnname", "Value 1", placeholder = "Enter value from metadata or leave blank"),
textInput("cnname2", "Value 2", placeholder = "Enter value from metadata or leave blank"),
textInput("cnname3", "Value 3", placeholder = "Enter value from metadata or leave blank"),
textInput("cnname4", "Value 4", placeholder = "Enter value from metadata or leave blank"),
title = "Choose metadata values to filter PCA biplot",
"Enter metadata values of the metadata variable you have chosen (must be exact match).
The biplot will be replotted with only the samples identified by
the metadata values. Leave inputs blank if you don't need them.
Samples that do not have metadata will be coloured black",
footer = tagList(actionButton("update", "Update Filter"),
actionButton("reset", "Reset Filter"),
modalButton("Cancel")),
easyClose = TRUE
)
}
#pop up for inputting ebi project numberq
ebiModal <- function (x) {
modalDialog(
textInput("ebi_id", "EBI Project ID", placeholder = "Project ID"),
title = "Download EBI project to explore",
"Enter the MGnify study ID (for example: MGYS00001110) to download the GO slim annotation for all samples. This will take a few minutes to gather all data depending on the size of the study. Internet access if required. Do not close window while download is in progress. File will be automatically inputted after downloading.",
footer = tagList(actionButton("update_EBI", "Download and input"),
modalButton("Cancel")),
easyClose = TRUE
)
}
ebi_download_modal <- function (x) {
modalDialog(
title = "Save counts table?", "Click yes to save the counts table locally. Input this file to avoid redownloading the data.",
footer = tagList(h3(downloadButton("ebi_counts_download", "Yes")), modalButton("No"), modalButton("Close this window")), easyClose = TRUE
)
}
select_columns <- function (x) {
modalDialog(
title = "Manually select conditions",
"Enter the column numbers for each condition, separated by a comma. Condition 1 will be compared against condition 2. Scroll across table to see column names. Column numbers are shown below the column name.",
DT::renderDataTable({
data <- data.t()
dataTable <- data.frame(matrix(0, ncol = length(colnames(data)), nrow = 1))
colnames(dataTable) <- colnames(data)
newrow <- 1:length(dataTable)
dataTable <- rbind(newrow, dataTable)
rownames(dataTable) <- c("Column number", "")
dataTable
}, options = list(pageLength = 5, scrollX = TRUE)),
textInput("effect_cond_1", "Columns for condition 1", placeholder = "1, 2, 3, ..."),
textInput("effect_cond_2", "Columns for condition 2", placeholder = "1, 2, 3, ..."),
footer = tagList(actionButton("column_choice_ab", "Update conditions"), modalButton("Close window")), easyClose =TRUE
)
}
output$taxchoice <- renderUI({
if (input$taxoncheckbox) {
radioButtons("taxlevel",
"Choose taxonomic level to display",
c("Kingdom" = 1,
"Phylum" = 2,
"Class" = 3,
"Order" = 4,
"Family" = 5,
"Genus" = 6,
"Species" = 7),
selected = 4
)
}
})
#dynamic variance slider
output$varianceslider <- renderUI({
data <- data()
sliderInput(
"varslider",
"Variance cutoff",
min = 0,
max = 5,
value = 0,
step = 0.05
)
})
#effect plot conditions
output$conditions<- renderUI({
if (input$ep_chooseconds == 2) {
meta <- metadata()
options <- colnames(meta)
cn <- input$colselect
choice <- unique(meta[[cn]])
tagList(
selectInput("group1", "Choose group 1", choices = choice),
selectInput("group2", "Choose group 2", choices = choice))
}
})
#choose column from metadata
output$colselectcond <- renderUI({
meta <- metadata()
options <- colnames(meta)
selectInput("colselect", "Select column from metadata", choices = options)
})
###########################################################################
#data input
#get data from uploaded file
data <- reactive({
if (input$exampledata) {
read.table(
"example_data.txt",
header = TRUE,
sep = "\t",
stringsAsFactors = FALSE,
quote = "",
row.names = 1,
check.names = FALSE,
comment.char = "",
na.strings = ""
)
} else if (input$exampledata2) {
read.table(
"selex.txt",
header = TRUE,
sep = "\t",
stringsAsFactors = FALSE,
quote = "",
row.names = 1,
check.names = FALSE,
comment.char = "",
na.strings = ""
)} else if (!is.null(vals$ebi_counts)) {
# load downloaded file as input
data <- vals$ebi_counts
# make rownames descriotion
rownames(data) <- data$description
# rearrange, put descriptors at end so it's easy to take off
data <- cbind(data[,4:length(data)], GO = data[,1], category = data[,3])
} else if (input$ebi_format == TRUE) {
#reactive input file
inFile <- input$file1
#return NULL when no file is uploaded
if (is.null(inFile))
return(NULL)
# input EBI formatted data
data <- read.table(
inFile$datapath,
header = TRUE,
sep = "\t",
stringsAsFactors = FALSE,
quote = "",
row.names = NULL,
check.names = FALSE,
comment.char = "",
na.strings = "")
# make rownames descriotion
rownames(data) <- data$description
# rearrange, put descriptors at end so it's easy to take off
data <- cbind(data[,4:length(data)], GO = data[,1], category = data[,3])
} else {
#reactive input file
inFile <- input$file1
#return NULL when no file is uploaded
if (is.null(inFile))
return(NULL)
#reads the file
#if there's an error, it doesn't quit omicplotR
data <- try(read.table(
inFile$datapath,
header = TRUE,
sep = "\t",
stringsAsFactors = FALSE,
quote = "",
row.names = 1,
check.names = FALSE,
comment.char = "",
na.strings = ""), silent = TRUE)
#if rownames error
if(grepl("duplicate 'row.names'", data[1], fixed = TRUE)) {
showModal(rownamesModal())
} else {
#if no error, then continue
data <- data
}
}
}) #reactive
#get metadata from uploaded file
metadata <- reactive({
if (input$exampledata) {
read.table(
"example_metadata.txt",
header = TRUE,
sep = "\t",
stringsAsFactors = FALSE,
quote = "",
row.names = 1,
check.names = FALSE,
comment.char = ""
)
} else {
#reactive input file
inFile2 <- input$file2
#return NULL when no file is uploaded
if (is.null(inFile2))
return(NULL)
#reads the file
read.table(
inFile2$datapath,
header = TRUE,
sep = "\t",
stringsAsFactors = FALSE,
quote = "",
row.names = 1,
check.names = FALSE,
comment.char = ""
)
}
})
################################################################################
#tests to make sure input is correct format
formatModal <- function(failed = FALSE) {
modalDialog(
title="Incorrect format",
"There are duplicate column names. Ensure all column names unique, then re-import your file.",
easyClose = TRUE,
footer = modalButton("Dismiss")
)
}
rownamesModal <- function(failed = FALSE) {
modalDialog(
title="Incorrect format",
"There are duplicate row names. Ensure all row names unique, then re-import your file.",
easyClose = TRUE,
footer = modalButton("Dismiss")
)
}
#check data format
observeEvent(input$showdata, {
inFile <- data()
#return NULL when no file is uploaded
if (is.null(inFile)) {
return(NULL)
}
#make frequency table of occurence of colnames
c_occur <- data.frame(table(colnames(inFile)))
#if frequency is more than one, show the "your format is wrong" modalDialog
if (max(c_occur$Freq) > 1) {
showModal(formatModal())
} else {
return(NULL)
}
})
#metadata check format
observeEvent(input$showmetadata, {
inFile2 <- metadata()
#return NULL when no file is uploaded
if (is.null(inFile2)) {
return(NULL)
}
#make frequency table of occurence of colnames
c_occur <- data.frame(table(colnames(inFile2)))
#if frequency is more than one, show the "your format is wrong" modalDialog
if (max(c_occur$Freq) > 1) {
showModal(formatModal())
} else {
return(NULL)
}
})
################################################################################
#input ALDEx2 table
effect_input <- reactive({
inFile3 <- input$effect_file
#return NULL when no file is uploaded
if (is.null(inFile3))
return(NULL)
read.table(
inFile3$datapath,
header = TRUE,
sep = "\t",
stringsAsFactors = FALSE,
quote = "",
row.names = 1,
check.names = FALSE,
comment.char = "",
na.strings = ""
)
})
#create reactive object for biplot filtering inputs
vals <- reactiveValues(data = NULL)
metaval <- reactiveValues(data = NULL)
#get column selection for metadata
column <- reactive({
cn <- input$selectcolumn
})
###########################################################################
#data processing
#generate taxonomy vector for biplots
taxonomy <- reactive({
data <- data.t()
tax.result <- data.check()
#if no taxonomy column, return NULL for later
if (isTRUE(tax.result)) {
tax <- NULL
} else {
#remove taxonomy column
tax <- data$taxonomy
data$taxonomy <- NULL
#get genus names
genus <- vapply(strsplit(as.character(tax), "[[:punct:]]"), "[", taxselected, FUN.VALUE=character(1))
}
})
#if taxonomic column present, return boolean. no tax column returns TRUE
data.check <- reactive ({
data.r <- data()
if (is.null(data.r$taxonomy)) {
return(TRUE)
} else {
return(FALSE)
}
})
#do transformations of data for biplot
data.t <- reactive ({
#get the data
x <- data()
meta <- metadata()
cn <- column()
#set to zero, but inputs from sliders/numeric inputs
min.count <- input$mincounts
min.prop <- input$minprop
max.prop <- input$maxprop
min.sum <- input$minsum
min.reads <- input$minreads
# validation statements
validate((need((input$mincounts >=0), "Input minimum count per feature (0 or above)")))
validate((need((input$minprop >=0), "Input minimum proportional abundance (0 or above)")))
validate((need((input$maxprop <= 1), "Input maximum proportional abundance (1 or below)")))
validate((need((input$minsum >= 0), "Input minimum count sum (0 or above)")))
validate((need((input$minreads >= 0), "Input minimum count sum per samples (0 or above)")))
#catch the errors
validate((need(input$minprop, "Processing..")))
#check for tax
if (is.null(x$taxonomy)) {
taxCheck <- TRUE
if (input$ebi_format == TRUE) {
# this removes the additional columns.
order <- order(colnames(x[,1:(ncol(x) - 2) ]))
test <- as.matrix(x[order])
} else {
test <- as.matrix(x[order(colnames(x))])
}
validate(need(min.reads < max(colSums(test)), "Minimum count sum per sample exceeds any sample. Reduce so not all samples are removed by filter."))
# filter by min reads per sample
test.0 <- test[, which(colSums(test) > min.reads)]
validate(need(min.count < max(matrixStats::rowMaxs(test.0)), "Minimum count per feature exceeds maximum count. Reduce so not all features are removed by filter."))
# filter by min count per feature
test.1 <- test.0[which(matrixStats::rowMaxs(test.0) >= min.count), ]
# filter by sum of count per feature
test.2 <- test.1[which(rowSums(test.1) >= min.sum), ]
} else {
taxCheck <- FALSE
test <- x[order(colnames(x[seq_len(length(x) - 1)]))]
validate(need(min.reads < max(colSums(test)), "Minimum count sum per sample exceeds any sample. Reduce so not all samples are removed by filter."))
# filter by min reads per sample
test.0 <- as.matrix(test[, which(colSums(test[, seq_along(test)]) >=
min.reads)])
validate(need(length(which(matrixStats::rowMaxs(test.0) > min.count)) > 1, "Minimum count per feature exceeds maximum count. Reduce so not all features are removed by filter."))
# filter by min count per feature
test.1 <- test.0[which(matrixStats::rowMaxs(test.0) >= min.count),]
# filter by sum of count per feature
test.2 <- test.1[which(rowSums(test.1) >= min.sum), ]
}
#get filtered data if filtered
if (is.null(vals$data)) {
x <- x
} else {
x <- omicplotr.metadataFilter(x, meta, column = metaval$data, values = vals$data)
}
if (input$ebi_format == TRUE) {
# remove last two columns (GO terms and descriptor columns)
x.filt <- omicplotr.filter(x[,1:(ncol(x)-2)], min.reads = min.reads, min.count = min.count, min.prop = min.prop, max.prop = max.prop, min.sum = min.sum)
} else {
x.filt <- omicplotr.filter(x, min.reads = min.reads, min.count = min.count, min.prop = min.prop, max.prop = max.prop, min.sum = min.sum)
}
return(x.filt)
})
#prcomp object
data.prcomp <- reactive({
#get data
data.t <- data.t()
# prevent further calculation if or less than 1 sample remains
validate(need((dim(data.t)[1] > 0 & dim(data.t)[2] > 1), "Filtering has removed all features or samples. Reduce the stringency of the filters so you have features to plot."))
var.filt <- input$varslider
data <- data()
validate(need(input$varslider, "Calculating..."))
#check for tax
if (is.null(data$taxonomy)) {
taxCheck <- TRUE
} else {
taxCheck <- FALSE
}
#catch error if there is no data
if (is.null(data)) {
return(NULL)
} else {
if (isTRUE(taxCheck)) {
data.t <- data.t
} else {
data.t$taxonomy <- NULL
}
# check fo variance filter
if (any(data.t == 0)) {
test.0 <- zCompositions::cmultRepl(t(data.t), label = 0, method = "CZM")
}
else {
test.0 <- t(data.t)
}
test.clr <- as.matrix(log(test.0) - rowMeans(log(test.0)))
# requires more than 1 feature to remain for plotting.
validate(need(length(which(var.filt < matrixStats::colVars(test.clr))) > 1, "Variance filter exceeds maximum variance. Reduce the stringency of the filters so you have features to plot."))
# set to CZM by default
zeros <- "CZM"
if (input$zero_replacement == 1) {
zeros <- "CZM"
}
if (input$zero_replacement == 2) {
zeros <- "pseudo"
}
data.pr <- omicplotr.clr(data.t, var.filt, zero.method=zeros)
}
return(data.pr)
})
#these are for effect plot choices by metadata
cn <- ""
group1 <- ""
group2 <- ""
denom <- ""
observeEvent(input$column_choice_ab, {
effect_cond_2 <<- input$effect_cond_2
effect_cond_1 <<- input$effect_cond_1
})
#computing aldex object
d.clr <- reactive({
# get reactive input from selecting conditions
cn <- input$colselect
group1 <- input$group1
group2 <- input$group2
denom <- input$denomchoice
x <- data.t()
meta <- metadata()
#require user to click action button
validate(need(input$effectplot_ab, ""))
#get filtered metadata if it is filtered
if (is.null(vals$data)) {
x <- x
} else {
x <- omicplotr.metadataFilter(x, meta, column = metaval$data, values = vals$data)
meta <- meta[which(rownames(meta) %in% colnames(x)),]
}
# Separate the taxonomy column from the counts
if (is.null(x$taxonomy)) {
d <- x
} else {
d <- x[, 0:(dim(x)[2] - 1)]
taxon <- x[(dim(x)[2])]
}
if (input$ep_chooseconds == 1) {
g1s <- effect_cond_1
g2s <- effect_cond_2
# rearrange the columns and make conditions
# split on the comma and space to get all columns for each condtion
group1 <- as.integer(unlist(strsplit(g1s, ", ")))
group2 <- as.integer(unlist(strsplit(g2s, ", ")))
# rearrange for aldex table
d <- cbind(d[group1], d[group2])
# make conditions length of each group
# make conds a global variable that can be accessed by other functions
conds <<- c(rep("group1", length(group1)),
rep("group2", length(group2)))
}
if (input$ep_chooseconds ==2) {
#filter the metadata and keep only the data which have been chosen
group1 <- rownames(meta[which(meta[[cn]] == group1), ])
group1.filt <- group1[group1 %in% (colnames(x))]
data1.filt <- x[,which(colnames(x) %in% group1.filt)]
one <- length(data1.filt)
group2 <- rownames(meta[which(meta[[cn]] == group2), ])
group2.filt <- group2[group2 %in% (colnames(x))]
data2.filt <- x[,which(colnames(x) %in% group2.filt)]
two <- length(data2.filt)
# make conds a global variable that can be accessed by other functions
conds <<- c(rep("Group 1", one),
rep("Group 2", two))
#combine
d <- cbind(data1.filt, data2.filt)
}
# Generate ALDEx2 object and get a distribution of values that are centered
# log ratio transformed at each feature*sample
choices = c("all", "iqlr", "zero")
method <- choices[as.numeric(denom)]
withProgress(
message = "Calculating",
detail = "Calculating expected clr values", value = 1/2, {
d.clr <- aldex.clr(d, mc.samples=128, conds = conds, denom = method, verbose=TRUE)
incProgress(1/2, message = "clr values calculated")
}
)
#output d.clr
d.clr <- d.clr
})
aldex.obj <- reactive({
x <- data.t()
d.clr <- d.clr()
meta <- metadata()
#get filtered data if filtered
if (is.null(vals$data)) {
x <- x
} else {
x <- omicplotr.metadataFilter(x, meta, column = metaval$data, values = vals$data)
meta <- meta[which(rownames(meta) %in% colnames(x)),]
}
if (is.null(x$taxonomy)) {
d <- x
} else {
d <- x[, 0:(dim(x)[2] - 1)]
taxon <- x[(dim(x)[2])]
}
withProgress(
message = "Calculating t-test...",
detail = "Calculating t test and effect size", value = 1/2, {
# Run a t-test between the two groups specified by conds
#TODO option to generate effect plots ttest to save time.
# this will require changing aldex.plot in effect plot output
x.tt <- aldex.ttest(d.clr, paired.test=FALSE)
incProgress(1/4, message = "Calculating effect size...")
# Generate effect sizes
x.effect <- aldex.effect(d.clr, include.sample.summary=TRUE,
verbose=TRUE)
incProgress(1/4, message = "Efect sizes calculated")
}
)
# Combine into one table
x.all <- data.frame(x.tt, x.effect, stringsAsFactors=FALSE)
})
#stripchart data
clr.strip <- reactive({
x <- d.clr()
codaSeq.repl <- function(x){
# Initialize medians vector to be reshaped later to matrix
MC.means <- numeric()
# Iterating all samples
for(i in seq_len(numConditions(x))) {
sample.means <- numeric()
# Get sample's MC Instances for features
MC.matrix <- getMonteCarloInstance(x, i)
# Iterating features
for(j in seq_len(numFeatures(x))) {
feature.means <- mean(MC.matrix[j, ])
sample.means <- append(sample.means, feature.means)
}
# Add subject's MC instance medians to master vector
MC.means <- append(MC.means, sample.means)
}
# Turn the vector of medians into a matrix and then data frame with
result <- matrix(MC.means, nrow = numFeatures(x), ncol = numConditions(x))
result <- data.frame(result, row.names = getFeatureNames(x))
colnames(result) <- getSampleIDs(x)
return(result)
}
clr.strip <- codaSeq.repl(x)
})
###########################################################################
# outputs
#show removed OTUs/samples
output$removedDT <- DT::renderDataTable({
# catch error message
validate(need(data() != "", ""),
need(input$showremoved, ""))
data.pr <- data.prcomp()
data.in <- data()
omicplotr.getRemovedSamples(data.in, data.pr)
},
#force datatable to size of window
options = list(scrollX = TRUE)
)
output$removedDTotu <- DT::renderDataTable({
validate(need(data() != "", ""),
need(input$showremoved, "Click 'Show removed samples/OTUs' to view removed OTUs"))
data.pr <- data.prcomp()
data.in <- data()
omicplotr.getRemovedFeatures(data.in, data.pr)
},
#force datatable to size of window
options = list(scrollX = TRUE))
#choose the metadata column you want to colour by
output$choose_column <- renderUI({
metadata <- metadata()
#message if there is nothing uploaded
if (is.null(metadata)) {
selectInput(
"selectcolumn",
label = h3("Choose column to colour by"),
choices = list(
"No metadata file detected" = 1
),
selected = 1
)
} else {
options <- colnames(metadata)
selectInput(
"selectcolumn",
label = h3("Choose column to colour by"),
choices = options,
selected = 1
)
}
})
output$textTitle <- renderText({
"Choose filtering options"
})
output$nometadata <- renderText({
metadata <- metadata()
if (is.null(metadata)) {
"Select metadata file"
}
})
output$nodata <- renderText({
metadata <- metadata()
if (is.null(data)) {
"Select data file"
}
})
output$nostripchart <- renderText({
validate(need(input$effectplot_ab, "Select conditions and click 'Generate effect plot'"))
})
output$test <- renderText({
if (!is.null(vals$data)) {
c("Data filtered by metadata column:", metaval$data, "value:", vals$data)
} else {
return(NULL)
}
})
output$filter_warning_effect <- renderText({
if (!is.null(vals$data)) {
c("Data filtered by metadata column:", metaval$data, "value:", vals$data)
} else {
return(NULL)
}
})
output$filter_warning_dendro <- renderText({
if (!is.null(vals$data)) {
c("Data filtered by metadata column:", metaval$data, "value:", vals$data)
} else {
return(NULL)
}
})
output$datatable <- DT::renderDataTable({
validate((need(input$showdata, "Click 'Check data' to check format and display table")))
if (input$showdata) {
data <- data()
}
}, options = list(scrollX = TRUE)) #force data table to window size
output$metadatatable <- DT::renderDataTable({
validate((need(input$showmetadata, "Click 'Check metadata' to check format and display table")))
if (input$showmetadata) {
meta <- metadata()
}
}, options = list(scrollX = TRUE)) #force data table to window size
output$contents <- renderTable(include.rownames = TRUE, {
data()
})
##############################################################################
# PCA biplots
#biplot
output$biplot <- renderPlot({
validate(need(data() !="", "Input a correctly formatted data file"))
#get reactive objects
data <- data.prcomp()
tax <- data.t()
removenames <- input$removesamplenames
scale.slider <- input$scale
arrowcheck <- input$arrowcheckbox
taxoncheck <- input$taxoncheckbox
taxselect <- as.numeric(input$taxlevel)
#title <- input$biplot_title
opacity <- input$opacity_samples_pca
sample_size <- input$size_samples_pca
x.var <- sum(data$sdev ^ 2)
PC1 <- paste("PC 1 Variance: %", round(sum(data$sdev[1] ^ 2) / x.var * 100, 1))
PC2 <- paste("PC 2 Variance: %", round(sum(data$sdev[2] ^ 2) / x.var*100, 1))
#if no data don't display anything
if (is.null(data))
return(NULL)
if (input$taxoncheckbox) {
validate(need(input$taxlevel, "Processing..."))
}
taxonomy <- tax$taxonomy
#if Show taxonomy checkbox is clicked, take chosen level
if (isTRUE(taxoncheck)) {
taxselect <- as.numeric(input$taxlevel)
} else {
taxselect <- 6
}
#get genus (or other level)
genus <- vapply(strsplit(as.character(taxonomy), "[[:punct:]]"), "[", taxselect, FUN.VALUE=character(1))
#biplot colouring options
col = c(rgb(0,0,0,opacity), rgb(0, 0, 0, 0.2))
#do checks for arrows
if (isTRUE(arrowcheck)) {
arrows = FALSE
} else {
arrows = TRUE
}
#if taxonomy is is null, use periods as points for features..
#if taxoncheckbox is checked, show genus instead of points, otherwise
if (isTRUE(taxoncheck)) {
points <- genus
} else {
points <- c(rep(".", length(dimnames(data$rotation)[[1]])))
}
#remove sample names
if (isTRUE(removenames)) {
xlabs <- c(rep(".", length(dimnames(data$x)[[1]])))
size = c(5, 0.8)
} else {
xlabs = unlist(dimnames(data$x)[1])
size = c(sample_size, 0.8)
}
biplot(
data,
main = "Principal Component Analysis",
cex.main = 1.5,
cex = size,
col = col,
scale = scale.slider,
var.axes = arrows,
xlab = PC1,
ylab = PC2,
xlabs = xlabs,
ylabs = points
)
})
#coloured biplot
output$coloredBiplot <- renderPlot({
#file check
validate(need(data() !="", "Input a correctly formatted data file"))
#get reactive objects
d <- data()
data.prcomp <- data.prcomp()
tax <- data.t()
tax.check <- data.check()
meta <- metadata()
cn <- column()
taxoncheck <- input$taxoncheckbox
taxselect <- as.numeric(input$taxlevel)
opacity <- input$opacity_samples_pca
sample_size <- input$size_samples_pca
validate(need(input$selectcolumn, "Click 'Colouring Options' to choose metadata for colouring biplot"))
if (is.null(vals$data)) {
#reactive metadata instead
df <- as.data.frame(unlist(dimnames(data.prcomp$x)[1]))
} else {
#order the metadata
meta <- meta[order(rownames(meta)), ]
#get the input from the pop up
select <- vals$data
#get rid of blank values
s <- select[select != ""]
#filter metatable if it was filtered
meta <- meta[which(meta[[metaval$data]] %in% s),]
df <- unlist(dimnames(data.prcomp$x)[1])
df <- as.data.frame(df[which(df %in% rownames(meta))])
}
if (input$taxoncheckbox) {
validate(need(input$taxlevel, "Processing..."))
}
#if no data don't display anything
if (is.null(meta))
return(NULL)
#get rid of taxonomy column if its there
if (!isTRUE(tax.check)) {
d$taxonomy <- NULL
}
colourvector <- omicplotr.colvec(data.prcomp, meta, opacity, cn, type = input$colouringtype)
omicplotr.colouredPCA(data.prcomp, colourvector, scale = input$scale, arrows = input$arrowcheckbox, taxonomy = tax$taxonomy, show.taxonomy = taxoncheck, tax.level = taxselect, removenames = input$removesamplenames, names.cex=sample_size)
})
#histograms
output$metahist <- renderPlot({
# file check
validate(need(data() !="", ""))
#import reactive objects
cn <- column()
meta <- metadata()
data <- data.prcomp()
validate(need(input$selectcolumn, ""))
if (is.null(meta))
return(NULL)
#get sample names
df <- unlist(dimnames(data$x)[1])
#filter rownames meta based on sample names in data
meta <- meta[rownames(meta) %in% df,]
#filter meta based on colnames data so it updates
#colouring options
if (input$colouringtype == 1) {
validate(need(is.numeric(meta[[cn]]), "Nonnumeric data detected. Please click 'Nonnumeric metadata'"))
#get length of unique values
#dont laugh at my variables
un <- unique(meta[[cn]])
uniq <- un[!is.na(un)]
uni <- length(uniq)
#ramp it up
colfunc <- colorRampPalette(c("red", "blue"))
#make the colour
col <- colfunc(uni)
barplot(
table(meta[[cn]]),
space = 0,
col = col,
main = "Variable frequency",
xlab = cn
)
} else if (input$colouringtype == 2) {
validate(need(is.numeric(meta[[cn]]), "Nonnumeric data detected. Please click 'Nonnumeric metadata'"))
#calculate quartile
q <- quantile(meta[[cn]])
#get freq/value
t <- as.data.frame(table(meta[[cn]]))
#convert factors to numeric
t[, 1] <- as.numeric(as.character(t[, 1]))
#add quartile rank column
tn <-
within(t, quartile <-
as.integer(cut(
t[, 1], quantile(meta[[cn]]), include.lowest = TRUE
)))
c <- colorRampPalette(c("red", "blue"))(4)
#replace with colours
tn$quartile[tn$quartile == 1] <- c[1]
tn$quartile[tn$quartile == 2] <- c[2]
tn$quartile[tn$quartile == 3] <- c[3]
tn$quartile[tn$quartile == 4] <- c[4]
barplot(
table(meta[[cn]]),
col = tn$quartile,
space = 0,
main = "Variable frequency",
xlab = paste(cn, "by Quartiles")
)
} else if (input$colouringtype == 3) {
#get frequency table
t <- as.data.frame(table(meta[[cn]], exclude = NULL))
#make colour column
t$col <- NA
#get unique features of columns in metadata
u <- as.character(unique(meta[[cn]]))
#colour palette
colours <- c("indianred1", "steelblue3", "skyblue1", "mediumorchid",
"royalblue4", "olivedrab3", "pink", "#FFED6F", "mediumorchid3",
"ivory2", "tan1", "aquamarine3", "#C0C0C0", "mediumvioletred",
"#999933", "#666699", "#CC9933", "#006666", "#3399FF",
"#993300", "#CCCC99", "#666666", "#FFCC66", "#6699CC",
"#663366", "#9999CC", "#CCCCCC", "#669999", "#CCCC66",
"#CC6600", "#9999FF", "#0066CC", "#99CCCC", "#999999",
"#FFCC00", "#009999", "#FF9900", "#999966", "#66CCCC",
"#339966", "#CCCC33", "#EDEDED"
)
#the tricky part here is to order the colouring based on what the coloredBiplot is doing,
#so you need to order t based on the order of the unique values found in meta
t <- t[match(u, t$Var1), ]
#colour NAs black or follow color scheme
if (NA %in% t$Var1) {
y <- which(is.na(t$Var1))
t$col[y] <- "black"
for (i in (seq_len(length(t$Var1)))) {
if (is.na(t$Var1[i])) {
next
} else {
t$col[i] <- colours[i - 1]
}
}
#colour NAs black
} else {
for (i in (seq_len(length(t$Var1)))) {
t$col[i] <- colours[i]
}
}
barplot(
t$Freq,
space = 0,
col = t$col,
main = "Number of occurences",
names.arg = as.character(t$Var1),
xlab = cn,
ylab = "Frequency"
)
}
})
#generate screeplot
output$screeplot <- renderPlot({
# file check
validate(need(data() !="", ""))
data <- data.prcomp()
#if no data don't display anything
if (is.null(data.t()))
return(NULL)
#generate screeplot
screeplot(data, main = "Screeplot of Variances", xlab = "Component")
})
#removed samples
#colsums for samples
output$colsums <- renderPlot({
data <- data()
if (is.null(data)) {
return(NULL)
}
ab <- input$minreads
if (is.null(data$taxonomy)){
x <- colSums(data)
plot(x, ylab = "Counts", xlab = "Sample Number", pch = 19, col = ifelse({x > ab}, "gray0", "red"), main = "Samples removed by filtering (count sum)")
abline(h = ab, col = "red", lty = 2, lwd = 2)
legend("topright", legend = c("Remaining", "Removed"), col = c("black", "red"), pch = 19)
} else {
x <- colSums(data[,(seq_along(data) - 1)])
plot(x, ylab = "Counts", xlab = "Sample Number", pch = 19, col = ifelse({x > ab}, "gray0", "red"), main = "Samples removed by filtering")
abline(h = ab, col = "red", lty = 2, lwd = 2)
legend("topright", legend = c("Remaining", "Removed"), col = c("black", "red"), pch = 19)
}
})
output$rowsums <- renderPlot({
data <- data()
if (is.null(data)) {
return(NULL)
}
ab <- input$minsum
if (is.null(data$taxonomy)){
x <- rowSums(data)
plot(x, ylab = "Counts", xlab = "Row Number", pch = 19, col = ifelse({x > ab}, "gray0", "grey"), main = "Rows removed by filtering (count sum)")
abline(h = ab, col = "grey", lty = 2, lwd = 2)
legend("topright", legend = c("Remaining", "Removed"), col = c("black", "grey"), pch = 19)
} else {
x <- rowSums(data[,(seq_along(data) - 1)])
plot(x, ylab = "Counts", xlab = "Row Number", pch = 19, col = ifelse({x > ab}, "gray0", "grey"), main = "Rows removed by filtering")
abline(h = ab, col = "grey", lty = 2, lwd = 2)
legend("topright", legend = c("Remaining", "Removed"), col = c("black", "grey"), pch = 19)
}
})
##############################################################################
goslim_stripchart <- reactive({
# sanity checks. user needs data and EBI formatted data.
validate(
need(data() != "", "You need data. Input your data."),
need(input$ebi_format == TRUE, "This page requires a GO Slim formatted count table. Input the correctly formatted data, and check the GO Slim format box to generate a plot."),
need(!(is.null(input$varslider)), "Principal component object needs to be calculated. Please view Colored PCA Biplot before GO slim chart.")
)
# get input date
data <- data()
data.prcomp <- data.prcomp()
meta <- metadata()
opacity <- input$opacity_samples_pca
cn <- column()
# rearrange the input to format for strip chart function
data <- cbind(GO = data$GO, category = data$category, data[,1:(ncol(data) - 2)])
# if metadata is absent, don't colour by sample.
# metadata present
if (!is.null(meta)) {
validate(need(!is.null(cn), "Please select columns to colour by under the Options panel from Colored Biplot."))
colourvector <- omicplotr.colvec(data.prcomp, meta, opacity, cn, type = input$colouringtype)
} else {
# no metadata
# make colourvector for number of samples
colourvector <- colorRampPalette(c("black", "white"))(length(data) - 2)
}
createStripcharts <- function(data) {
#create dataframe with 0.5 added so there are no zeros for log function later
data.n0 <- cbind(data[,1:2], data[,3:ncol(data)] + 0.5)
#create dataframes with information needed (calculated percent reads)
molFunSet <- subset(data.n0, category == "molecular_function")
logMFSet <- cbind(molFunSet[,1:2], log(molFunSet[,3:ncol(molFunSet)]))
finalMFSet <- (logMFSet[,3:ncol(logMFSet)]) - colMeans(logMFSet[,3:ncol(logMFSet)])
#rownames(finalMFSet) <- molFunSet[,1]
bioProcSet <- subset(data.n0, category == "biological_process")
logBPSet <- cbind(bioProcSet[,1:2], log(bioProcSet[,3:ncol(bioProcSet)]))
finalBPSet <- (logBPSet[,3:ncol(logBPSet)]) - colMeans(logBPSet[,3:ncol(logBPSet)])
#rownames(finalBPSet) <- bioProcSet[,1]
cellCompSet <- subset(data.n0, category == "cellular_component")
logCCSet <- cbind(cellCompSet[,1:2], log(cellCompSet[,3:ncol(cellCompSet)]))
finalCCSet <- (logCCSet[,3:ncol(logCCSet)]) - colMeans(logCCSet[,3:ncol(logCCSet)])
#rownames(finalCCSet) <- cellCompSet[,1]
#create room for description titles
par(mar=c(5.1, 23.1, 4.1, 1.1))
par(mfrow=c(1,3))
#loop to create and colour stripcharts
for (i in 1:length(finalMFSet)) {
if (i == 1) {
stripchart(finalMFSet[,i] ~ rownames(finalMFSet), method = "jitter", jitter = 0.2, pch = 19, las = 2, cex = 0.7, cex.axis = 0.8, group.names = rownames(finalMFSet), xlab = "Centered Log of Percent Reads", col = colourvector[i], main = "Molecular Function")
}
else {
stripchart(finalMFSet[,i] ~ rownames(finalMFSet), method = "jitter", jitter = 0.2, pch = 19, las = 2, cex = 0.7, add = TRUE, col = colourvector[i])
}
}
#loop to divide description from description and ease readability
for (j in 0.5:(length(rownames(finalMFSet))+0.5)){
abline(h=j, lty=3, col="grey80")
}
#add vertical line to mark x = 0
abline(v=0, lty=3, col = "black")
#loop to create and colour stripcharts
for (i in 1:length(finalBPSet)) {
if (i == 1) {
stripchart(finalBPSet[,i] ~ rownames(finalBPSet), method = "jitter", jitter = 0.2, pch = 19, las = 2, cex = 0.7, cex.axis = 0.8, group.names = rownames(finalBPSet), xlab = "Centered Log of Percent Reads", col = colourvector[i], main = "Biological Process")
}
else {
stripchart(finalBPSet[,i] ~ rownames(finalBPSet), method = "jitter", jitter = 0.2, pch = 19, las = 2, cex = 0.7, add = TRUE, col = colourvector[i])
}
}
#loop to divide description from description and ease readability
for (j in 0.5:(length(rownames(finalBPSet))+0.5)){
abline(h=j, lty=3, col="grey80")
}
#add vertical line to mark x = 0
abline(v=0, lty=3, col = "black")
#loop to create and colour stripcharts
for (i in 1:length(finalCCSet)) {
if (i == 1) {
stripchart(finalCCSet[,i] ~ rownames(finalCCSet), method = "jitter", jitter = 0.2, pch = 19, las = 2, cex = 0.7, cex.axis = 0.8, group.names = rownames(finalCCSet), xlab = "Centered log ratio", col = colourvector[i], main = "Cellular Component")
}
else {
stripchart(finalCCSet[,i] ~ rownames(finalCCSet), method = "jitter", jitter = 0.2, pch = 19, las = 2, cex = 0.7, add = TRUE, col = colourvector[i])
}
}
#loop to divide description from description and ease readability
for (j in 0.5:(length(rownames(finalCCSet))+0.5)){
abline(h=j, lty=3, col="grey80")
}
#add vertical line to mark x = 0
abline(v=0, lty=3, col = "black")
}
if (input$returnpdf) {
pdf("goslim_stripchart.pdf", width = 25, height = nrow(data)/6.8)
createStripcharts(data)
dev.off()
}
createStripcharts(data)
})
# this dynamically sets the height to adjust to the size of the window.
output$ebi_stripchart <- renderPlot(expr = {goslim_stripchart()},
# dynamically gets height of plotting window.
height = function() {
session$clientData$output_ebi_stripchart_width
}
)
output$pdflink <- downloadHandler(
filename <- "ebi_stripchart.pdf",
content <- function(file) {
file.copy("goslim_stripchart.pdf", file)
}
)
output$pdf_note <- renderText({"Note: it may take several seconds to generate the PDF before download is available."})
##############################################################################
#this will be implemented in a later version
# #association plot
#
# output$associationplot <- renderPlot({
# d <- data()
# rhocut <- input$rhocutoff
#
# if (is.null(d)) {
# return(NULL)
# }
# associationPlot <- function(x, cutoff = rhocut) {
# # Separate out the taxonomy column from the counts
# d <- x[, 0:(dim(x)[2] - 1)]
# taxon <- x[(dim(x)[2])]
#
# # Generate ALDEx2 object so values are centered log ratio transformed,
# # then convert to propr object with a symmetric rho statistic matrix
# d.clr <- aldex.clr(d, mc.samples = 128, verbose = TRUE)
# d.sma.df <- aldex2propr(d.clr, how = "perb")
#
# # Make a reference list with pairs related by a rho statistic
# # less than the cutoff
# d.sma.lo.rho <- d.sma.df["<", cutoff]
#
# # **** propr and ALDEx stuff done ****
#
# # igraph: Convert the connections into a graphical object using propr's
# # cytescape function to first generate a table of indexed pairs and
# # proportions
# g <- graph.data.frame(cytescape(d.sma.lo.rho), directed = FALSE)
#
# # igraph: Find the clusters
# g.clust <- clusters(g)
#
# # Make a table to examine the cluster membership by hand
# g.df <-
# data.frame(
# Systematic.name = V(g)$name,
# cluster = g.clust$membership,
# cluster.size = g.clust$csize[g.clust$membership]
# )
#
# # Generate a set of clusters larger than some size
# # Minimum cluster size is 2 (obviously)
# big <- g.df[which(g.df$cluster.size >= 2), ]
# colnames(big) <- colnames(g.df)
#
# # Get genera
# genera <- c()
# for (i in 1:dim(taxon)[1]) {
# genera <- c(genera, sapply(strsplit(as.character(taxon[i,]), "[[:punct:]]"),
# "[", 6))
# }
#
# # igraph: Rename the cluster members by their genus name
# # gsub(pattern, replacement, strings, perl-syntax)
# V(g)$name <- gsub("(^[A-Za-z]{3}).+", "\\1",
# as.vector(genera[V(g)]), perl = TRUE)
#
# plot.new()
#
# # igraph:
# # vertex.size controls point and text color
# # vertex.color controls point color
# # vertex.frame controls point outline color
# plot(
# g,
# vertex.size = 5,
# vertex.color = rgb(0, 0, 0, 0.2),
# vertex.frame.color = "white"
# )
# }
# associationPlot(d)
# })
#
# output$associationtext <- renderText({
# "This association plot uses Spearman's rho to measure the strength and direction of association between two variables.
# The cutoff values ranges from -1 to 1. If greater than 1000 features are detected, input will be required on the R console."
# })
################################################################################
# Relative abundance plots
#dendrogram
output$dendrogram <- renderPlot({
validate(need(data.check() == FALSE, "These plots require a count table with the final column titled taxonomy. Ensure the input is correctly formatted."))
x <- data.t()
meta <- metadata()
abund <- input$abundcutoffbarplot
observeEvent(input$dendro_dblclick, {
brush <- input$dendro_brush
if (!is.null(brush)) {
ranges$x <- c(brush$xmin, brush$xmax)
ranges$y <- c(brush$ymin, brush$ymax)
} else {
ranges$x <- NULL
ranges$y <- NULL
}
})
#get filtered data if filtered
if (is.null(vals$data)) {
x <- x
} else {
x <- omicplotr.metadataFilter(x, meta, column = metaval$data, values = vals$data)
}
if (is.null(x$taxonomy)) {
d <- x
} else {
d <- x[, seq_along(x) - 1]
taxon <- x[(dim(x)[2])]
}
validate(need(x$taxonomy, "No taxonomy column detected"))
# Get genera
genera <- c()
for(i in (seq_len(nrow(taxon)))) {
genera <- c(genera, vapply(strsplit(as.character(taxon[i, ]), "[[:punct:]]"),
"[", 6, FUN.VALUE=character(1)))
}
# sum counts by name
d.agg <- aggregate(d, by=list(genera), FUN=sum)
tax.agg <- d.agg$Group.1
d.agg$Group.1 <- NULL
# convert to abundances
d.prop <- apply(d.agg, 2, function(x){x/sum(x)})
#filters by abundance (slider bar)
d.abund <- d.agg[apply(d.prop, 1, max) > abund,]
tax.abund.u <- tax.agg[apply(d.prop, 1, max) > abund]
if (any(d.abund == 0)) {
d.abund <- t(zCompositions::cmultRepl(t(d.abund), label = 0, method = "CZM"))
} else {
d.abund <- d.abund
}
# get proportions of the filtered data for plotting below
# in log-ratio speak, you are re-closing your dataset
d.P.u <- apply(d.abund, 2, function(x){x/sum(x)})
# order by OTU abundances
new.order <- rownames(d.P.u)[order(apply(d.P.u, 1, sum), decreasing=TRUE)]
tax.abund <- tax.abund.u[order(apply(d.P.u, 1, sum), decreasing=TRUE)]
d.P <- d.P.u[new.order, ]
d.clr <- apply(d.P, 2, function(x){log2(x) - mean(log2(x))})
#distance matrix
inp <- as.numeric(input$dismethod)
method.m <- c("euclidean", "maximum", "manhattan")
method.mchoice <- method.m[inp]
dist.d.clr <- dist(t(d.clr), method=method.mchoice)
#get clustering method for dendrogram
num <- as.numeric(input$clustermethod)
method <- c("complete", "single", "ward.D2")
method.choice <- method[num]
clust.d <- hclust(dist.d.clr, method=method.choice)
plot.new()
par(fig=c(0, 1, 0, 1), new=TRUE)
plot(as.dendrogram(clust.d), main=NULL, cex=0.8, xlab="", xlim = ranges$x, ylim= ranges$y, xpd = TRUE)
})
output$dendrotext <- renderText({
"Drag mouse and double click to zoom in. \nDouble click again to zoom out"
})
#taoxnomic distribution
output$barplot <- renderPlot({
#no need for message to be repeated, but still squashes error.
validate(need(data.check() == FALSE, ""))
x <- data.t()
meta <- metadata()
abund <- input$abundcutoffbarplot
observeEvent(input$bp_dblclick, {
bp_brush <- input$bp_brush
if (!is.null(bp_brush)) {
bp_ranges$x <- c(bp_brush$xmin, bp_brush$xmax)
bp_ranges$y <- c(bp_brush$ymin, bp_brush$ymax)
} else {
bp_ranges$x <- NULL
bp_ranges$y <- NULL
}
})
#get filtered data if filtered
if (is.null(vals$data)) {
x <- x
} else {
x <- omicplotr.metadataFilter(x, meta, column = metaval$data, values = vals$data)
}
if (is.null(x$taxonomy)) {
d <- x
} else {
d <- x[, 0:(dim(x)[2] - 1)]
taxon <- x[(dim(x)[2])]
}
validate(need(x$taxonomy, ""))
# Get genera
genera <- c()
for(i in (seq_len(nrow(taxon)))) {
genera <- c(genera, vapply(strsplit(as.character(taxon[i, ]), "[[:punct:]]"),
"[", 6, FUN.VALUE=character(1)))
}
# sum counts by name
d.agg <- aggregate(d, by=list(genera), FUN=sum)
tax.agg <- d.agg$Group.1
d.agg$Group.1 <- NULL
# convert to abundances
d.prop <- apply(d.agg, 2, function(x){x/sum(x)})
d.abund <- d.agg[apply(d.prop, 1, max) > abund,]
tax.abund.u <- tax.agg[apply(d.prop, 1, max) > abund]
if (any(d.abund == 0)) {
d.abund <- t(zCompositions::cmultRepl(t(d.abund), label = 0, method = "CZM"))
} else {
d.abund <- d.abund
}
# get proportions of the filtered data for plotting below
# in log-ratio speak, you are re-closing your dataset
d.P.u <- apply(d.abund, 2, function(x){x/sum(x)})
# order by OTU abundances
new.order <- rownames(d.P.u)[order(apply(d.P.u, 1, sum), decreasing=TRUE)]
tax.abund <- tax.abund.u[order(apply(d.P.u, 1, sum), decreasing=TRUE)]
d.P <- d.P.u[new.order, ]
d.clr <- apply(d.P, 2, function(x){log2(x) - mean(log2(x))})
#distance matrix
inp <- as.numeric(input$dismethod)
method.m <- c("euclidean", "maximum", "manhattan")
method.mchoice <- method.m[inp]
dist.d.clr <- dist(t(d.clr), method=method.mchoice)
#clustering
num <- as.numeric(input$clustermethod)
method <- c("complete", "single", "ward.D2")
method.choice <- method[num]
clust.d <- hclust(dist.d.clr, method=method.choice)
# standard colour scheme (Jean Macklaim)
colours <- c("steelblue3", "skyblue1", "indianred", "mediumpurple1",
"olivedrab3", "pink", "#FFED6F", "mediumorchid3",
"ivory2", "tan1", "aquamarine3", "#C0C0C0", "royalblue4",
"mediumvioletred", "#999933", "#666699", "#CC9933", "#006666",
"#3399FF", "#993300", "#CCCC99", "#666666", "#FFCC66",
"#6699CC", "#663366", "#9999CC", "#CCCCCC", "#669999",
"#CCCC66", "#CC6600", "#9999FF", "#0066CC", "#99CCCC",
"#999999", "#FFCC00", "#009999", "#FF9900", "#999966",
"#66CCCC", "#339966", "#CCCC33", "#EDEDED")
plot.new()
par(fig=c(0,1,0,1), new = TRUE)
par(fig=c(0,0.80,0, 1), new = TRUE)
barplot(d.P[,clust.d$order], names.arg = clust.d$labels, space=0, xlim = bp_ranges$x, ylim= bp_ranges$y, col=colours, las=2, axisnames=TRUE, border = NA, xpd = TRUE)
par(fig=c(0.8,1, 0, 1), new=TRUE)
par(xpd = TRUE)
leg.col <- rev(colours[seq_len(nrow(d.P))])
legend(x="center", legend=rev(tax.abund), col=leg.col, lwd=5, cex=0.8,
border=NULL)
})
################################################################################
# effect plots
#find points by string and colour them
point.colour <- eventReactive(input$update_points, {
effect <- effect_input()
point.colour <- input$point.colour
row.num <- grep(point.colour, rownames(effect))
points(effect$diff.win[row.num], effect$diff.btw[row.num], pch=19, col=rgb(1,0,0,0.8), cex=1)
})
#find points by string and colour them
BA.point.colour <- eventReactive(input$update_points, {
effect <- effect_input()
point.colour <- input$point.colour
row.num <- grep(point.colour, rownames(effect))
points(effect$rab.all[row.num], effect$diff.btw[row.num], pch=19, col=rgb(1,0,0,0.8), cex=1)
})
#effect plots after calculating
output$effectMW <- renderPlot({
# ensure data is inputted
validate(need(data() != "", ""))
x.all <- aldex.obj()
if (input$effectplot_ab) {
if (is.null(x.all)){
return(NULL)
} else {
aldex.plot(x.all, type="MW", test="welch", all.cex = 1.5, rare.cex = 1.5, called.cex = 1.5, xlab = "Dispersion", ylab = "Difference")
title(main = "Effect Plot")
}
}
})
output$effectMA <- renderPlot({
# ensure data is inputted
validate(need(data() != "", ""))
x.all <- aldex.obj()
if (input$effectplot_ab) {
if (is.null(x.all)){
return(NULL)
} else {
aldex.plot(x.all, type="MA", test="welch", all.cex = 1.5, rare.cex = 1.5, called.cex = 1.5, xlab = "CLR abundance", ylab = "Difference between")
title(main = "Bland-Altman Plot")
}
}
})
#effect plots for inputted aldex table
output$table_effect <- renderPlot({
# ensure data is inputted
validate(need(data() != "", ""))
effect <- effect_input()
point.colour <- input$point.colour
if (input$effectplot_ab2) {
if (is.null(effect)){
return(NULL)
} else {
plot(effect$diff.win, effect$diff.btw, pch = 19, col=rgb(0,0,0,0.1), cex=0.4, xlab = "Difference within", ylab = "Difference between")
title(main = "Effect Plot")
}
if (input$update_points == 0){
return()
} else {
point.colour()
}
}
})
#effect plots for inputted aldex table
output$table_bland <- renderPlot({
# ensure data is inputted
validate(need(data() != "", ""))
effect <- effect_input()
point.colour <- input$point.colour
if (input$effectplot_ab2) {
if (is.null(effect)){
return(NULL)
} else {
plot(effect$rab.all, effect$diff.btw, pch = 19, col=rgb(0,0,0,0.1), cex=0.4, xlab = "CLR abundance", ylab = "Difference within")
title(main = "Bland-Altman Plot")
}
if (input$update_points == 0){
return()
} else {
BA.point.colour()
}
}
})
#display information of hovered point
output$ma_hovertext <- renderUI({
x.all <- aldex.obj()
row <- nearPoints(x.all, input$ma_hover, xvar = "rab.all", yvar = "diff.btw")
x <- paste("Feature Id: ", rownames(row))
y <- paste("Median Log2 relative abundance: ", round(row$rab.all, digits =3))
z <- paste("Between condition difference size: ", round(row$diff.btw, digits = 3))
e <- paste("Effect size: ", round(row$effect, digits = 3))
a <- ""
HTML(paste(x, y, z, e, a, sep = "<br/>"))
})
#display information of hovered point
output$mw_hovertext <- renderUI({
# ensure data is inputted
validate(need(data() != "", ""))
x.all <- aldex.obj()
a <- d.clr()
row <- nearPoints(x.all, input$mw_hover, xvar = "diff.win", yvar = "diff.btw", maxpoints = 1)
if (is.null(input$mw_hover)) {
HTML("Hover over MW plot with mouse")
} else {
p.v <- round(row$we.eBH, digits = 4)
ps <- format(p.v, scientific=TRUE)
x <- paste("Feature Id: ", rownames(row))
y <- paste("Within condition difference size: ", round(row$diff.win, digits =3))
z <- paste("Between condition difference size: ", round(row$diff.btw, digits = 3))
e <- paste("Effect size: ", round(row$effect, digits = 3))
p <- paste("Benjami Hochberg corrected p-value:", ps)
a <- ""
HTML(paste(x, y, z, e, p, a, sep = "<br/>"))
}
})
#strip chart of expected CLR values for each sample per condition of hovered
# point
output$stripchart <- renderPlot({
# ensure data is inputted
validate(need(data() != "", "You need data. Input your data."))
x.all <- aldex.obj()
d.clr <- d.clr()
if (!is.null(input$mw_hover)){
feature <- nearPoints(x.all, input$mw_hover, xvar = "diff.win", yvar = "diff.btw", maxpoints = 1)
# only plot if one feature select
if (dim(feature)[1] == 1) {
aldex.plotFeature(d.clr, rownames(feature), pooledOnly=TRUE, densityOnly=TRUE)
}
} else {
#HTML("Hover over MW plot with mouse")
validate(need(input$mw_hover != "", "Hover over a point on the graph."))
}
})
#displays row name for plots when inputting ALDEx2 table
output$featurename<- renderUI({
x.all <- effect_input()
row <- nearPoints(x.all, input$mw_hover2, xvar = "diff.win", yvar = "diff.btw")
ba.row <- nearPoints(x.all, input$ma_hover, xvar = "rab.all", yvar = "diff.btw")
feature <- rownames(row)
feature2 <- rownames(ba.row)
number <- c(rownames(x.all[feature,]), rownames(x.all[feature2,]))
return(number)
})
output$effectwarning <- renderText({
"See the GitHub Wiki for more information on how to select conditions"
})
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.