rshinyd3heatmapggiraph

R Shiny ggiraph and d3heatmap Compatibility Issues


I'm trying to add an interactive heatmap to my Shiny app, but I also have interactive graphs using ggiraph. I'm currently using the d3heatmap package, but the heatmaps don't render in the app. I've created a toy example to illustrate this:

library(shiny)
library(ggiraph)
library(d3heatmap)

ui <- fluidPage(
    d3heatmapOutput('d3'),
    ggiraphOutput('gg')
)

server <- function(input, output, session) {

    # Create heatmap
    output$d3 <- renderD3heatmap({
        d3heatmap(matrix(1:100, nrow = 100, ncol = 100))
    })

    # Create ggiraph
    output$gg <- renderggiraph({
        p <- ggplot(iris, aes(x = Sepal.Length, y = Petal.Width,
                              color = Species, tooltip = iris$Species) ) +
             geom_point_interactive()

        ggiraph(code = {print(p)})
    })
}

shinyApp(ui =  ui, server = server)

Together, only the ggiraph renders, but the heatmap does not. However, if you comment out the ggiraph code, the heatmap renders. I tried switching the order of loading the packages, but that still didn't work.

I'm currently running on R 3.2.2 (I have to use this version because the company servers only run on this version, and neither my manager nor I have the authority to update it). I tried downloading the shinyheatmap, heatmaply, and heatmap.2 packages, but because of versioning issues, the installations were unsuccessful.

So right now, I've just used pheatmap to create the heatmaps, but they aren't interactive (i.e., I can't get values when I hover over individual cells, and I can't zoom in). Is there any workaround for this, or are there other interactive heatmap packages out there that would work? I'd like to avoid changing all of my ggiraph graphs to plotly graphs since there are a lot of them in my code.

Please let me know if there's any other information you need. Any suggestions would be much appreciated!


Solution

  • (just to let you know I am the author of ggiraph) There is a conflict between ggiraph and d3heatmap because ggiraph is using d3.js version 4 and d3heatmap is using D3.js version 3. I don't think there is a solution to solve that conflict.

    However, building an interactive heatmap with ggplot2/ggiraph is not that difficult. See below:

    library(dplyr)
    library(tidyr)
    library(ggplot2)
    library(ggiraph)
    library(ggdendro)
    
    
    # mydata <- cor(mtcars)
    mydata <- matrix(runif(2500, min = -2, max = 2), ncol = 50)
    row.names(mydata) <- paste0("row_", seq_len(nrow(mydata)))
    colnames(mydata) <- paste0("col_", seq_len(ncol(mydata)))
    
    # dendrogram for rows
    hc <- hclust(dist(mydata), "ave")
    dhr <- as.dendrogram(hc)
    order_r <- rownames(mydata)[hc$order]
    
    # dendrogram for columns
    hc <- hclust(dist(t(mydata)), "ave")
    dhc <- as.dendrogram(hc)
    order_c <- colnames(mydata)[hc$order]
    
    # the data
    expr_set <- bind_cols(
      data_frame(rowvar = rownames(mydata)),
      as.data.frame(mydata)
    )
    expr_set <- gather(expr_set, colvar, measure, -rowvar)
    expr_set$rowvar <- factor( expr_set$rowvar, levels = order_r )
    expr_set$colvar <- factor( expr_set$colvar, levels = order_c )
    expr_set <- arrange(expr_set, rowvar, colvar)
    
    # get data for dendrograms - IMHO, ggdendro is the hero here...
    data_c <- dendro_data(dhc, type = "rectangle")
    data_c <- segment(data_c) %>% mutate(
      y = y + length(order_r) + .5,
      yend = yend + length(order_r) + .5
    )
    
    data_r <- dendro_data(dhr, type = "rectangle")
    data_r <- segment(data_r)
    data_r <- data_r %>%
      mutate( x_ = y + length(order_c) + .5,
              xend_ = yend + length(order_c) + .5,
              y_ = x,
              yend_ = xend )
    
    expr_set <- expr_set %>% 
      mutate( 
        tooltip = sprintf("Row: %s<br/>Col: %s<br/>measure: %.02f", 
                          rowvar, colvar, measure) ,
        data_id = sprintf("%s_%s", rowvar, colvar)
        )
    
    
    # all data are tidy and can be now used with ggplot
    p <- ggplot(data = expr_set, aes(x = colvar, y = rowvar) ) +
      geom_tile_interactive(aes(fill = measure, tooltip = tooltip, data_id = data_id), colour = "white") +
      scale_fill_gradient(low = "white", high = "#BC120A") +
      geom_segment(
        data = data_c,
        mapping = aes(x = x, y = yend, xend = xend, yend = y),
        colour = "gray20", size = .2) +
      geom_segment(
        data = data_r,
        mapping = aes(x = x_, y = y_, xend = xend_, yend = yend_),
        colour = "gray20", size = .2) +
      coord_equal()
    
    # cosmetics
    p <- p + theme_minimal() +
      theme(
        legend.position = "right",
        panel.grid.minor = element_line(color = "transparent"),
        panel.grid.major = element_line(color = "transparent"),
        axis.ticks.length   = unit(2, units = "mm"),
        plot.title = element_text(face = "bold", hjust = 0.5, size = 12),
        axis.title = element_text(size = 9, colour = "gray30"),
        axis.text.y = element_text(hjust = 1, size = 5, colour = "gray40"),
        axis.text.x = element_text(angle = 90, hjust = 1, size = 5, colour = "gray40"),
        legend.title=element_text(face = "bold", hjust = 0.5, size=8),
        legend.text=element_text(size=6)
      )
    
    
    
    ggiraph(ggobj = p)
    

    enter image description here

    Hope it helps