################################################################################
################################### Values #####################################
################################################################################
#' @name fR_boxplotUI
#'
#' @title Fluid row UI for tab panel 'Boxplot/Violin plot'
#'
#' @description
#' The module defines the UI for the tab panel 'Boxplot/Violin plot'.
#'
#' @details
#' \code{fR_boxplotUI} returns the HTML code for the tab-pane
#' 'Boxplot/Violin plot'. Internal function for \code{shinyQC}.
#'
#' @param id \code{character}
#' @param name \code{character}
#' @param collapsed \code{logical}
#'
#' @return
#' \code{shiny.tag} with HTML content
#'
#' @author Thomas Naake
#'
#' @examples
#' fR_boxplotUI("test", "name")
#'
#' @importFrom shiny NS fluidRow downloadButton plotOutput
#' @importFrom shinydashboard box
#'
#' @noRd
fR_boxplotUI <- function(id, name, collapsed) {
ns <- shiny::NS(id)
shiny::fluidRow(
shinydashboard::box(title = name, width = 12, collapsible = TRUE,
collapsed = collapsed,
shiny::plotOutput(outputId = ns("boxplot")),
shiny::downloadButton(outputId = ns("downloadPlot"), ""))
)
}
#' @name tP_boxplotUI
#'
#' @title Tab panel UI for tab panel 'Boxplot/Violin plot'
#'
#' @description
#' The function defines the UI for the tab panel 'Boxplot/Violin plot'. It
#' serves as a wrapper for the function \code{fR_boxplotUI}.
#'
#' @details
#' \code{tP_boxplotUI} returns the HTML code for the tab-pane
#' 'Boxplot/Violin plot'. Internal function for \code{shinyQC}.
#'
#' @param id \code{character}
#'
#' @return
#' \code{shiny.tag} with HTML content
#'
#' @author Thomas Naake
#'
#' @examples
#' tP_boxplotUI("test")
#'
#' @importFrom shiny NS tabPanel fluidRow column conditionalPanel
#' @importFrom shiny selectInput radioButtons HTML
#' @importFrom shinyhelper helper
#' @importFrom plotly plotlyOutput
#'
#' @noRd
tP_boxplotUI <- function(id) {
ns <- shiny::NS(id)
shiny::tabPanel(title = "Boxplot/Violin plot",
shiny::fluidRow(
shiny::column(6,
shiny::radioButtons(inputId = "boxLog",
label = shiny::HTML("Display log values? <br>
(only for 'raw', 'normalized' and 'batch corrected')"),
choices = list("no log", "log"),
selected = "no log")),
shiny::column(2,
shiny::radioButtons(inputId = "violinPlot",
label = "Type of display",
choices = list("boxplot", "violin"),
selected = "boxplot")),
shiny::column(3,
shiny::selectInput(inputId = ns("orderCategory"),
label = "Select variable to order samples",
choices = "name")),
shiny::column(1,
shiny::br() |>
shinyhelper::helper(content = "tabPanel_boxplot"))
),
fR_boxplotUI("boxRaw", "raw", collapsed = FALSE),
fR_boxplotUI("boxNorm", "normalized", collapsed = TRUE),
fR_boxplotUI("boxBatch", "batch corrected", collapsed = TRUE),
fR_boxplotUI("boxTransf", "transformed", collapsed = TRUE),
shiny::conditionalPanel("output.missingVals == 'TRUE'",
fR_boxplotUI("boxImp", "imputed", collapsed = TRUE))
)
}
#' @name boxPlotUIServer
#'
#' @title Module for server expressions for the UI of tab panel
#' 'Boxplot/Violin plot'
#'
#' @description
#' The module defines the server expressions for parts of the UI for the tab
#' panel 'Boxplot/Violin plot'. It will load different helper files depending
#' on \code{missingValue}
#'
#' @details
#' Internal function for \code{shinyQC}.
#'
#' @param id \code{character}
#' @param missingValue \code{logical} (will load different helper files)
#'
#' @return
#' \code{shiny.render.function} expression
#'
#' @importFrom shiny moduleServer observe updateSelectInput
#' @importFrom shinyhelper helper
#' @importFrom SummarizedExperiment SummarizedExperiment
#'
#' @author Thomas Naake
#'
#' @noRd
boxPlotUIServer <- function(id, se) {
shiny::moduleServer(
id,
function(input, output, session) {
shiny::observe({
shiny::updateSelectInput(session = session,
inputId = "orderCategory", choices = colnames(se@colData))
})
}
)
}
#' @name boxPlotServer
#'
#' @title Module for server expressions of tab panel 'Boxplot/Violin plot'
#'
#' @description
#' The module defines the server expressions for the tab panel
#' 'Boxplot/Violin plot'.
#'
#' @details
#' Internal function for \code{shinyQC}.
#'
#' @param id \code{character}
#' @param se \code{SummarizedExperiment}
#' @param boxLog \code{reactive} expression and \code{logical}
#' @param violin \code{reactive} expression and \code{character}
#' @param type \code{character}
#'
#' @return
#' \code{shiny.render.function} expression
#'
#' @author Thomas Naake
#'
#' @importFrom shiny moduleServer reactive renderPlot downloadHandler req
#' @importFrom ggplot2 ggsave
#' @importFrom plotly plotlyOutput
#'
#' @noRd
boxPlotServer <- function(id, se, orderCategory, boxLog, violin, type) {
shiny::moduleServer(
id,
function(input, output, session) {
logValues <- shiny::reactive({
if (boxLog() == "log") {
TRUE
} else {
FALSE
}
})
vP <- shiny::reactive({
if (violin() == "violin") {
TRUE
} else {
FALSE
}
})
## create the actual plot
p_boxplot <- shiny::reactive({
createBoxplot(se = se(), orderCategory = orderCategory(),
title = "", log = logValues(),
violin = vP())
})
output$boxplot <- shiny::renderPlot({
p_boxplot()
})
output$downloadPlot <- shiny::downloadHandler(
filename = function() {
paste("Boxplot_violinplot_", type, ".pdf", sep = "")
},
content = function(file) {
ggplot2::ggsave(file, p_boxplot(), device = "pdf",
limitsize = FALSE)
}
)
}
)
}
################################################################################
################################# drift/trend ##################################
################################################################################
#' @name tP_driftUI
#'
#' @title Tab panel UI for tab panel 'Trend/drift'
#'
#' @description
#' The module defines the UI for the tab panel 'Trend/drift'.
#'
#' @details
#' \code{tP_driftUI} returns the HTML code for the tab-pane
#' 'Trend/drift'. Internal function for \code{shinyQC}.
#'
#' @param id \code{character}
#'
#' @return
#' \code{shiny.tag} with HTML content
#'
#' @author Thomas Naake
#'
#' @examples
#' tP_driftUI("test", se)
#'
#' @importFrom shiny NS tabPanel fluidRow downloadButton column
#' @importFrom shiny selectInput
#' @importFrom shinydashboard box
#' @importFrom shinyhelper helper
#' @importFrom plotly plotlyOutput
#'
#' @noRd
tP_driftUI <- function(id) {
ns <- shiny::NS(id)
shiny::tabPanel(title = "Trend/drift",
shiny::fluidRow(
shiny::column(width = 12,
plotly::plotlyOutput(outputId = ns("plotDrift"),
width = "95%") |>
shinyhelper::helper(content = "tabPanel_drift"),
shiny::downloadButton(outputId = ns("downloadPlot"), "")
),
shinydashboard::box(width = 12, collapsible = TRUE,
collapsed = FALSE, title = "Parameters",
shiny::column(6,
shiny::selectInput(
inputId = ns("category"),
label = "Select variable", choices = "name"),
shiny::selectInput(
inputId = ns("levelSel"),
label = "Select level to highlight",
choices = "all"),
shiny::selectInput(
inputId = ns("orderCategory"),
label = "Select variable to order samples",
choices = "name")),
shiny::column(6,
shiny::selectInput(inputId = ns("aggregation"),
label = "Select aggregation",
choices = list("sum", "median"), selected = "sum"),
shiny::selectInput(inputId = ns("method"),
label = "Select smoothing method",
choices = list("LOESS" = "loess", "linear model" = "lm"),
selected = "loess"),
shiny::selectInput(inputId = ns("data"),
label = "Select data input", choices = "raw"))
),
)
)
}
#' @name driftServer
#'
#' @title Module for server expressions of tab panel 'Trend/drift'
#'
#' @description
#' The module defines the server expressions for the tab panel
#' 'Trend/drift'.
#'
#' @details
#' Internal function for \code{shinyQC}.
#'
#' @param id \code{character}
#' @param se \code{SummarizedExperiment} and \code{reactive} value
#' @param se_n \code{SummarizedExperiment} and \code{reactive} value
#' @param se_b \code{SummarizedExperiment} and \code{reactive} value
#' @param se_t \code{SummarizedExperiment} and \code{reactive} value
#' @param se_i \code{SummarizedExperiment} and \code{reactive} value
#' @param missingValue \code{logical} (if \code{FALSE} do not show option for imputed)
#'
#' @return
#' \code{shiny.render.function} expression
#'
#' @author Thomas Naake
#'
#' @importFrom shiny moduleServer selectInput reactive req observe
#' @importFrom shiny updateSelectInput
#' @importFrom plotly renderPlotly
#' @importFrom htmlwidgets saveWidget
#' @importFrom SummarizedExperiment colData
#' @importFrom shinyhelper helper
#'
#' @noRd
driftServer <- function(id, se, se_n, se_b, se_t, se_i, missingValue) {
shiny::moduleServer(
id,
function(input, output, session) {
shiny::observe({
if (missingValue) {
data_l <- list("raw", "normalized", "batch corrected",
"transformed", "imputed")
} else {
data_l <- list("raw", "normalized", "batch corrected",
"transformed")
}
shiny::updateSelectInput(session = session, inputId = "data",
choices = data_l)
})
se_drift <- shiny::reactive({
shiny::req(input$data)
if (input$data == "raw") se <- se()
if (input$data == "normalized") se <- se_n()
if (input$data == "batch corrected") se <- se_b()
if (input$data == "transformed") se <- se_t()
if (input$data == "imputed") se <- se_i()
se
})
cD <- shiny::reactive(se()@colData)
shiny::observe({
cols_cD <- colnames(cD())
shiny::updateSelectInput(session = session,
inputId = "category",
choices = cols_cD)
shiny::updateSelectInput(session = session,
inputId = "orderCategory", choices = cols_cD)
})
shiny::observe({
shiny::updateSelectInput(session = session,
inputId = "levelSel",
choices = c("all", unique(cD()[[input$category]])))
})
p_drift <- shiny::reactive({
driftPlot(se = se_drift(), aggregation = input$aggregation,
category = input$category,
orderCategory = input$orderCategory,
level = input$levelSel, method = input$method)
})
output$plotDrift <- plotly::renderPlotly({
p_drift()
})
output$downloadPlot <- shiny::downloadHandler(
filename = function() {
paste("Drift_", input$aggregation, "_",
input$category, "_",
input$levelSel, "_", input$method, ".html", sep = "")
},
content = function(file) {
htmlwidgets::saveWidget(p_drift(), file)
}
)
}
)
}
################################################################################
########################### coefficient of variation ###########################
################################################################################
#' @name tP_cvUI
#'
#' @title Tab panel UI for tab panel 'Coefficient of Variation'
#'
#' @description
#' The module defines the UI for the tab panel 'Coefficient of Variation'.
#'
#' @details
#' \code{fR_boxplotUI} returns the HTML code for the tab-pane
#' 'Coefficient of Variation'. Internal function for \code{shinyQC}.
#'
#' @param id \code{character}
#'
#' @return
#' \code{shiny.tag} with HTML content
#'
#' @author Thomas Naake
#'
#' @examples
#' fR_cvUI("test")
#'
#' @importFrom shiny NS tabPanel fluidRow downloadButton selectInput column
#'
#' @noRd
tP_cvUI <- function(id) {
ns <- shiny::NS(id)
shiny::tabPanel(title = "Coefficient of variation",
shiny::fluidRow(
shiny::column(12,
shiny::plotOutput(outputId = ns("cv"), width = "95%") |>
shinyhelper::helper(content = "tabPanel_cv")),
shiny::column(6,
shiny::selectInput(inputId = ns("data"),
label = "Data set", choices = "raw",
selected = "raw", multiple = TRUE)),
shiny::column(6,
shiny::downloadButton(outputId = ns("downloadPlot"), ""))
)
)
}
#' @name cvServer
#'
#' @title Module for server expressions of tab panel 'Coefficient of variation'
#'
#' @description
#' The module defines the server expressions for the tab panel
#' 'Coefficient of variation'.
#'
#' @details
#' Internal function for \code{shinyQC}.
#'
#' @param id \code{character}
#' @param a_r \code{matrix} and \code{reactive} value
#' @param a_n \code{matrix} and \code{reactive} value
#' @param a_b \code{matrix} and \code{reactive} value
#' @param a_t \code{matrix} and \code{reactive} value
#' @param a_i \code{matrix} and \code{reactive} value
#' @param missingValue \code{logical} (if \code{FALSE} do not use imputed values)
#'
#' @return
#' \code{shiny.render.function} expression
#'
#' @author Thomas Naake
#'
#' @importFrom shiny moduleServer reactive updateSelectInput renderPlot
#' @importFrom shiny downloadHandler
#' @importFrom shinyhelper helper
#' @importFrom ggplot2 ggsave
#' @importFrom plotly plotlyOutput
#'
#' @noRd
cvServer <- function(id, a_r, a_n, a_b, a_t, a_i, missingValue) {
shiny::moduleServer(
id,
function(input, output, session) {
## create the cv values
cv_r <- shiny::reactive({
cv(a_r(), name = "raw")
})
cv_n <- shiny::reactive({
cv(a_n(), name = "normalized")
})
cv_b <- shiny::reactive({
cv(a_b(), name = "batch corrected")
})
cv_t <- shiny::reactive({
cv(a_t(), name = "transformed")
})
cv_i <- shiny::reactive({
cv(a_i(), name = "imputed")
})
shiny::observe({
a_r()
if (missingValue) {
data_l <- c("raw", "normalized", "batch corrected",
"transformed", "imputed")
} else {
data_l <- c("raw", "normalized", "batch corrected",
"transformed")
}
shiny::updateSelectInput(session = session, inputId = "data",
choices = data_l, selected = "raw")
})
## create a reactive data.frame containing the cv values
df_cv <- shiny::reactive({
df <- data.frame(row.names = colnames(a_r()))
if ("raw" %in% input$data) df <- cbind(df, cv_r())
if ("normalized" %in% input$data) df <- cbind(df, cv_n())
if ("batch corrected" %in% input$data) df <- cbind(df, cv_b())
if ("transformed" %in% input$data) df <- cbind(df, cv_t())
if ("imputed" %in% input$data) df <- cbind(df, cv_i())
df
})
p_cv <- shiny::reactive({
plotCV(df = df_cv())
})
## create the actual plot
output$cv <- shiny::renderPlot({
p_cv()
})
output$downloadPlot <- shiny::downloadHandler(
filename = function() {
paste("CV.pdf", sep = "")
},
content = function(file) {
ggplot2::ggsave(file, p_cv(), device = "pdf",
limitsize = FALSE)
}
)
}
)
}
################################################################################
################################# mean-sd plot #################################
################################################################################
#' @name box_meanSdUI
#'
#' @title Box UI for tab panel 'mean-sd plot'
#'
#' @description
#' The module defines the UI in the tab panel 'mean-sd plot'.
#'
#' @details
#' \code{box_meanSdUI} returns the HTML code for the tab-pane 'mean-sd plot'.
#' Internal function for \code{shinyQC}.
#'
#' @param id \code{character}
#' @param name \code{character}, name/title for the box
#'
#' @return
#' \code{shiny.tag} with HTML content
#'
#' @author Thomas Naake
#'
#' @examples
#' box_meanSdUI("test", "test")
#'
#' @importFrom shiny NS plotOutput downloadButton
#' @importFrom shinydashboard box
#'
#' @noRd
box_meanSdUI <- function(id, name) {
ns <- shiny::NS(id)
shinydashboard::box(title = name, width = 6, collapsible = TRUE,
shiny::plotOutput(outputId = ns("meanSd")),
shiny::downloadButton(outputId = ns("downloadPlot"), "")
)
}
#' @name tP_meanSdUI
#'
#' @title Tab panel UI for tab panel 'mean-sd plot'
#'
#' @description
#' The module defines the UI in the tab panel 'mean-sd plot'. It serves as a
#' wrapper for the function \code{box_meanSdUI}.
#'
#' @details
#' \code{box_meanSdUI} returns the HTML code for the tab-pane 'mean-sd plot'.
#' Internal function for \code{shinyQC}.
#'
#' @param id \code{character}
#'
#' @return
#' \code{shiny.tag} with HTML content
#'
#' @author Thomas Naake
#'
#' @examples
#' tP_meanSdUI("")
#'
#' @importFrom shiny tabPanel fluidRow conditionalPanel br column
#' @importFrom shinyhelper helper
#'
#' @noRd
tP_meanSdUI <- function(id) {
ns <- shiny::NS(id)
shiny::tabPanel(title = "mean-sd plot",
## call here the module UIs box_meanSdUI
shiny::fluidRow(width = 12,
shiny::column(12,
shiny::br() |>
shinyhelper::helper(content = "tabPanel_meanSd")),
box_meanSdUI("meanSdTransf", "transformed"),
shiny::conditionalPanel("output.missingVals == 'TRUE'",
box_meanSdUI("meanSdImp", "imputed"))
)
)
}
#' @name meanSdServer
#'
#' @title Module for server expressions of tab panel 'mean-sd plot'
#'
#' @description
#' The module defines the server expressions for the tab panel 'mean-sd plot'.
#'
#' @details
#' Internal function for \code{shinyQC}.
#'
#' @param id \code{character}
#' @param assay \code{matrix} and \code{reactive} expression, obtained from
#' \code{assay(SummarizedExperiment)}
#' @param type \code{character}
#'
#' @return
#' \code{shiny.render.function} expression
#'
#' @author Thomas Naake
#'
#' @importFrom shiny moduleServer reactive renderPlot downloadHandler
#' @importFrom ggplot2 ggsave theme_classic
#'
#' @noRd
#'
#' @importFrom vsn meanSdPlot
meanSdServer <- function(id, assay, type) {
shiny::moduleServer(
id,
function(input, output, session) {
p_meansd <- shiny::reactive({
req(assay())
vsn::meanSdPlot(assay(), ranks = TRUE)$gg +
ggplot2::theme_bw()
})
output$meanSd <- shiny::renderPlot({
p_meansd()
})
output$downloadPlot <- shiny::downloadHandler(
filename = function() {
paste("Meansd_", type, ".pdf", sep = "")
},
content = function(file) {
ggplot2::ggsave(file, p_meansd(), device = "pdf",
limitsize = FALSE)
}
)
}
)
}
################################################################################
#################################### MA plot ###################################
################################################################################
#' @name tP_maUI
#'
#' @title Tab panel UI for tab panel 'MA plot'
#'
#' @description
#' The module defines the UI in the tab panel 'MA plot'.
#'
#' @details
#' \code{tP_maUI} returns the HTML code for the tab-pane 'MA plot'.
#' Internal function for \code{shinyQC}.
#'
#' @param id \code{character}
#' @param missingValue \code{logical} (if \code{FALSE} do not show option
#' for imputed)
#'
#' @return
#' \code{shiny.tag} with HTML content
#'
#' @author Thomas Naake
#'
#' @examples
#' tP_maUI("test")
#'
#' @importFrom shiny NS tabPanel fluidRow downloadButton column
#' @importFrom shiny plotOutput checkboxInput
#' @importFrom shinydashboard box
#' @importFrom plotly plotlyOutput
#'
#' @noRd
tP_maUI <- function(id) {
ns <- shiny::NS(id)
shiny::tabPanel(title = "MA plot",
shiny::fluidRow(
shiny::column(6,
shiny::selectInput(
inputId = ns("groupMA"), label = "group",
choices = "all")),
shiny::column(6,
shiny::selectInput(
inputId = ns("plotMA"), label = "plot", multiple = TRUE,
selected = "sample", choices = "all_samples"))
) |>
shinyhelper::helper(content = "tabPanel_MA"),
shiny::fluidRow(
shinydashboard::box(title = "MA plot per sample", width = 12,
collapsible = TRUE,
shiny::plotOutput(outputId = ns("MAplot"), height = "100%"),
shiny::downloadButton(outputId = ns("downloadPlotMA"), ""),
shiny::selectInput(
inputId = ns("MAtype"), label = "Data set for the MA plot",
choices = "raw")
)
),
shiny::fluidRow(
shinydashboard::box(title = "Hoeffding's D statistic", width = 12,
collapsible = TRUE,
plotly::plotlyOutput(outputId = ns("hoeffDPlot")),
shiny::downloadButton(outputId = ns("downloadPlothD"), ""),
shiny::checkboxInput(inputId = ns("hDLines"),
label = "lines", value = FALSE)
)
)
)
}
#' @name maServer
#'
#' @title Module for server expressions of tab panel 'MA plot'
#'
#' @description
#' The module defines the server expressions in the tab panel 'MA plot'.
#'
#' @details
#' Internal function for \code{shinyQC}.
#'
#' @param id \code{character}
#' @param se \code{SummarizedExperiment} object and \code{reactive} value,
#' containing raw values
#' @param se_n \code{SummarizedExperiment} object and \code{reactive} value,
#' containing normalized values
#' @param se_b \code{SummarizedExperiment} object and \code{reactive} value,
#' containing batch corrected values
#' @param se_t \code{SummarizedExperiment} object and \code{reactive} value,
#' containing transformed values
#' @param se_i \code{SummarizedExperiment} object and \code{reactive} value,
#' containing imputed values
#' @param innerWidth \code{numeric} and \code{reactive} value, specifying
#' the width of the window size
#' @param missingValue \code{logical} (if \code{FALSE} do not show values for
#' imputed)
#'
#' @return
#' \code{shiny.render.function} expression
#'
#' @author Thomas Naake
#'
#' @importFrom shiny moduleServer fluidRow selectInput column req
#' @importFrom shiny downloadHandler bindCache
#' @importFrom shinyhelper helper
#' @importFrom plotly renderPlotly
#' @importFrom htmlwidgets saveWidget
#' @importFrom SummarizedExperiment colData
#'
#' @noRd
maServer <- function(id, se, se_n, se_b, se_t, se_i, innerWidth,
missingValue) {
shiny::moduleServer(
id,
function(input, output, session) {
## create reactiveValues to store innerWidth, update if there are
## changes to the parameters
rv <- reactiveValues(
innerWidth = "600px")
observeEvent(innerWidth(), {
rv$innerWidth <- innerWidth() * 2.5 / 5
})
## access the colData slot and add the rownames as a new column to cD
## (will add the column "rowname")
cD <- shiny::reactive({
se()@colData |> as.data.frame()
})
cD_rn <- shiny::reactive({
cD_rn <- cD()
cD_rn[["rowname"]] <- rownames(cD_rn)
cD_rn
})
selected_samples <- reactive({
if (nrow(cD()) > 3) {
rownames(cD())[seq_len(3)]
} else {
rownames(cD())
}
})
shiny::observe({
shiny::updateSelectInput(
inputId = "groupMA", choices = c("all", colnames(cD())))
})
shiny::observe({
selected_samples <- selected_samples()
shiny::updateSelectInput(
inputId = "plotMA", selected = selected_samples,
choices = cD_rn()[["rowname"]])
})
shiny::observe({
if (missingValue) {
data_l <- list("raw", "normalized", "batch corrected",
"transformed", "imputed")
} else {
data_l <- list("raw", "normalized", "batch corrected",
"transformed")
}
shiny::updateSelectInput(session = session, inputId = "MAtype",
choices = data_l)
})
## create MA values: se, log2, group
vals_r <- shiny::reactive({
if (any(SummarizedExperiment::assay(se()) < 0, na.rm = TRUE)) {
log2_se <- FALSE
} else {
log2_se <- TRUE
}
MAvalues(se(), log2_se, input$groupMA)}) |>
shiny::bindCache(se(), input$groupMA, cache = "session")
vals_n <- shiny::reactive({
if (any(SummarizedExperiment::assay(se_n()) < 0, na.rm = TRUE)) {
log2_se <- FALSE
} else {
log2_se <- TRUE
}
MAvalues(se_n(), log2_se, input$groupMA)}) |>
shiny::bindCache(se_n(), input$groupMA, cache = "session")
vals_b <- shiny::reactive({
if (any(SummarizedExperiment::assay(se_b()) < 0, na.rm = TRUE)) {
log2_se <- FALSE
} else {
log2_se <- TRUE
}
MAvalues(se_b(), log2_se, input$groupMA)}) |>
shiny::bindCache(se_b(), input$groupMA, cache = "session")
vals_t <- shiny::reactive({
MAvalues(se_t(), FALSE, input$groupMA)}) |>
shiny::bindCache(se_t(), input$groupMA, cache = "session")
vals_i <- shiny::reactive({
MAvalues(se_i(), FALSE, input$groupMA)}) |>
shiny::bindCache(se_i(), input$groupMA, cache = "session")
## MA plots: MA values, group
p_ma <- shiny::reactive({
if (length(input$plotMA) != 0) {
if (input$MAtype == "raw") {
ma <- MAplot(vals_r(), group = input$groupMA,
plot = input$plotMA)
}
if (input$MAtype == "normalized") {
ma <- MAplot(vals_n(), group = input$groupMA,
plot = input$plotMA)
}
if (input$MAtype == "batch corrected") {
ma <- MAplot(vals_b(), group = input$groupMA,
plot = input$plotMA)
}
if (input$MAtype == "transformed") {
ma <- MAplot(vals_t(), group = input$groupMA,
plot = input$plotMA)
}
if (input$MAtype == "imputed") {
ma <- MAplot(vals_i(), group = input$groupMA,
plot = input$plotMA)
}
ma
} else
NULL
})
output$MAplot <- shiny::renderPlot({
if (!is.null(p_ma()))
p_ma()
}, height = reactive(rv$innerWidth), width = "auto")
output$downloadPlotMA <- shiny::downloadHandler(
filename = function() {
paste("MA_", input$MAtype, "_", input$groupMA, "_",
input$plotMA,".pdf", sep = "")
},
content = function(file) {
ggplot2::ggsave(file, p_ma(), device = "pdf",
height = rv$innerWidth, width = rv$innerWidth,
units = "px", limitsize = FALSE)
}
)
## Hoeffding's D values: MA values, title for plot
hD_r <- shiny::reactive({
hoeffDValues(vals_r(), "raw", sample_n = 5000)
}) |>
shiny::bindCache(vals_r(), cache = "session")
hD_n <- shiny::reactive({
hoeffDValues(vals_n(), "normalized", sample_n = 5000)
}) |>
shiny::bindCache(vals_n(), cache = "session")
hD_b <- shiny::reactive({
hoeffDValues(vals_b(), "batch corrected", sample_n = 5000)
}) |>
shiny::bindCache(vals_b(), cache = "session")
hD_t <- shiny::reactive({
hoeffDValues(vals_t(), "transformed", sample_n = 5000)
}) |>
shiny::bindCache(vals_t(), cache = "session")
hD_i <- shiny::reactive({
hoeffDValues(vals_i(), "imputed", sample_n = 5000)
}) |>
shiny::bindCache(vals_i(), cache = "session")
## create reactive data.frame for the hoeffDPlot function
hoeffD_df <- shiny::reactive({
if (missingValue) {
df <- data.frame(raw = hD_r(), normalized = hD_n(),
`batch corrected` = hD_b(), transformed = hD_t(),
imputed = hD_i())
} else {
df <- data.frame(raw = hD_r(), normalized = hD_n(),
`batch corrected` = hD_b(), transformed = hD_t())
}
df
})
## Hoeffding's D plots: lists (Hoeffding's D values), lines
output$hoeffDPlot <- plotly::renderPlotly({
hoeffDPlot(hoeffD_df(), lines = input$hDLines)
})
output$downloadPlothD <- shiny::downloadHandler(
filename = function() {
paste("Hoeffding_D_", input$groupMA, ".html")
},
content = function(file) {
htmlwidgets::saveWidget(
hoeffDPlot(hoeffD_df(), lines = input$hDLines), file)
}
)
}
)
}
################################################################################
##################################### ECDF #####################################
################################################################################
#' @name tP_ECDFUI
#'
#' @title Tab panel UI for tab panel 'ECDF'
#'
#' @description
#' The module defines the UI in the tab panel 'ECDF'
#'
#' @details
#' \code{tP_ECDFUI} returns the HTML code for the tab-pane 'ECDF'.
#' Internal function for \code{shinyQC}.
#'
#' @param id \code{character}
#'
#' @return
#' \code{shiny.tag} with HTML content
#'
#' @author Thomas Naake
#'
#' @examples
#' tP_ECDFUI("test")
#'
#' @importFrom shiny NS tabPanel plotOutput fluidRow column downloadButton
#' @importFrom shinyhelper helper
#'
#' @noRd
tP_ECDFUI <- function(id) {
ns <- shiny::NS(id)
shiny::tabPanel(title = "ECDF",
shiny::plotOutput(outputId = ns("ECDF")) |>
shinyhelper::helper(content = "tabPanel_ecdf"),
shiny::downloadButton(outputId = ns("downloadPlot"), ""),
shiny::fluidRow(
shiny::column(4,
shiny::selectInput(inputId = ns("typeECDF"),
label = "Data set for the ECDF plot", choices = "raw")),
shiny::column(4,
shiny::selectInput(inputId = ns("sampleECDF"),
label = "Sample", choices = "all_samples",
selected = "sample")),
shiny::column(4,
shiny::selectInput(inputId = ns("groupECDF"),
label = "group", choices = "all"))
)
)
}
#' @name ECDFServer
#'
#' @title Module for server expressions of tab panel 'ECDF'
#'
#' @description
#' The module defines the server expressions in the tab panel 'ECDF'.
#'
#' @details
#' Internal function for \code{shinyQC}.
#'
#' @param id \code{character}
#' @param se \code{SummarizedExperiment} object and \code{reactive} value, containing
#' raw values
#' @param se_n \code{SummarizedExperiment} object and \code{reactive} value, containing
#' normalized values
#' @param se_b \code{SummarizedExperiment} object and \code{reactive} value, containing
#' batch corrected values
#' @param se_t \code{SummarizedExperiment} object and \code{reactive} value, containing
#' transformed values
#' @param se_i \code{SummarizedExperiment} object and \code{reactive} value, containing
#' imputed values
#' @param missingValue \code{logical} (if \code{FALSE} do not show option for imputed)
#'
#' @return
#' \code{shiny.render.function} expression
#'
#' @importFrom shiny moduleServer updateSelectInput reactive
#' @importFrom shiny downloadHandler renderPlot
#' @importFrom ggplot2 ggsave
#' @importFrom SummarizedExperiment colData
#' @importFrom tibble rownames_to_column
#'
#' @author Thomas Naake
#'
#' @noRd
ECDFServer <- function(id, se, se_n, se_b, se_t, se_i, missingValue) {
shiny::moduleServer(
id,
function(input, output, session) {
shiny::observe({
if (missingValue) {
data_l <- list("raw", "normalized", "batch corrected",
"transformed", "imputed")
} else {
data_l <- list("raw", "normalized", "batch corrected",
"transformed")
}
shiny::updateSelectInput(session = session,
inputId = "typeECDF", choices = data_l)
})
shiny::observe({
cD_rn <- se() |> colnames()
shiny::updateSelectInput(session = session,
inputId = "sampleECDF", choices = cD_rn)
})
shiny::observe({
updateSelectInput(
inputId = "groupECDF",
choices = c("all", colnames(se()@colData)))
})
## ECDF plots: se, sample, group
se_sel <- shiny::reactive({
if (input$typeECDF == "raw") SE <- se()
if (input$typeECDF == "normalized") SE <- se_n()
if (input$typeECDF == "batch corrected") SE <- se_b()
if (input$typeECDF == "transformed") SE <- se_t()
if (input$typeECDF == "imputed") SE <- se_i()
SE
})
p_ecdf <- shiny::reactive({
ECDF(se = se_sel(), sample = input$sampleECDF,
group = input$groupECDF)
})
output$ECDF <- shiny::renderPlot({
p_ecdf()
})
output$downloadPlot <- shiny::downloadHandler(
filename = function() {
paste("ECDF_", input$typeECDF, "_", input$groupECDF, "_",
input$sampleECDF, ".pdf", sep = "")
},
content = function(file) {
ggplot2::ggsave(file, p_ecdf(), device = "pdf",
limitsize = FALSE)
}
)
}
)
}
################################################################################
################################### distances ##################################
################################################################################
#' @name fR_distUI
#'
#' @title Fluid row UI for tab panel 'Distance matrix'
#'
#' @description
#' The module defines the UI in the tab panel 'Distance matrix'.
#'
#' @details
#' \code{fR_distUI} returns the HTML code for the tab-pane 'Distance Matrix'.
#' Internal function for \code{shinyQC}.
#'
#' @param id \code{character}
#' @param title \code{character} name/title of the box
#' @param collapsed \code{logical}
#'
#' @return
#' \code{shiny.tag} with HTML content
#'
#' @author Thomas Naake
#'
#' @examples
#' fR_distUI("test", "test")
#'
#' @importFrom shiny NS fluidRow downloadButton column
#' @importFrom shinydashboard box
#' @importFrom plotly plotlyOutput
#' @importFrom shinyhelper helper
#'
#' @noRd
fR_distUI <- function(id, title, collapsed = TRUE) {
ns <- shiny::NS(id)
shiny::fluidRow(
shinydashboard::box(title = title, width = 12,
collapsible = TRUE, collapsed = collapsed,
shiny::column(6,
shiny::plotOutput(outputId = ns("distSample")),
shiny::downloadButton(outputId = ns("downloadPlotDist"), "")),
shiny::column(6,
plotly::plotlyOutput(outputId = ns("distSampleSum")),
shiny::downloadButton(outputId = ns("downloadPlotSum"), ""))))
}
#' @name tP_distUI
#'
#' @title Tab panel UI for tab panel 'Distance matrix'
#'
#' @description
#' The function defines the UI in the tab panel 'Distance matrix'. It serves
#' as a wrapper for \code{fR_distUI}.
#'
#' @details
#' \code{tP_distUI} returns the HTML code for the tab-pane 'Distance matrix'.
#' Internal function for \code{shinyQC}.
#'
#' @param missingValue \code{logical} (if \code{FALSE} do not show box for imputed)
#'
#' @return
#' \code{shiny.tag} with HTML content
#'
#' @author Thomas Naake
#'
#' @examples
#' tP_distUI()
#'
#' @importFrom shiny tabPanel fluidRow column selectInput br
#' @importFrom shinydashboard box
#'
#' @noRd
tP_distUI <- function() {
shiny::tabPanel(title = "Distance matrix",
br() |> shinyhelper::helper(content = "tabPanel_distMat"),
fR_distUI(id = "distRaw", title = "raw", collapsed = FALSE),
fR_distUI(id = "distNorm", title = "normalized", collapsed = TRUE),
fR_distUI(id = "distBatch", title = "batch corrected",
collapsed = TRUE),
fR_distUI(id = "distTransf", title = "transformed", collapsed = TRUE),
shiny::conditionalPanel("output.missingVals == 'TRUE'",
fR_distUI(id = "distImp", title = "imputed", collapsed = TRUE)),
shiny::fluidRow(
shinydashboard::box(title = "Parameters", width = 6,
collapsible = TRUE, collapsed = FALSE,
shiny::column(12,
shiny::selectInput(inputId = "groupDist",
label = "annotation", choices = "name")),
shiny::column(12,
shiny::selectInput(inputId = "methodDistMat",
label = "distance method",
choices = c("euclidean", "maximum", "canberra",
"minkowski"),
selected = "euclidean"))
)
)
)
}
#' @name distServer
#'
#' @title Module for server expressions of tab panel 'Distance matrix'
#'
#' @description
#' The module defines the server expressions in the tab panel 'Distance matrix'.
#'
#' @details
#' Internal function for \code{shinyQC}.
#'
#' @param id \code{character}
#' @param se \code{SummarizedExperiment} object and \code{reactive} value
#' @param assay \code{matrix} and \code{reactive} value
#' @param method \code{character} and \code{reactive} value, one of \code{"euclidean"},
#' \code{"mannhattan"}, \code{"canberra"}, or \code{"minkowski"}
#' @param label \code{character} and \code{reactive} value, specified the annotation of
#' the \code{ComplexHeatmap}
#' @param type \code{character}
#'
#' @return
#' \code{shiny.render.function} expression
#'
#' @author Thomas Naake
#'
#' @importFrom shiny moduleServer reactive downloadHandler req
#' @importFrom plotly renderPlotly partial_bundle
#' @importFrom htmlwidgets saveWidget
#' @importFrom ComplexHeatmap draw
#' @importFrom grDevices pdf dev.off
#'
#'
#' @noRd
distServer <- function(id, se, assay, method, label, type) {
shiny::moduleServer(
id,
function(input, output, session) {
d <- shiny::reactive({
distShiny(assay(), method = method())
})
## plot of distance matrix
p_dist <- shiny::reactive({
distSample(d(), se(), label = label(), title = "")
})
output$distSample <- shiny::renderPlot({
shiny::req(label())
p_dist()
})
output$downloadPlotDist <- shiny::downloadHandler(
filename = function() {
paste("Distance_", type, "_", method(), ".pdf", sep = "")
},
content = function(file) {
grDevices::pdf(file)
p = p_dist()
ComplexHeatmap::draw(p)
grDevices::dev.off()
##htmlwidgets::saveWidget(partial_bundle(p_dist()), file)
}
)
## plot of sum of distances
p_sumDist <- shiny::reactive({
sumDistSample(d(), title = "")
})
output$distSampleSum <- plotly::renderPlotly({
p_sumDist()
})
output$downloadPlotSum <- shiny::downloadHandler(
filename = function() {
paste("Sum_distance_", type, "_",
method(), ".html", sep = "")
},
content = function(file) {
htmlwidgets::saveWidget(partial_bundle(p_sumDist()), file)
}
)
}
)
}
################################################################################
################################### Features ###################################
################################################################################
#' @name tP_featureUI
#'
#' @title UI for tab panel 'Features'
#'
#' @description
#' The module defines the UI in the tab panel 'Features'.
#'
#' @details
#' \code{tP_featureUI} returns the HTML code for the tab-pane 'Distance Matrix'.
#' Internal function for \code{shinyQC}.
#'
#' @param id \code{character}
#' @param title \code{character} name/title of the box
#' @param collapsed \code{logical}
#'
#' @return
#' \code{shiny.tag} with HTML content
#'
#' @author Thomas Naake
#'
#' @examples
#' fR_distUI("test", "test")
#'
#' @importFrom shiny NS tabPanel plotOutput column radioButtons
#' @importFrom shiny selectizeInput checkboxInput downloadButton
#' @importFrom shinydashboard box
#' @importFrom plotly plotlyOutput
#' @importFrom shinyhelper helper
#'
#' @noRd
tP_featureUI <- function(id) {
ns <- shiny::NS(id)
shiny::tabPanel(title = "Features",
br() |> shinyhelper::helper(content = "tabPanel_Features"),
shinydashboard::box(title = "", width = 12, collapsible = TRUE,
collapsed = FALSE,
shiny::plotOutput(outputId = ns("Features")),
shiny::column(4,
shiny::downloadButton(outputId = ns("downloadPlot"), "")),
shiny::column(4,
shiny::selectInput(inputId = ns("data"),
label = "Data set", choices = "raw", multiple = TRUE,
selected = "raw")),
shiny::column(4,
shiny::selectizeInput(inputId = ns("selectFeature"),
choices = NULL, label = "Select feature"))
),
shinydashboard::box(title = "", width = 12, collapsible = TRUE,
collapsed = FALSE,
plotly::plotlyOutput(outputId = ns("FeaturesCV")),
shiny::column(6,
shiny::downloadButton(outputId = ns("downloadPlotCV"), "")),
shiny::column(6,
shiny::checkboxInput(inputId = ns("FeatureLines"),
label = "lines", value = FALSE))
),
shiny::radioButtons(inputId = ns("mode"), label = "Select features",
choices = list("all" = "all", "exclude" = "exclude",
"select" = "select")),
shiny::selectizeInput(inputId = ns("excludeFeature"), choices = NULL,
label = NULL, multiple = TRUE)
)
}
#' @name featureServer
#'
#' @title Module for server expressions of tab panel 'Features'
#'
#' @description
#' The module defines the server expressions in the tab panel 'Features'.
#'
#' @details
#' Internal function for \code{shinyQC}.
#'
#' @param id \code{character}
#' @param se \code{SummarizedExperiment} object
#' @param a \code{matrix} and \code{reactive} value, containing raw values
#' @param a_n \code{matrix} and \code{reactive} value, containing
#' normalized values
#' @param a_b \code{matrix} and \code{reactive} value, containing
#' batch corrected values
#' @param a_t \code{matrix} and \code{reactive} value, containing
#' transformed values
#' @param a_i \code{matrix} and \code{reactive} value, containing
#' imputed values
#' @param missingValue \code{logical} (if \code{FALSE} do not show option for
#' imputed)
#'
#' @return
#' \code{shiny.render.function} expression
#'
#' @author Thomas Naake
#'
#' @importFrom shiny moduleServer observe updateSelectizeInput updateSelectInput
#' @importFrom shiny reactive req renderPlot downloadHandler
#' @importFrom ggplot2 ggsave
#' @importFrom plotly renderPlotly
#' @importFrom htmlwidgets saveWidget
#'
#' @noRd
featureServer <- function(id, se, a, a_n, a_b, a_t, a_i, missingValue) {
shiny::moduleServer(
id,
function(input, output, session) {
shiny::observe({
shiny::updateSelectizeInput(session = session,
inputId = "selectFeature",
choices = as.list(rownames(a())), server = TRUE)
})
shiny::observe({
shiny::updateSelectizeInput(session = session,
inputId = "excludeFeature",
choices = rownames(se), server = TRUE)
})
shiny::observe({
if (missingValue) {
choices_l <- c("raw", "normalized", "batch.corrected",
"transformed", "imputed")
} else {
choices_l <- c("raw", "normalized", "batch.corrected",
"transformed")
}
shiny::updateSelectInput(inputId = "data",
label = "Data set", choices = choices_l,
selected = choices_l)
})
## create a reactive data.frame containing the assay values
l_assays <- shiny::reactive({
shiny::req(a_i())
if (missingValue) {
l <- list(raw = a(), normalized = a_n(),
`batch.corrected` = a_b(), transformed = a_t(),
imputed = a_i())
} else {
l <- list(raw = a(), normalized = a_n(),
`batch.corrected` = a_b(), transformed = a_t())
}
l
})
df_feature <- shiny::reactive({
l <- l_assays()
l <- l[names(l) %in% input$data]
if (length(l) > 0) {
createDfFeature(l, feature = input$selectFeature)
} else {
NULL
}
})
p_feature <- shiny::reactive({
if (!is.null(df_feature()))
featurePlot(df_feature())
})
output$Features <- shiny::renderPlot({
p_feature()
})
output$downloadPlot <- shiny::downloadHandler(
filename = function() {
paste("Features_", input$selectFeature, ".pdf", sep = "")
},
content = function(file) {
ggplot2::ggsave(file, p_feature(), device = "pdf",
limitsize = FALSE)
}
)
output$FeaturesCV <- plotly::renderPlotly({
cvFeaturePlot(l_assays(), lines = input$FeatureLines)
})
output$downloadPlotCV <- shiny::downloadHandler(
filename = function() {
paste("Features_CV_lines_", input$FeatureLines,
".html", sep = "")
},
content = function(file) {
htmlwidgets::saveWidget(
cvFeaturePlot(l_assays(), lines = input$FeatureLines),
file)
}
)
}
)
}
#' @name tP_values_all
#'
#' @title Tab panel UI for tab panel 'Values'
#'
#' @description
#' The module defines the UI for the tab panel 'Values'.
#'
#' @details
#' \code{tP_values_all} returns the HTML code for the tab-pane 'Values'.
#' Internal function for \code{shinyQC}.
#'
#' @return
#' \code{shiny.tag} with HTML content
#'
#' @author Thomas Naake
#'
#' @examples
#' tP_values_all()
#'
#' @importFrom shiny tabPanel
#' @importFrom shinydashboard tabBox
#'
#' @noRd
tP_values_all <- function() {
shiny::tabPanel("Values",
shinydashboard::tabBox(title = "", width = 12,
tP_boxplotUI(id = "boxUI"),
tP_driftUI(id = "drift"),
tP_cvUI(id = "cv"),
tP_meanSdUI(id = "meanSd"),
tP_maUI(id = "MA"),
tP_ECDFUI(id = "ECDF"),
tP_distUI(),
tP_featureUI(id = "features")
)
)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.