3

I am using the UpSet function from the ComplexHeatmap package and I am trying to add annotation to the graph. In the really good how-to, they describe the extra step to plot the counts next to the bars, and they also explain, why they separate this function.

So a minimum example from the documentation looks like this (it is the smallest example I could find):

library(ComplexHeatmap)
movies = read.csv(system.file("extdata", "movies.csv", package = "UpSetR"), 
                  header = TRUE, sep = ";")

m = make_comb_mat(movies, top_n_sets = 6)

m = m[comb_degree(m) > 0]

ss = set_size(m)
cs = comb_size(m)
ht = UpSet(m, 
           set_order = order(ss),
           comb_order = order(comb_degree(m), -cs),
           top_annotation = HeatmapAnnotation(
             "Genre Intersections" = anno_barplot(cs, 
                                                  ylim = c(0, max(cs)*1.1),
                                                  border = FALSE, 
                                                  gp = gpar(fill = "black"), 
                                                  height = unit(4, "cm")
             ), 
             annotation_name_side = "left", 
             annotation_name_rot = 90),
           left_annotation = rowAnnotation(
             "Movies Per Genre" = anno_barplot(-ss, 
                                               baseline = 0,
                                               axis_param = list(
                                                 at = c(0, -500, -1000, -1500),
                                                 labels = c(0, 500, 1000, 1500),
                                                 labels_rot = 0),
                                               border = FALSE, 
                                               gp = gpar(fill = "black"), 
                                               width = unit(4, "cm")
             ),
             set_name = anno_text(set_name(m), 
                                  location = 0.5, 
                                  just = "center",
                                  width = max_text_width(set_name(m)) + unit(4, "mm"))
           ), 
           right_annotation = NULL,
           show_row_names = FALSE)
ht = draw(ht)
od = column_order(ht)
decorate_annotation("Genre Intersections", {
  grid.text(cs[od], x = seq_along(cs), y = unit(cs[od], "native") + unit(2, "pt"), 
            default.units = "native", just = c("left", "bottom"), 
            gp = gpar(fontsize = 6, col = "#404040"), rot = 45)
})

With this last function decorate_annotation we add the numbers to the already drawn plot and everything is fine.

But, when I want to compare for example 5 plots and I join them via %v% vertically together, how can I add the decorate_annotation to ALL of the plots? Here the example code:

genre = c("Action", "Romance", "Horror", "Children", "SciFi", "Documentary")
rating = cut(movies$AvgRating, c(0, 1, 2, 3, 4, 5))
m_list = tapply(seq_len(nrow(movies)), rating, function(ind) {
  m = make_comb_mat(movies[ind, genre, drop = FALSE])
  m[comb_degree(m) > 0]
})
m_list = normalize_comb_mat(m_list)

max_set_size = max(sapply(m_list, set_size))
max_comb_size = max(sapply(m_list, comb_size))


ht_list = NULL
for(i in seq_along(m_list)) {
  ht_list = ht_list %v%
    UpSet(m_list[[i]], row_title = paste0("rating in", names(m_list)[i]),
          set_order = NULL, comb_order = NULL,
          top_annotation = upset_top_annotation(m_list[[i]], ylim = c(0, max_comb_size)),
          right_annotation = upset_right_annotation(m_list[[i]], ylim = c(0, max_set_size)))
}
ht_list

Has somebody added the annotation to it already?

halfer
  • 19,824
  • 17
  • 99
  • 186
drmariod
  • 11,106
  • 16
  • 64
  • 110

1 Answers1

1

The solution shown below is based on the command as.ggplot of the ggplotify package. A function plot_upset is first defined; it draws an upset plot with decorated heatmap annotation. The plot generated by this function is converted in a ggplot object by as.ggplotand stored in ht_list.

library(ComplexHeatmap)
library(patchwork)
library(ggplotify)

movies <- read.csv(system.file("extdata", "movies.csv", package = "UpSetR"), 
                   header = TRUE, sep = ";")

genre <- c("Action", "Romance", "Horror", "Children", "SciFi", "Documentary")
rating <- cut(movies$AvgRating, c(0, 1, 2, 3, 4, 5))
m_list <- tapply(seq_len(nrow(movies)), rating, function(ind) {
  m <- make_comb_mat(movies[ind, genre, drop = FALSE])
  m[comb_degree(m) > 0]
})
m_list <- normalize_comb_mat(m_list)

max_set_size <- max(sapply(m_list, set_size))

plot_upset <- function(m, name, maxSetSize) {
  cs = comb_size(m)  
  ht <- UpSet(m, row_title = paste0("rating in", name),
              set_order = NULL, comb_order = NULL,
              top_annotation = HeatmapAnnotation(
                "Genre Intersections" = anno_barplot(cs, 
                                                     ylim = c(0, max(cs)*1.1),
                                                     border = FALSE, 
                                                     gp = gpar(fill = "black"), 
                                                     height = unit(4, "cm")
                ),
                annotation_name_side = "left", 
                annotation_name_rot = 90),
              right_annotation = upset_right_annotation(m, ylim = c(0, maxSetSize)))
  ht = draw(ht)
  od = column_order(ht)
  decorate_annotation("Genre Intersections", {
    grid.text(cs[od], x = seq_along(cs), y = unit(cs[od], "native") + unit(2, "pt"), 
              default.units = "native", just = c("left", "bottom"), 
              gp = gpar(fontsize = 6, col = "#404040"), rot = 45)
  })
}

ht_list <- vector(2, mode="list")
for(i in seq_along(m_list)) {
  m <- m_list[[i]]
  name_m <- names(m_list)[i]
  dht <- as.ggplot( ~ plot_upset(m, name_m, max_set_size))
  ht_list[[i]] <- dht
} 
patchwork::wrap_plots(ht_list, ncol=1)

Here is the final plot (only 3 of the 5 plots are reported). enter image description here

Marco Sandri
  • 23,289
  • 7
  • 54
  • 58