#' alpha UI Function
#'
#' @description A shiny Module.
#'
#' @param id,input,output,session Internal parameters for {shiny}.
#'
#' @noRd
#'
#' @importFrom shiny NS tagList
#' @import shinyjs
#' @import tibble
mod_alpha_ui <- function(id){
ns <- NS(id)
tagList(
fluidPage(
inlineCSS("
.nav li a.disabled {
background-color: #aaa !important;
color: #333 !important;
cursor: not-allowed !important;
border-color: #aaa !important;
}"),
# wellPanel(width = 12, h3('check'), br(), verbatimTextOutput(ns('check'))),
navlistPanel(
'',
id = 'alpha_menu',
well=FALSE,
widths=c(3,9),
# info tab body-----------------------------------------------------
tabPanel(
'Module Info',
value = 'info_tab_alpha',
icon = icon('info-circle'),
fluidRow(
br(), br(),
column(
width = 12,
h1("\u03B1-Diversity"),
div(
p("This analysis module evalutes the microbiome on the basis of u03B1-diversity. u03B1-Diversity is measured on a per-sample basis and is quantified using an u03B1-diversity index, such as Shannon's D. More detail is provided of different u03B1-diversity indeces in the 'u03B1-Diversity Analysis' tab."),
p("Module overview:"),
tags$ul(
tags$li(tags$b("Aggregate Features:"), "Select the taxonomic level at which you want to examine the microbiome profiles"),
tags$li(tags$b("Filter Features:"), "Filter aggregated features based on feature abundance and prevalence"),
tags$li(tags$b("\u03B1-Diversity Analysis:"), "Calculates \u03B1-diversity and performs group-wise statistical testing where applicable")
)
)
)
)
), # end tabPanel
# aggregate tab body------------------------------------------------
tabPanel(
'Aggregate Features',
value = 'agg_alpha_tab',
fluidRow(
br(),br(),
column(
width = 12,
br(),br(),
mod_aggregate_ui(ns("aggregate_ui_1"))
)
)
), # end tabItem
# filter tab body---------------------------------------------------
tabPanel(
'Filter Features',
value = "filter_asv_alpha",
fluidRow(
br(),br(),
column(
width = 12,
div(id=ns('filtfeat_mod_div'),
mod_filterfeat_ui(ns("filterfeat_ui_1"))
)
)
)
), # end tabPanel
# alpha tab body----------------------------------------------------
tabPanel(
'\u03B1-Diversity Analysis',
value = 'alpha_tab',
fluidRow(
br(),br(),
h1("\u03B1-Diversity"),
p("Alpha diversity assesses the diversity of a community (within one sample). Species richness is the number of unique species. Species evenness is a measure of the consistency of species abundances (uneven data sets have community members that dominate in abundance). Entropy measures such as Shannon's index (H) and Simpson index are measures of uncertainty in the species identity of a sample (", a("Jost 2006", href="https://doi.org/10.1111/j.2006.0030-1299.14714.x"), ")."),
p("Diversity measures, such as Shannon's Diversity and Inverse Simpson's Index, takes into account of the abundance of species in the community. In fact, when all species in a community are equally common, entropy and diversity measures are equivalent. Entropy indices can be converted to diversity by mathematical transformation."),
p("Diversity indecies are calculated with", a(code("vegan::diversity"), href="https://cran.r-project.org/web/packages/vegan/vignettes/diversity-vegan.pdf"), "Shannon's D index is calculated as ", code("exp(Shannon's Index)"), "Richness is calculated with", a(code("vegan::specnum"), href="https://cran.r-project.org/web/packages/vegan/vignettes/diversity-vegan.pdf"), ", and evenness is calculated as ", code("Shannon's Index/log(Richness)"), ".")
),
fluidRow(
DT::dataTableOutput(ns('alpha_table')) %>%
shinycssloaders::withSpinner()
), br(),
fluidRow(
DT::dataTableOutput(ns('alpha_test')) %>%
shinycssloaders::withSpinner()
), br(),
fluidRow(
column(
width = 3, br(), br(),
wellPanel(
uiOutput(ns('alpha_metric_ui')),
uiOutput(ns('alpha_grp_ui'))
)
),
column(
width = 9,
column(
width = 1, style = 'padding:0px;',
mod_download_ui(ns('download_alpha')),
),
column(
width = 11, style = 'padding:0px;',
shinyjqui::jqui_resizable(
plotlyOutput(ns('alpha_plot'), width = '100%',
height= 'auto') %>%
shinycssloaders::withSpinner()
)
)
)
) # end fluidRow
), # end tabPanel
# report------------------------------------------------------------
tabPanel(
'Report',
value = "alpha_report_tab",
fluidRow(
br(), br(),
column(
width = 12,
mod_report_ui(ns("alpha_report_ui"))
)
)
) # end tabPanel
) # end navlistPanel
) # end fluidPage
) # end taglist
}
#' alpha Server Function
#'
#' @noRd
mod_alpha_server <- function(input, output, session, improxy){
ns <- session$ns
# output$check <- renderPrint({
# })
# initiate a reactive to track/permit progress through analysis module--------
progress <- reactiveValues(complete_agg = 0, complete_featfilt = 0)
observeEvent(input[['aggregate_ui_1-agg_calculate']], {
progress$complete_agg <- 1
progress$complete_featfilt <- 0
})
observeEvent(input[['aggregate_ui_1-agg_clear']], {
progress$complete_agg <- 0
progress$complete_featfilt <- 0
})
observeEvent(input[['filterfeat_ui_1-submit_asv']], {
progress$complete_featfilt <- 1
})
observeEvent(input[['filterfeat_ui_1-clear_asv']], {
progress$complete_featfilt <- 0
})
observe({
if(progress$complete_featfilt == 0) {
reset('filtfeat_mod_div')
hide('filterfeat_ui_1-prev_filter_div')
hide('filterfeat_ui_1-preview_asv_div')
}
})
# enable tabs sequentially----------------------------------------------------
observe({
toggleState(selector = "#alpha_menu li a[data-value=filter_asv_alpha]",
condition = progress$complete_agg == 1)
})
observe({
toggleState(selector = "#alpha_menu li a[data-value=alpha_tab]",
condition = progress$complete_featfilt == 1)
})
observe({
toggleState(selector = "#alpha_menu li a[data-value=alpha_report_tab]",
condition = progress$complete_featfilt == 1)
})
# initiate value to pass into submodules--------------------------------------
bridge <- reactiveValues()
observe({
bridge$qualfilt_db <- improxy$work_db
})
# initiate list to pass onto report submodule
for_report <- reactiveValues()
# store values to pass to report
observe({
for_report$params <- list(
# sample filter
met1 = improxy$work_db$met,
sample_select_prompt = improxy$work_db$sample_select_prompt,
sample_select = improxy$work_db$sample_select
)
})
# aggregate features----------------------------------------------------------
agg_output <- callModule(mod_aggregate_server, "aggregate_ui_1", bridge,
default_tax = 'featureID')
# store data in reactiveValues to pass onto submodules
observe({
if(!is.null(agg_output$output)) {
tax_entry <- dplyr::select(agg_output$output$aggregated_tax, -n_collapse)
# add aggregate features to bridge to be passed to submodules
bridge$work_db <- list(
met = improxy$work_db$met,
asv = agg_output$output$aggregated_count,
tax = tax_entry
)
} else {
# agg_output starts out as NULL initially. else statement stops that from causing app to crash
bridge$work_db <- 'tempstring'
}
})
observe({
# add aggregate features to report params
for_report$params$aggregate_by <- input[['aggregate_ui_1-aggregate_by']]
for_report$params$aggregated_count <- agg_output$output$aggregated_count
for_report$params$aggregated_tax <- agg_output$output$aggregated_tax
})
# filter features-------------------------------------------------------------
# submodule returns list of filtered met, asv and tax tables
filter_output <- callModule(mod_filterfeat_server, "filterfeat_ui_1", bridge)
# add filtered data to bridge
observe({
bridge$filtered <- filter_output$filtered
})
# update report params
observe({
#feature filter
for_report$params$asv_select_prompt <-
input[['filterfeat_ui_1-asv_select_prompt']]
for_report$params$asv_filter_options <-
input[['filterfeat_ui_1-asv_filter_options']]
for_report$params$cutoff_method <- input[['filterfeat_ui_1-cutoff_method']]
for_report$params$asv_cutoff <- input[['filterfeat_ui_1-asv_cutoff']]
for_report$params$prevalence <- input[['filterfeat_ui_1-prevalence']]
for_report$params$asv_cutoff_msg <- filter_output$params$asv_cutoff_msg
for_report$params$asv_remove <- filter_output$params$asv_remove
for_report$params$prev_agg_plot <- filter_output$params$prev_agg_plot
for_report$params$prev_read_plot <- filter_output$params$prev_read_plot
for_report$params$empty_sample <- filter_output$params$empty_sample
for_report$params$empty_asv <- filter_output$params$empty_asv
for_report$params$met2 <- filter_output$filtered$met
for_report$params$tax2 <- filter_output$filtered$tax
})
# render controls - alpha diversity-------------------------------------------
output$alpha_metric_ui <- renderUI({
checkboxGroupInput(ns('alpha_metric'), 'Diversity Index',
choices=c("Shannon's Index (H)" = 'shannon',
"Shannon's D Index (D'H)" = 'shannon_d',
"Simpson Index" = 'simpson',
"Inverse Simpson Index" = 'invsimpson'),
selected = 'shannon_d')
})
output$alpha_grp_ui <- renderUI({
selectInput(ns('alpha_grp'), "Compare Sample Groups",
choices = colnames(bridge$filtered$met), selected = 'sampleID')
})
# calculate alpha diversity---------------------------------------------------
alpha_result <- reactive({
req(input$alpha_grp)
alpha_data <- bridge$filtered$asv %>%
column_to_rownames('featureID')
shannon <- vegan::diversity(alpha_data,index = 'shannon',
base = 2, MARGIN = 2)
shannon_d <- exp(shannon)
richness <- vegan::specnumber(alpha_data, MARGIN = 2)
evenness <- shannon / log(richness)
invsimpson <- vegan::diversity(alpha_data,index = 'invsimpson',
base = 2, MARGIN = 2)
simpson <- vegan::diversity(alpha_data, index = 'simpson',
base = 2, MARGIN = 2)
out <- data.frame(sampleID = names(shannon),
shannon = shannon,
simpson = simpson,
shannon_d = shannon_d,
richness = richness,
evenness = evenness,
invsimpson = invsimpson)
out
})
# determine valid stat test
grp_tally <- reactive({
req(input$alpha_grp)
out <- table(bridge$filtered$met[,input$alpha_grp])
if(length(out) == 0) out <- 0
out
})
stat_test <- reactive({
if(length(grp_tally()) == 2) 'wilcox.test'
else 'kruskal.test'
})
alpha_stat <- eventReactive(input$alpha_grp, {
validate(
need(max(grp_tally()) != 1, "Only one observation per group. Group-wise comparisons not performed"),
need(length(grp_tally()) > 1, "All observations are in the same group. Group-wise comparisons not performed")
)
out <- alpha_result() %>%
gather('alpha_metric', 'alpha_value', -sampleID) %>%
inner_join(bridge$filtered$met %>%
gather('meta_variable','grouping', -sampleID),
'sampleID') %>%
filter(meta_variable == input$alpha_grp)
out <- ggpubr::compare_means(formula = alpha_value~grouping, data = out,
group.by = c('alpha_metric'),
method = stat_test(), p.adjust.method = 'BH')
out
})
# show tables
output$alpha_table <- DT::renderDataTable(server = FALSE, {
out <- bridge$filtered$met %>%
arrange(sampleID) %>%
inner_join(alpha_result(), 'sampleID')
DT::datatable(out, extensions = 'Buttons',
rownames = FALSE,
options = list(scrollX = TRUE, dom = 'Blfrtip',
buttons = c('copy','csv'))) %>%
DT::formatRound(column = colnames(alpha_result())[2:ncol(alpha_result())], digits = 3)
})
validation_msg <- reactive({
if(max(grp_tally()) == 1) {
"Only one observation per group. Group-wise comparisons not performed"
} else if(length(grp_tally()) == 1) {
"All observations are in the same group. Group-wise comparisons not performed"
} else {
'valid'
}
})
output$alpha_test <- DT::renderDataTable(server = FALSE, {
validate(
need(max(grp_tally()) != 1, "Only one observation per group. Group-wise comparisons not performed"),
need(length(grp_tally()) > 1, "All observations are in the same group. Group-wise comparisons not performed")
)
DT::datatable(alpha_stat() %>%
select(-.y., -p.format, ), extensions = 'Buttons',
rownames = FALSE,
options = list(scrollX = TRUE, dom = 'Blfrtip',
buttons = c('copy','csv')))
})
# plot alpha diversity
pdata_alpha <- reactive({
req(input$alpha_grp, input$alpha_metric)
# set xorder based on shannon_d
xorder <- bridge$filtered$met %>%
mutate_all(as.character) %>%
arrange(sampleID) %>%
inner_join(alpha_result(), 'sampleID') %>%
group_by(.data[[input$alpha_grp]]) %>%
mutate(alpha_avg = mean(shannon_d)) %>%
distinct(.data[[input$alpha_grp]], alpha_avg) %>%
ungroup() %>%
mutate(x = forcats::fct_reorder(.data[[input$alpha_grp]],
desc(alpha_avg)))
out <- alpha_result() %>%
gather('alpha_metric', 'alpha_value', -sampleID) %>%
filter(alpha_metric %in% c('evenness','richness',input$alpha_metric)) %>%
inner_join(bridge$filtered$met %>% mutate_all(as.character), 'sampleID') %>%
group_by(alpha_metric, .data[[input$alpha_grp]]) %>%
mutate(alpha_avg = mean(alpha_value)) %>%
distinct(.data[[input$alpha_grp]], alpha_metric, alpha_value, alpha_avg) %>%
ungroup()
if(validation_msg() == 'valid') {
# re-calculate comparison statistic
compare_stat <- alpha_result() %>%
gather('alpha_metric', 'alpha_value', -sampleID) %>%
inner_join(bridge$filtered$met %>%
gather('meta_variable','grouping', -sampleID),
'sampleID') %>%
filter(meta_variable == input$alpha_grp)
compare_stat <- ggpubr::compare_means(formula = alpha_value~grouping,
data = compare_stat,
group.by = c('alpha_metric'),
method = stat_test(),
p.adjust.method = 'BH')
out <- out %>%
left_join(compare_stat %>% select(alpha_metric, p, p.adj),
'alpha_metric') %>%
mutate(panel = sprintf("%s\np=%0.3f, p.adj=%0.3f",
alpha_metric, p, p.adj))
}
out
})
p_alpha <- reactive({
req(input$alpha_grp)
p <- ggplot(pdata_alpha(), aes(x = .data[[input$alpha_grp]],
y = alpha_value,
group = .data[[input$alpha_grp]]))
if(validation_msg() == 'valid') {
p <- p + facet_wrap(~panel, scales = 'free')
} else {
p <- p + facet_wrap(~alpha_metric, scales = 'free')
}
if(min(grp_tally()) > 5) {
p <- p +
geom_boxplot(outlier.fill=NA) +
geom_point(position = position_jitter(width = 0.25, seed = 1),
alpha = 0.6)
}
else {
p <- p +
geom_point(alpha = 0.6)
}
p <- p +
theme_bw() +
xlab(input$alpha_grp) +
theme(axis.text.x = element_text(angle = 90),
axis.title.y = element_blank())
p
})
output$alpha_plot <- renderPlotly({
out <- plotly_build(p_alpha())
out$x$data <- lapply(out$x$data, FUN = function(x) {
x$marker = list(color = "rgba(0,0,0,1)",
outliercolor = "rgba(0,0,0,0)",
line = list(outliercolor='rgba(0,0,0,0)'))
return(x)
})
out
})
# download data
for_download <- reactiveValues()
observe({
req(input$alpha_grp)
for_download$figure <- p_alpha()
for_download$fig_data <- pdata_alpha()
})
callModule(mod_download_server, "download_alpha", bridge = for_download, 'alpha')
# initiate list to pass onto report submodule
observe({
for_report$params$alpha_result <- alpha_result()
for_report$params$validation_msg <- validation_msg()
for_report$params$p_alpha <- p_alpha()
})
observe({
req(validation_msg())
if(validation_msg() == 'valid') {
for_report$params[['alpha_stat']] <- alpha_stat()
}
})
# build report
callModule(mod_report_server, "alpha_report_ui", bridge = for_report,
template = "alpha_report",
file_name = "alpha_report")
}
## To be copied in the UI
# mod_alpha_ui("alpha_ui_1")
## To be copied in the server
# callModule(mod_alpha_server, "alpha_ui_1")
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.