#' debrowserheatmap
#'
#' Heatmap module to create interactive heatmaps and get selected list from
#' a heatmap
#' @param input, input variables
#' @param output, output objects
#' @param session, session
#' @param data, a matrix that includes expression values
#' @return heatmapply plot
#'
#' @examples
#' x <- debrowserheatmap()
#'
#' @export
#'
#'
debrowserheatmap <- function( input, output, session, data = NULL){
if(is.null(data)) return(NULL)
output$heatmap <- renderPlotly({
shinyjs::onevent("mousemove", "heatmap", js$getHoverName(session$ns("hoveredgenename")))
shinyjs::onevent("click", "heatmap", js$getHoverName(session$ns("hoveredgenenameclick")))
#shinyjs::onclick( "heatmap", js$getHoverName(session$ns("hoveredgenename1")))
withProgress(message = 'Drawing Heatmap', detail = "interactive", value = 0, {
runHeatmap(input, session, orderData())
})
})
output$heatmap2 <- renderPlot({
withProgress(message = 'Drawing Heatmap', detail = "non-interactive", value = 0, {
runHeatmap2(input, session, orderData())
})
})
heatdata <- reactive({
cld <- prepHeatData(data)
if (input$kmeansControl)
{
res <- niceKmeans(cld, input)
cld <- res$clustered
}
cld
})
button <- reactiveVal(FALSE)
orderData <- reactive({
newclus <- heatdata()
if (input$changeOrder && isolate(button()) && !is.null(input$clusterorder)){
newclus <- changeClusterOrder(isolate(input$clusterorder), newclus)
}
button(FALSE)
newclus
})
observeEvent(input$changeOrder,{
button(TRUE)
})
output$heatmapUI <- renderUI({
if (is.null(input$interactive)) return(NULL)
shinydashboard::box(
collapsible = TRUE, title = session$ns("Heatmap"), status = "primary",
solidHeader = TRUE, width = NULL,
draggable = TRUE, getPlotArea(input, session))
})
hselGenes <- reactive({
if (is.null(input$selgenenames)) return("")
unlist(strsplit(input$selgenenames, split=","))
})
shg <- reactive({
if (is.null(input$hoveredgenename)) return("")
js$getSelectedGenes(session$ns("heatmap"), session$ns("selgenenames"))
input$hoveredgenename
})
observe({
if(!input$changeOrder)
updateTextInput(session, "clusterorder", value = paste(seq(1:input$knum), collapse=","))
if (is.null(shg()))
js$getSelectedGenes()
})
shgClicked <- reactive({
if (is.null(input$hoveredgenenameclick)) return("")
input$hoveredgenenameclick
})
list( shg = (shg), shgClicked=(shgClicked), selGenes=(hselGenes), getSelected = (orderData))
}
#' getPlotArea
#'
#' returns plot area either for heatmaply or heatmap.2
#' @param input, input variables
#' @param session, session
#' @return heatmapply/heatmap.2 plot area
#'
#' @examples
#' x <- getPlotArea()
#'
#' @export
#'
#'
getPlotArea <- function(input = NULL, session = NULL){
if (is.null(input)) return(NULL)
ret <- c()
if (input$interactive){
ret <- plotlyOutput(session$ns("heatmap"),
height=input$height, width=input$width)
}
else{
ret <- plotOutput(session$ns("heatmap2"),
height = input$height, input$width)
}
ret
}
#' runHeatmap
#'
#' Creates a heatmap based on the user selected parameters within shiny
#' @param input, input variables
#' @param session, session
#' @param data, a matrix that includes expression values
#' @return heatmapply plot
#'
#' @examples
#' x <- runHeatmap()
#'
#' @export
#'
#'
runHeatmap <- function(input = NULL, session = NULL, data = NULL){
if (is.null(data)) return(NULL)
cld <-data
hclustfun_row <- function(x, ...) hclust(x, method = input$hclustFun_Row)
hclustfun_col <- function(x, ...) hclust(x, method = input$hclustFun_Col)
distfun_row <- function(x, ...) {
if (input$distFun_Row != "cor") {
return(dist(x, method = input$distFun_Row))
} else {
return(as.dist(1 - cor(t(x))))
}
}
distfun_col <- function(x, ...) {
if (input$distFun_Col != "cor") {
return(dist(x, method = input$distFun_Col))
} else {
return(as.dist(1 - cor(t(x))))
}
}
if (!input$customColors ) {
heatmapColors <- eval(parse(text=paste0(input$pal,
'(',input$ncol,')')))
}
else{
if (!is.null(input$color1))
heatmapColors <- colorRampPalette(c(input$color1,
input$color2, input$color3))(n = 1000)
#heatmapColors <- colorRampPalette(c("red", "white", "blue"))(n = 1000)
}
if (!input$kmeansControl){
p <- heatmaply(cld,
main = input$main,
xlab = input$xlab,
ylab = input$ylab,
row_text_angle = input$row_text_angle,
column_text_angle = input$column_text_angle,
dendrogram = input$dendrogram,
branches_lwd = input$branches_lwd,
seriate = input$seriation,
colors = heatmapColors,
distfun_row = distfun_row,
hclustfun_row = hclustfun_row,
distfun_col = distfun_col,
hclustfun_col = hclustfun_col,
showticklabels = c(input$labCol, input$labRow),
k_col = input$k_Col,
k_row = input$k_Row
)
}else {
if (!input$showClasses){
cld <- data.frame(cld)
cld <- as.matrix(cld [, -match("class",names(cld))])
}
rhcr <- hclust(dist(cld))
chrc <- hclust(dist(t(cld)))
p <- heatmaply(cld,
main = input$main,
xlab = input$xlab,
ylab = input$ylab,
row_text_angle = input$row_text_angle,
column_text_angle = input$column_text_angle,
#dendrogram = input$dendrogram,
dendrogram = "none",
branches_lwd = input$branches_lwd,
seriate = input$seriation,
colors = heatmapColors,
showticklabels = c(input$labCol, input$labRow),
Rowv = as.dendrogram(rhcr),
Colv = as.dendrogram(chrc),
k_col = input$k_Col,
k_row = input$knum
)
}
p <- p %>%
plotly::layout(
margin = list(l = input$left,
b = input$bottom,
t = input$top,
r = input$right
))
p$elementId <- NULL
p
}
#' runHeatmap2
#'
#' Creates a heatmap based on the user selected parameters within shiny
#' @param input, input variables
#' @param session, session
#' @param data, a matrix that includes expression values
#' @return heatmap.2
#'
#' @examples
#' x <- runHeatmap2()
#'
#' @export
#'
#'
runHeatmap2 <- function(input = NULL, session = NULL, data = NULL){
if(is.null(data)) return(NULL)
if (nrow(data)>5000)
data <- data[1:5000, ]
if (!input$customColors ) {
heatmapColors <- eval(parse(text=paste0(input$pal,
'(',input$ncol,')')))
}
else{
if (!is.null(input$color1))
heatmapColors <- colorRampPalette(c(input$color1,
input$color2, input$color3))(n = 1000)
#heatmapColors <- colorRampPalette(c("red", "white", "blue"))(n = 1000)
}
hclustfun_row <- function(x, ...) hclust(x, method = input$hclustFun_Row)
distfun_row <- function(x, ...) {
if (input$distFun_Row != "cor") {
return(dist(x, method = input$distFun_Row))
} else {
return(as.dist(1 - cor(t(x))))
}
}
if (!input$showClasses && "class" %in% names(data) ){
data <- data.frame(data)
data <- as.matrix(data [, -match("class",names(data))])
}
if (input$kmeansControl){
m <- heatmap.2(as.matrix(data), Rowv = FALSE, main = input$main, dendrogram = input$dendrogram,
Colv = FALSE, col = heatmapColors, labRow = input$labRow,
distfun = distfun_row, hclustfun = hclustfun_row, density.info = "none",
trace = "none", margins = c(10,10))
}else{
m <- heatmap.2(as.matrix(data), main = input$main, dendrogram = input$dendrogram,
col = heatmapColors, labRow = input$labRow,
distfun = distfun_row, hclustfun = hclustfun_row, density.info = "none",
trace = "none", margins = c(10,10))
}
m
}
#' changeClusterOrder
#'
#' change order of K-means clusters
#'
#' @note \code{changeClusterOrder}
#' @param order, order
#' @param cld, data
#' @return heatmap plot area
#' @examples
#' x <- changeClusterOrder()
#' @export
#'
changeClusterOrder <- function(order = NULL, cld = NULL){
if (is.null(order) || is.null(cld) ) return(NULL)
newcluster <- c()
idx <- as.integer(as.vector(unlist(strsplit(order, ","))))
da <- data.frame(cld)
for (i in 1:length(idx)) {
newcluster <- rbind(newcluster, da[da$class == idx[i], ])
}
newcluster
}
#' niceKmeans
#'
#' Generates hierarchially clustered K-means clusters
#'
#' @note \code{niceKmeans}
#' @param df, data
#' @param input, user inputs
#' @param iter.max, max iteration for kmeans clustering
#' @param nstart, n for kmeans clustering
#' @return heatmap plot area
#' @examples
#' x <- niceKmeans()
#' @export
#'
niceKmeans <-function (df = NULL, input = NULL, iter.max = 1000, nstart=100) {
if(is.null(df)) return(NULL)
source <-df
kmeans <- kmeans(source, centers = input$knum, iter.max = iter.max, algorithm=input$kmeansalgo, nstart=nstart)
clustered <- data.frame()
distfun_row <- function(x, ...) {
if (input$distFun_Row != "cor") {
return(dist(x, method = input$distFun_Row))
} else {
return(as.dist(1 - cor(t(x))))
}
}
breaks <- c();
for (i in 1:input$knum) {
cluster <- source[kmeans$cluster==i,]
rows <- row.names(cluster)
clust <- hclust(distfun_row(as.matrix(cluster)), method = input$hclustFun_Row)
clust$rowInd <- clust[[3]]
cluster.ordered <- cluster[clust$rowInd,]
cluster.ordered.genes <- rows[clust$rowInd]
row.names(cluster.ordered) <- cluster.ordered.genes
class <- data.frame(row.names = cluster.ordered.genes)
class[,"class"] <- i
cluster.ordered <- cbind(cluster.ordered, class)
clustered <- rbind(clustered, cluster.ordered)
if(i > 1 & i < input$knum) {
breaks[i] <- as.numeric(breaks[i-1]) + length(rows)
} else if(i==1) {
breaks[i] <- length(rows);
}
}
result <- list();
result$clustered <- clustered;
result$breaks <- breaks;
return(result);
}
#' getHeatmapUI
#'
#' Generates the left menu to be used for heatmap plots
#'
#' @note \code{getHeatmapUI}
#' @param id, module ID
#' @return heatmap plot area
#' @examples
#' x <- getHeatmapUI("heatmap")
#' @export
#'
getHeatmapUI <- function(id) {
ns <- NS(id)
uiOutput(ns("heatmapUI"))
}
#' heatmapControlsUI
#'
#' Generates the left menu to be used for heatmap plots
#'
#' @note \code{heatmapControlsUI}
#' @param id, module ID
#' @return HeatmapControls
#' @examples
#' x <- heatmapControlsUI("heatmap")
#' @export
#'
heatmapControlsUI <- function(id) {
ns <- NS(id)
list(
checkboxInput(ns('interactive'), 'Interactive', value = FALSE),
kmeansControlsUI(id),
dendControlsUI(id, "Row"),
dendControlsUI(id, "Col"),
shinydashboard::menuItem("Heatmap Colors",
conditionalPanel(paste0("!input['", ns("customColors"), "']"),
palUI(id),
sliderInput(ns("ncol"), "# of Colors",
min = 1, max = 256, value = 256)),
customColorsUI(id)
),
shinydashboard::menuItem("Heatmap Dendrogram",
selectInput(ns('dendrogram'),'Type',
choices = c("both", "row", "column", "none"),selected = 'both'),
selectizeInput(ns("seriation"), "Seriation",
c(OLO="OLO", GW="GW", Mean="mean", None="none"),selected = 'OLO'),
sliderInput(ns('branches_lwd'),'Branch Width',
value = 0.6,min=0,max=5,step = 0.1)
),
shinydashboard::menuItem("Heatmap Layout",
textInput(ns('main'),'Title',''),
textInput(ns('xlab'),'Sample label',''),
sliderInput(ns('row_text_angle'),'Sample Text Angle',
value = 0,min=0,max=180),
textInput(ns('ylab'), 'Gene/Region label',''),
sliderInput(ns('column_text_angle'),'Gene/Region Text Angle',
value = 45,min=0,max=180)
))
}
#' kmeansControlsUI
#'
#' get kmeans controls
#'
#' @note \code{kmeansControlsUI}
#' @param id, module ID
#' @return controls
#' @examples
#' x <- kmeansControlsUI("heatmap")
#' @export
#'
kmeansControlsUI <- function(id) {
ns <- NS(id)
shinydashboard::menuItem("kmeans",
checkboxInput(ns('kmeansControl'), 'kmeans clustering', value = FALSE),
conditionalPanel(paste0("input['", ns("kmeansControl"), "']"),
sliderInput(ns("knum"), "k: # of Clusters",
min = 2, max = 20, value = 2),
selectizeInput(ns("kmeansalgo"), "kmeans.algorithm",
c("Hartigan-Wong", "Lloyd", "Forgy",
"MacQueen"), selected = 'Lloyd'),
textInput(ns('clusterorder'),
'The order of the clusters', ""),
actionButton(ns("changeOrder"), label = "Change Order", styleclass = "primary"),
checkboxInput(ns('showClasses'), 'Show Classes', value = FALSE)))
}
#' dendControlsUI
#'
#' get distance metric parameters
#'
#' @note \code{dendControlsUI}
#' @param id, module ID
#' @param dendtype, Row or Col
#' @return controls
#' @examples
#' x <- dendControlsUI("heatmap")
#' @export
#'
dendControlsUI <- function(id, dendtype = "Row") {
ns <- NS(id)
shinydashboard::menuItem(paste0(dendtype, " dendrogram"),
selectizeInput(ns(paste0("distFun_", dendtype)), "Dist. method",
distFunParamsUI(),
selected = 'euclidean'),
selectizeInput(ns(paste0("hclustFun_", dendtype)), "Clustering linkage",
clustFunParamsUI(),
selected = 'complete'),
sliderInput(ns(paste0("k_", dendtype)), "# of Clusters",
min = 1, max = 10, value = 2),
checkboxInput(ns(paste0('lab',dendtype)), paste0(dendtype, ' Labels'), value = TRUE))
}
#' clustFunParamsUI
#'
#' get cluster function parameter control
#'
#' @note \code{clustFunParamsUI}
#' @return cluster params
#' @examples
#' x <- clustFunParamsUI()
#' @export
#'
clustFunParamsUI <- function() {
c(Complete= "complete",Single= "single",Average= "average",
Mcquitty= "mcquitty",Median= "median",Centroid= "centroid",
Ward.D= "ward.D",Ward.D2= "ward.D2")
}
#' distFunParamsUI
#'
#' get distance metric parameters
#'
#' @note \code{distFunParamsUI}
#' @return funParams
#' @examples
#' x <- distFunParamsUI()
#' @export
#'
distFunParamsUI <- function() {
c(Cor="cor", Euclidean="euclidean",Maximum='maximum',
Manhattan='manhattan',Canberra='canberra',
Binary='binary',Minkowski='minkowski')
}
#' palUI
#'
#' get pallete
#'
#' @note \code{palUI}
#' @param id, namespace ID
#' @return pals
#' @examples
#' x <- palUI("heatmap")
#' @export
#'
palUI <- function(id) {
ns <- NS(id)
colSel='RdBu'
selectizeInput(inputId = ns("pal"),
label ="Select Color Palette",
choices = c('RdBu' = 'RdBu',
'BlueRed' = 'bluered',
'RedBlue' = 'redblue',
'RdYlBu' = 'RdYlBu',
'RdYlGn' = 'RdYlGn',
'BrBG' = 'BrBG',
'Spectral' = 'Spectral',
'BuGn' = 'BuGn',
'PuBuGn' = 'PuBuGn',
'YlOrRd' = 'YlOrRd',
'Heat' = 'heat.colors',
'Grey' = 'grey.colors'),
selected=colSel)
}
#' customColorsUI
#'
#' get Custom Color controls
#'
#' @note \code{getColRng}
#' @param id, namespace ID
#' @return color range
#' @examples
#' x <- customColorsUI("heatmap")
#' @export
#'
customColorsUI <- function(id) {
ns <- NS(id)
list(
checkboxInput(ns('customColors'), 'Custom Colors', value = FALSE),
conditionalPanel(paste0("input['", ns("customColors"), "']"),
colourpicker::colourInput(ns("color1"), "Choose min colour", "blue"),
colourpicker::colourInput(ns("color2"), "Choose median colour", "white"),
colourpicker::colourInput(ns("color3"), "Choose max colour", "red")))
}
#' prepHeatData
#'
#' scales the data
#'
#' @param data, a matrixthat includes expression values
#' @return heatdata
#'
#' @examples
#' x <- prepHeatData(mtcars)
#'
#' @export
#'
prepHeatData <- function(data = NULL)
{
if(is.null(data)) return(NULL)
ld <- data
#ld <- log2(data + 0.1)
cldt <- scale(t(ld), center = TRUE, scale = TRUE)
cld <- t(cldt)
return(cld)
}
#' getSelHeat
#'
#' heatmap selection functionality
#'
#' @param data, selected genes
#' @param input, input params
#' @return plot
#' @export
#'
#' @examples
#' x <- getSelHeat()
#'
getSelHeat <- function(data = NULL, input = NULL) {
if (is.null(input)) return(NULL)
getSelected <- reactive({
data[unlist(strsplit(input, ",")), ]
})
list( getSelected = isolate(getSelected) )
}
#' heatmapJScode
#'
#' heatmap JS code for selection functionality
#'
#' @return JS Code
#' @export
#'
#' @examples
#' x <- heatmapJScode()
#'
heatmapJScode <- function() {
'shinyjs.getHoverName = function(params){
var defaultParams = {
controlname : "hoveredgenename"
};
params = shinyjs.getParams(params, defaultParams);
console.log(params.controlname)
var out = ""
if (typeof document.getElementsByClassName("nums")[0] != "undefined"){
if (typeof document.getElementsByClassName("nums")[0].querySelectorAll("tspan.line")[0] != "undefined"){
out = document.getElementsByClassName("nums")[0].querySelectorAll("tspan.line")[0].innerHTML.match("row: (.*)")[1]
$("#heatmap-heatmap").attr("gname", out)
}
}
Shiny.onInputChange(params.controlname, $("#heatmap-heatmap").attr("gname"));
}
shinyjs.getSelectedGenes = function(params){
var defaultParams = {
plotId : "heatmap",
controlname : "selgenenames"
};
params = shinyjs.getParams(params, defaultParams);
var count = document.getElementById(params.plotId).querySelectorAll("g.y2tick").length
var start = 0
var out = ""
for (i = start; i < count; i++)
{
if (typeof document.getElementById(params.plotId).querySelectorAll("g.y2tick")[i] != "undefined"){
out += document.getElementById(params.plotId).querySelectorAll("g.y2tick")[i].innerHTML.match(">(.*)</text>")[1] + ","
}
}
Shiny.onInputChange(params.controlname, out);
}'
}
#' getJSLine
#'
#' heatmap JS code for selection functionality
#'
#' @return JS Code
#' @export
#'
#' @examples
#' x <- getJSLine()
#'
getJSLine <-function()
{
list(shinyjs::useShinyjs(),
shinyjs::extendShinyjs(text = heatmapJScode(), functions = c("getHoverName", "getSelectedGenes")))
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.