#' Define additional heatmap observers
#'
#' Define a series of observers to track additional parameters specific to the \code{ComplexHeatmapPlot} panel.
#' These register input changes to each specified parameter in the app's memory
#' and request an update to the output of the affected panel.
#'
#' @param plot_name String containing the name of the panel.
#' @param se A \linkS4class{SummarizedExperiment} object after running \code{\link{.cacheCommonInfo}}.
#' @param input The Shiny input object from the server function.
#' @param session The Shiny session object from the server function.
#' @param pObjects An environment containing global parameters generated in the \code{\link{iSEE}} app.
#' @param rObjects A reactive list of values generated in the \code{\link{iSEE}} app.
#'
#' @return
#' Observers are set up to monitor the UI elements that can change various parameters specific to the \code{ComplexHeatmapPlot} panel.
#' A \code{NULL} is invisibly returned.
#'
#'
#' @seealso
#' \code{\link{.requestUpdate}} and \code{\link{.requestCleanUpdate}},
#' used to trigger updates to the panel output.
#'
#' @author Kevin Rue-Albrecht
#'
#' @rdname INTERNAL_create_heatmap_extra_observers
#' @importFrom shiny observeEvent updateNumericInput
#' @importFrom shinyjs disable enable
.create_heatmap_extra_observers <- function(plot_name, se, input, session, pObjects, rObjects) {
.input_FUN <- function(field) paste0(plot_name, "_", field)
# nocov start
observeEvent(input[[.input_FUN(.heatMapAssay)]], {
# .createUnprotectedParameterObservers with a twist
current <- slot(pObjects$memory[[plot_name]], .heatMapAssay)
matched_input <- as(input[[.input_FUN(.heatMapAssay)]], typeof(current))
if (identical(matched_input, current)) {
return(NULL)
}
slot(pObjects$memory[[plot_name]], .heatMapAssay) <- matched_input
# Twist: clear and update the limits of lower/upper bounds based on the new data
plot_range <- range(assay(se, input[[.input_FUN(.heatMapAssay)]]), na.rm = TRUE)
updateNumericInput(session, .input_FUN(.assayLowerBound), value = numeric(0), min = -Inf, max = 0)
updateNumericInput(session, .input_FUN(.assayUpperBound), value = numeric(0), min = 0, max = Inf)
# Twist2: toggle UI related to discrete/continuous assays
ABLEFUN <- if (matched_input %in% .getCachedCommonInfo(se, "ComplexHeatmapPlot")$discrete.assay.names) {
disable
} else {
enable
}
ABLEFUN(.input_FUN(.assayCenterRows))
ABLEFUN(.input_FUN(.assayScaleRows))
ABLEFUN(.input_FUN(.heatMapCenteredColormap))
ABLEFUN(.input_FUN(.heatMapCustomAssayBounds))
ABLEFUN(.input_FUN(.assayLowerBound))
ABLEFUN(.input_FUN(.assayUpperBound))
ABLEFUN(.input_FUN(.heatMapClusterFeatures))
ABLEFUN(.input_FUN(.heatMapClusterDistanceFeatures))
ABLEFUN(.input_FUN(.heatMapClusterMethodFeatures))
.requestUpdate(plot_name, rObjects)
}, ignoreInit=TRUE, ignoreNULL=TRUE)
# nocov end
# nocov start
observeEvent(input[[.input_FUN(.heatMapCustomAssayBounds)]], {
# .createUnprotectedParameterObservers with a twist
current <- slot(pObjects$memory[[plot_name]], .heatMapCustomAssayBounds)
matched_input <- as(input[[.input_FUN(.heatMapCustomAssayBounds)]], typeof(current))
if (identical(matched_input, current)) {
return(NULL)
}
slot(pObjects$memory[[plot_name]], .heatMapCustomAssayBounds) <- matched_input
# Twist: do not rerender if both custom assay bounds UI are empty
if (is.na(input[[.input_FUN(.assayLowerBound)]]) && is.na(input[[.input_FUN(.assayUpperBound)]])) {
return(NULL)
}
.requestUpdate(plot_name, rObjects)
}, ignoreInit=TRUE, ignoreNULL=TRUE)
# nocov end
# nocov start
for (field in c(.assayCenterRows, .assayScaleRows)) {
local({
field0 <- field
observeEvent(input[[.input_FUN(field0)]], {
# .createUnprotectedParameterObservers with a twist
current <- slot(pObjects$memory[[plot_name]], field0)
matched_input <- as(input[[.input_FUN(field0)]], typeof(current))
if (identical(matched_input, current)) {
return(NULL)
}
slot(pObjects$memory[[plot_name]], field0) <- matched_input
# Twist: clear and update the limits of lower/upper bounds based on the new data
updateNumericInput(session, .input_FUN(.assayLowerBound), value = numeric(0), min = -Inf, max = 0)
updateNumericInput(session, .input_FUN(.assayUpperBound), value = numeric(0), min = 0, max = Inf)
.requestUpdate(plot_name, rObjects)
}, ignoreInit=TRUE, ignoreNULL=TRUE)
})
}
# nocov end
# nocov start
all.bounds <- c(.assayLowerBound, .assayUpperBound)
for (bound in all.bounds) {
local({
bound0 <- bound
other <- setdiff(all.bounds, bound)
observeEvent(input[[.input_FUN(bound0)]], {
cur_value <- input[[.input_FUN(bound0)]]
if (is.null(cur_value)) {
return(NULL)
}
if (is.na(cur_value)) {
slot(pObjects$memory[[plot_name]], bound0) <- NA_real_
.requestUpdate(plot_name, rObjects)
return(NULL)
}
slot(pObjects$memory[[plot_name]], bound0) <- cur_value
# The upper bound cannot be lower than the lower bound.
other_bound <- slot(pObjects$memory[[plot_name]], other)
if (!is.null(other_bound) && !is.na(other_bound) &&
((bound0==.assayLowerBound && cur_value > other_bound) ||
(bound0==.assayUpperBound && cur_value < other_bound)))
{
# set identical values; 0-length range is handled later
slot(pObjects$memory[[plot_name]], other) <- cur_value
updateNumericInput(session, .input_FUN(other), value = cur_value)
}
# ComplexHeatmapPlot cannot send selections, thus a simple update is enough
.requestUpdate(plot_name,rObjects)
}, ignoreInit=TRUE, ignoreNULL=FALSE)
})
}
# nocov end
invisible(NULL)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.