Browse code

Added the ability to return a list of heatmaps to 'moduleHeatmap'. This made the generation of module heatmaps in the report much quicker as the data does not have to be renormalized each time

Joshua D. Campbell authored on 26/09/2021 18:26:49
Showing 3 changed files

... ...
@@ -16,9 +16,11 @@
16 16
 #'  \linkS4class{SingleCellExperiment} object. Default "counts".
17 17
 #' @param altExpName The name for the \link{altExp} slot
18 18
 #'  to use. Default "featureSubset".
19
-#' @param featureModule Integer Vector. The featureModule(s) to display.
19
+#' @param modules Integer Vector. The featureModule(s) to display.
20 20
 #'  Multiple modules can be included in a vector. Default \code{NULL} which
21 21
 #'  plots all module heatmaps.
22
+#' @param featureModule Same as \code{modules}. Either can be used to specify
23
+#' the modules to display. 
22 24
 #' @param col Passed to \link[ComplexHeatmap]{Heatmap}. Set color boundaries
23 25
 #'  and colors.
24 26
 #' @param topCells Integer. Number of cells with the highest and lowest
... ...
@@ -100,6 +102,9 @@
100 102
 #' and reduced the memory of the plot and the size of a file. If \code{NULL},
101 103
 #' then rasterization will be automatically determined by the underlying
102 104
 #' \link[ComplexHeatmap]{Heatmap} function. Default \code{TRUE}.
105
+#' @param returnAsList Boolean. If \code{TRUE}, then a list of plots will be
106
+#' returned instead of a single multi-panel figure. These plots can be 
107
+#' displayed using the \link[grid]{grid.draw} function. Default \code{FALSE}.
103 108
 #' @param ... Additional parameters passed to \link[ComplexHeatmap]{Heatmap}.
104 109
 #' @return A \link[multipanelfigure]{multi_panel_figure} object if plotting
105 110
 #'  more than one module heatmaps. Otherwise a
