ropensci / iheatmapr

Complex, interactive heatmaps in R
https://docs.ropensci.org/iheatmapr
Other
267 stars 35 forks source link

Question: How to add independent plotly panel as subplot #52

Open rfenouil opened 4 years ago

rfenouil commented 4 years ago

Hello, first of all thank you for the great work, super powerful library and very nicely built.

On top of my heatmap, I would like to add a stacked barplot summarizing stats (average value) for groups of columns (each bar spanning all columns of the group), and rows groups at the same time (stacked bars).

Why do I need that ?
I have a lot of columns (~2k) and while using add_col_summary(groups = TRUE) covers my need, it is cluttered by too many points on 'x' axis and overlapping traces. I think a stacked barplot for each group of columns would do better in this case.

I played with add_subplot() and add_col_barplot() but if I did not manage to do what I want.

With add_subplot:

With add_col_barplot:

Using add_col_barplot, if stacking is possible one solution would be to use a bar for each column (all bars in a group of columns would be similar) but I guess it would be suboptimal (lot of columns).

I managed to generate the barplot as a separate plotly panel but I cannot find a proper way to integrate it on top of the heatmap. Is there any way to integrate an independent plotly panel somewhere around the heatmap ?

I thought I could use the plotly subplot function (with shareX=TRUE) to group the heatmap and my plot but it seems that your library does not depend on plotly R functions so I am not sure if this is possible at all.

Could you point me to the best approach for this situation ?

Thank you very much.

rfenouil commented 4 years ago

If that can help, here is a small example of what I would like to achieve.

#### Create a heatmap

# Generate artificial data and groups
myMat = matrix( runif( 1000), ncol = 100)
rowsGroups = list( rowsGrouping = factor( paste0( "rowsGrp_", rep( LETTERS[1:( nrow( myMat)/2)], each = 2))))
colsGroups = list( colsGrouping = factor( paste0( "colsGrp_", rep( 1:4, c( 10, 20, 30, 40)))))

# Show the base heatmap
iheatmap( myMat,
          row_labels = TRUE, 
          col_labels = TRUE, 
          row_annotation = rowsGroups, 
          col_annotation = colsGroups)

#### Create stacked barplots summarizing stats for subgroups

# Let's use fake stats for rows and columns subgroups (computation is out of topic, ask if needed)
statSummary = matrix( runif( nlevels( rowsGroups[[1]]) * nlevels( colsGroups[[1]])), ncol = nlevels( colsGroups[[1]]))
rownames( statSummary) = levels( rowsGroups[[1]])
colnames( statSummary) = levels( colsGroups[[1]])

# Melt for plotly grouping
moltenSummary = data.table::melt( statSummary, varnames = c( "rowsGroups", "colsGroups"))
# Use columns group factor for computing bars 'x' coordinates (centered with columns groups)
nbColsByGrp = table( colsGroups[[1]])
xCoordBars = cumsum( nbColsByGrp) - ( nbColsByGrp/2)
# Add 'x' coordinates and number of columns (for bar width) to summaryStat
moltenSummary = cbind( moltenSummary, cbind( nbColsByGrp, xCoordBars)[moltenSummary[["colsGroups"]],], row.names = NULL)

# What I would like to put on top of the heatmap (with stack colors matched to rows groups)
plot_ly( data = moltenSummary, x = ~xCoordBars, y = ~value, color = ~rowsGroups) %>%
  add_trace( type = "bar", width = ~nbColsByGrp-1) %>%
  layout( barmode = "stack")
rfenouil commented 4 years ago

Using add_subplot, I tried the following (ignoring bar width for now) but I probably misunderstood something:

iheatmap( myMat,
          row_labels = TRUE, 
          col_labels = TRUE, 
          row_annotation = rowsGroups, 
          col_annotation = colsGroups) %>%
  add_subplot( side = "top", 
               size = 0.2, 
               data = moltenSummary, 
               x = ~xCoordBars, 
               y = ~value, 
               color = ~rowsGroups, 
               type = "bar", 
               layout = list( barmode = "stack"))