... ...
@@ -111,6 +116,7 @@ setGeneric("moduleHeatmap",
111 116
     function(x,
112 117
         useAssay = "counts",
113 118
         altExpName = "featureSubset",
119
+        modules = NULL,        
114 120
         featureModule = NULL,
115 121
         col = circlize::colorRamp2(c(-2, 0, 2),
116 122
             c("#1E90FF", "#FFFFFF", "#CD2626")),
... ...
@@ -136,6 +142,7 @@ setGeneric("moduleHeatmap",
136 142
         unit = "mm",
137 143
         ncol = NULL,
138 144
         useRaster = TRUE,
145
+        returnAsList = FALSE,
139 146
         ...) {
140 147
     standardGeneric("moduleHeatmap")})
141 148
 
... ...
@@ -151,6 +158,7 @@ setMethod("moduleHeatmap",
151 158
     function(x,
152 159
         useAssay = "counts",
153 160
         altExpName = "featureSubset",
161
+        modules = NULL,
154 162
         featureModule = NULL,
155 163
         col = circlize::colorRamp2(c(-2, 0, 2),
156 164
             c("#1E90FF", "#FFFFFF", "#CD2626")),
... ...
@@ -176,8 +184,15 @@ setMethod("moduleHeatmap",
176 184
         unit = "mm",
177 185
         ncol = NULL,
178 186
         useRaster = TRUE,
187
+        returnAsList = FALSE,
179 188
         ...) {
180 189
 
190
+        # 'modules' is an easier parameter name to remember so we include 
191
+        # support for both. 
192
+        if(!is.null(modules)) {
193
+            featureModule <- modules
194
+        }
195
+        
181 196
         altExp <- SingleCellExperiment::altExp(x, altExpName)
182 197
 
183 198
         counts <- SummarizedExperiment::assay(altExp, i = useAssay)
... ...
@@ -212,6 +227,8 @@ setMethod("moduleHeatmap",
212 227
 
213 228
         if (moduleLabel == "auto") {
214 229
             moduleLabel <- paste0("Module ", as.character(featureModule))
230
+        } else if (length(moduleLabel) == 1 & length(featureModule) > 1) {
231
+            moduleLabel <- rep(moduleLabel, length(featureModule))
215 232
         } else if (length(moduleLabel) != length(featureModule)) {
216 233
             stop("Invalid 'moduleLabel' length")
217 234
         }
... ...
@@ -264,12 +281,20 @@ setMethod("moduleHeatmap",
264 281
 
265 282
         # Get max rowFontSize if multiple modules are selected
266 283
         if (is.null(rowFontSize)) {
267
-          if (length(featureIndices) > 1) {
284
+          if (length(featureIndices) > 1 & !isTRUE(returnAsList)) {
285
+            # If there is more than 1 module selected, then the miniumum size
286
+            # size will be caculated for each module. This will ensure that
287
+            # all modules will have the same rowFontSize and the module
288
+            # heatmaps will have the same width. 
268 289
             maxlen <- max(unlist(lapply(featureIndices, length)))
269 290
             maxlen <- maxlen * sqrt(length(featureIndices))
270
-            rowFontSize <- min(200 / maxlen, 20)
291
+            rowFontSize <- rep(min(200 / maxlen, 20), length(featureIndices))
271 292
           } else {
272
-            rowFontSize <- min(200 / length(featureIndices[[1]]), 20)
293
+            # If there is only one plot or each plot will be generated 
294
+            # separately and returned in a list, then the size of the labels,
295
+            # will be caculated for each module separately.
296
+            len <- unlist(lapply(featureIndices, length))
297
+            rowFontSize <- pmin(200 / len, 20)
273 298
           }
274 299
         }
275 300
 
... ...
@@ -288,7 +313,7 @@ setMethod("moduleHeatmap",
288 313
                 showFeatureNames = showFeatureNames,
289 314
                 displayNames = displayNames[featureIndices[[i]]],
290 315
                 trim = trim,
291
-                rowFontSize = rowFontSize,
316
+                rowFontSize = rowFontSize[i],
292 317
                 showHeatmapLegend = showHeatmapLegend,
293 318
                 showTopAnnotationLegend = showTopAnnotationLegend,
294 319
                 showTopAnnotationName = showTopAnnotationName,
... ...
@@ -315,17 +340,22 @@ setMethod("moduleHeatmap",
315 340
                     wrap.grobs = TRUE)
316 341
             }
317 342
 
318
-            figure <- multipanelfigure::multi_panel_figure(
319
-                columns = ncol,
320
-                rows = nrow,
321
-                width = width,
322
-                height = height,
323
-                unit = unit)
324
-
325
-            for (i in seq(length(plts))) {
326
-                figure <- suppressMessages(multipanelfigure::fill_panel(figure,
327
-                    plts[[i]], label = ""))
343
+            if(isTRUE(returnAsList)) {
344
+                figure <- plts    
345
+            } else {
346
+                figure <- multipanelfigure::multi_panel_figure(
347
+                    columns = ncol,
348
+                    rows = nrow,
349
+                    width = width,
350
+                    height = height,
351
+                    unit = unit)
352
+                
353
+                for (i in seq(length(plts))) {
354
+                    figure <- suppressMessages(multipanelfigure::fill_panel(figure,
355
+                                                                            plts[[i]], label = ""))
356
+                }
328 357
             }
358
+            
329 359
             suppressWarnings(return(figure))
330 360
         }
331 361
     }
... ...
@@ -410,6 +440,10 @@ setMethod("moduleHeatmap",
410 440
         } else {
411 441
             stop("'scaleRow' needs to be of class 'function'")
412 442
         }
443
+        # If the standard deviation was 0 then the values will be NA
444
+        # Replacing the NAs with zero will keep the row the middle color
445
+        # rather than grey (default with ComplexHeatmap)
446
+        filteredNormCounts[is.na(filteredNormCounts)] <- 0
413 447
     }
414 448
 
415 449
     if (!is.null(trim)) {
... ...
@@ -169,6 +169,23 @@ Celda performs bi-clustering of features into modules and cells into subpopulati
169 169
 Use the tabs to select modules ranging from 1 to `r L`. Module probabilities on the 2-D embedding are scaled to range between 0 and 1. Each column on the heatmap represents a cell and each row represents a feature. Expression values for each feature are z-scored normalized across all cells after normalization. Red represents higher relative expression and blue represents lower relative expression. All cells are shown in the heatmap on the left. Only the top 100 cells with the lowest module probability and the 100 cells with the highest module probability are shown in the heatmap on the right. The column color bar displays the population assignment for each cell. 
170 170
 
171 171
 ```{r celda_module_heatmaps, results = "asis", fig.height = 15, fig.width = 10}
172
+p2 <- moduleHeatmap(
173
+  sce,
174
+  topCells = NULL,
175
+  displayName = displayName,
176
+  moduleLabel = "All cells",
177
+  useRaster = TRUE,
178
+  returnAsList = TRUE
179
+)
180
+p3 <- moduleHeatmap(
181
+  sce,
182
+  topCells = 100,
183
+  displayName = displayName,
184
+  moduleLabel = "Top 100 cells",
185
+  useRaster = TRUE,
186
+  returnAsList = TRUE
187
+)
188
+
172 189
 fig.list <- list()
173 190
 for (i in seq_len(L)) {
174 191
   p1 <- plotDimReduceModule(
... ...
@@ -178,22 +195,22 @@ for (i in seq_len(L)) {
178 195
     altExpName = altExpName,
179 196
     modules = i
180 197
   )
181
-  p2 <- moduleHeatmap(
182
-    sce,
183
-    featureModule = i,
184
-    topCells = NULL,
185
-    displayName = displayName,
186
-    moduleLabel = "All cells",
187
-    useRaster = TRUE
188
-  )
189
-  p3 <- moduleHeatmap(
190
-    sce,
191
-    featureModule = i,
192
-    topCells = 100,
193
-    displayName = displayName,
194
-    moduleLabel = "Top 100 cells",
195
-    useRaster = TRUE
196
-  )
198
+  # p2 <- moduleHeatmap(
199
+  #   sce,
200
+  #   featureModule = i,
201
+  #   topCells = NULL,
202
+  #   displayName = displayName,
203
+  #   moduleLabel = "All cells",
204
+  #   useRaster = TRUE
205
+  # )
206
+  # p3 <- moduleHeatmap(
207
+  #   sce,
208
+  #   featureModule = i,
209
+  #   topCells = 100,
210
+  #   displayName = displayName,
211
+  #   moduleLabel = "Top 100 cells",
212
+  #   useRaster = TRUE
213
+  # )
197 214
 
198 215
   fig <- multi_panel_figure(rows = 2,
199 216
                             columns = 2,
... ...
@@ -205,12 +222,12 @@ for (i in seq_len(L)) {
205 222
                     column = 1:2,
206 223
                     label = "")
207 224
   fig <- fill_panel(fig,
208
-                    p2,
225
+                    p2[[i]],
209 226
                     row = 2,
210 227
                     column = 1,
211 228
                     label = "")
212 229
   fig <- fill_panel(fig,
213
-                    p3,
230
+                    p3[[i]],
214 231
                     row = 2,
215 232
                     column = 2,
216 233
                     label = "")
... ...
@@ -9,6 +9,7 @@ moduleHeatmap(
9 9
   x,
10 10
   useAssay = "counts",
11 11
   altExpName = "featureSubset",
12
+  modules = NULL,
12 13
   featureModule = NULL,
13 14
   col = circlize::colorRamp2(c(-2, 0, 2), c("#1E90FF", "#FFFFFF", "#CD2626")),
14 15
   topCells = 100,
... ...
@@ -33,6 +34,7 @@ moduleHeatmap(
33 34
   unit = "mm",
34 35
   ncol = NULL,
35 36
   useRaster = TRUE,
37
+  returnAsList = FALSE,
36 38
   ...
37 39
 )
38 40
 
... ...
@@ -40,6 +42,7 @@ moduleHeatmap(
40 42
   x,
41 43
   useAssay = "counts",
42 44
   altExpName = "featureSubset",
45
+  modules = NULL,
43 46
   featureModule = NULL,
44 47
   col = circlize::colorRamp2(c(-2, 0, 2), c("#1E90FF", "#FFFFFF", "#CD2626")),
45 48
   topCells = 100,
... ...
@@ -64,6 +67,7 @@ moduleHeatmap(
64 67
   unit = "mm",
65 68
   ncol = NULL,
66 69
   useRaster = TRUE,
70
+  returnAsList = FALSE,
67 71
   ...
68 72
 )
69 73
 }
... ...
@@ -81,10 +85,13 @@ slot to use if \code{x} is a
81 85
 \item{altExpName}{The name for the \link{altExp} slot
82 86
 to use. Default "featureSubset".}
83 87
 
84
-\item{featureModule}{Integer Vector. The featureModule(s) to display.
88
+\item{modules}{Integer Vector. The featureModule(s) to display.
85 89
 Multiple modules can be included in a vector. Default \code{NULL} which
86 90
 plots all module heatmaps.}
87 91
 
92
+\item{featureModule}{Same as \code{modules}. Either can be used to specify
93
+the modules to display.}
94
+
88 95
 \item{col}{Passed to \link[ComplexHeatmap]{Heatmap}. Set color boundaries
89 96
 and colors.}
90 97
 
... ...
@@ -189,6 +196,10 @@ and reduced the memory of the plot and the size of a file. If \code{NULL},
189 196
 then rasterization will be automatically determined by the underlying
190 197
 \link[ComplexHeatmap]{Heatmap} function. Default \code{TRUE}.}
191 198
 
199
+\item{returnAsList}{Boolean. If \code{TRUE}, then a list of plots will be
200
+returned instead of a single multi-panel figure. These plots can be 
201
+displayed using the \link[grid]{grid.draw} function. Default \code{FALSE}.}
202
+
192 203
 \item{...}{Additional parameters passed to \link[ComplexHeatmap]{Heatmap}.}
193 204
 }
194 205
 \value{