Commit id: 3981fe02c795578b6314576278486fa5f88be6b8
merge from bioconductor
Commit id: 6811bed29d478afac5e518d7ea40819f5c649212
change version number
Commit id: 4785016520655b11334a5ea701eeb0b93778f205
change default value when the matrix has zeor column
Commit id: cf793440d71a2170d50b00564b6464fa92fe650c
fixed documentations
Commit id: 2fd8ba9a0ebf38c86fbe4eed604d37851e9bd91f
fixed bug when the heatmap list only contains zero column matrix
git-svn-id: https://hedgehog.fhcrc.org/bioconductor/trunk/madman/Rpacks/ComplexHeatmap@102662 bc3139a8-67e5-0310-9ffc-ced21a209358
... | ... |
@@ -42,8 +42,10 @@ exportMethods(component_width) |
42 | 42 |
exportMethods(draw_heatmap_list) |
43 | 43 |
export(grid.dendrogram) |
44 | 44 |
export(dist2) |
45 |
+export(rowAnnotation) |
|
45 | 46 |
exportMethods(draw_heatmap_legend) |
46 | 47 |
exportMethods(add_heatmap) |
48 |
+export(columnAnnotation) |
|
47 | 49 |
export(anno_barplot) |
48 | 50 |
export(anno_density) |
49 | 51 |
|
... | ... |
@@ -1,7 +1,12 @@ |
1 |
-CHANGES IN VERSION 0.99.4 |
|
1 |
+CHANGES IN VERSION 1.1.1 |
|
2 | 2 |
|
3 | 3 |
* fixed a bug when setting `cluster_rows` to FALSE but still cluster |
4 | 4 |
on rows. |
5 |
+* add `rowAnnotation` and `columnAnnotation` functions |
|
6 |
+* add examples in the vignette |
|
7 |
+* No error if the heatmap list only contains zero-column matrix |
|
8 |
+ |
|
9 |
+================================================= |
|
5 | 10 |
|
6 | 11 |
CHANGES IN VERSION 0.99.2 |
7 | 12 |
|
... | ... |
@@ -228,6 +228,7 @@ Heatmap = function(matrix, col, name, rect_gp = gpar(col = NA), |
228 | 228 |
|
229 | 229 |
if(ncol(matrix) == 0) { |
230 | 230 |
.Object@heatmap_param$show_heatmap_legend = FALSE |
231 |
+ .Object@heatmap_param$width = unit(0, "null") |
|
231 | 232 |
} |
232 | 233 |
|
233 | 234 |
if(is.character(matrix) || ncol(matrix) <= 1) { |
... | ... |
@@ -24,7 +24,8 @@ HeatmapAnnotation = setClass("HeatmapAnnotation", |
24 | 24 |
anno_list = "list", # a list of `SingleAnnotation` objects |
25 | 25 |
anno_size = "ANY", |
26 | 26 |
which = "character", |
27 |
- size = "ANY" # only for consistent of Heatmap |
|
27 |
+ size = "ANY", # only for consistent of Heatmap |
|
28 |
+ gap = "ANY" |
|
28 | 29 |
), |
29 | 30 |
prototype = list( |
30 | 31 |
anno_list = list(), |
... | ... |
@@ -47,8 +48,9 @@ HeatmapAnnotation = setClass("HeatmapAnnotation", |
47 | 48 |
# -annotation_height height of each annotation if annotations are column annotations. |
48 | 49 |
# -annotation_width width of each annotation if annotations are row annotations. |
49 | 50 |
# -height not using currently. |
50 |
-# -width width of the whole heatmap annotations, only used for column annotation when appending to the list of heatmaps. |
|
51 |
+# -width width of the whole heatmap annotations, only used for row annotation when appending to the list of heatmaps. |
|
51 | 52 |
# -gp graphic parameters for simple annotations. |
53 |
+# -gap gap between each annotation |
|
52 | 54 |
# |
53 | 55 |
# == details |
54 | 56 |
# The simple annotations are defined by ``df`` and ``col`` arguments. Complex annotations are |
... | ... |
@@ -57,12 +59,16 @@ HeatmapAnnotation = setClass("HeatmapAnnotation", |
57 | 59 |
# == value |
58 | 60 |
# A `HeatmapAnnotation-class` object. |
59 | 61 |
# |
62 |
+# == seealso |
|
63 |
+# There are two shortcut functions: `rowAnnotation` and `columnAnnotation`. |
|
64 |
+# |
|
60 | 65 |
# == author |
61 | 66 |
# Zuguang Gu <z.gu@dkfz.de> |
62 | 67 |
# |
63 | 68 |
HeatmapAnnotation = function(df, name, col, show_legend, ..., |
64 | 69 |
which = c("column", "row"), annotation_height = 1, annotation_width = 1, |
65 |
- height = unit(1, "cm"), width = unit(1, "cm"), gp = gpar(col = NA)) { |
|
70 |
+ height = unit(1, "cm"), width = unit(1, "cm"), gp = gpar(col = NA), |
|
71 |
+ gap = unit(0, "null")) { |
|
66 | 72 |
|
67 | 73 |
.Object = new("HeatmapAnnotation") |
68 | 74 |
|
... | ... |
@@ -139,7 +145,7 @@ HeatmapAnnotation = function(df, name, col, show_legend, ..., |
139 | 145 |
} |
140 | 146 |
|
141 | 147 |
if(!is.unit(anno_size)) { |
142 |
- anno_size = unit(anno_size/sum(anno_size), "npc") |
|
148 |
+ anno_size = unit(anno_size/sum(anno_size), "null") |
|
143 | 149 |
} |
144 | 150 |
|
145 | 151 |
|
... | ... |
@@ -153,9 +159,63 @@ HeatmapAnnotation = function(df, name, col, show_legend, ..., |
153 | 159 |
|
154 | 160 |
.Object@size = size |
155 | 161 |
|
162 |
+ if(is.null(gap)) gap = unit(0, "null") |
|
163 |
+ |
|
164 |
+ if(length(gap) == 1) { |
|
165 |
+ .Object@gap = rep(gap, n_anno) |
|
166 |
+ } else if(length(gap) == n_anno - 1) { |
|
167 |
+ .Object@gap = unit.c(gap, unit(0, "null")) |
|
168 |
+ } else if(length(gap) < n_anno - 1) { |
|
169 |
+ stop("Length of `gap` is wrong.") |
|
170 |
+ } else { |
|
171 |
+ .Object@gap = gap |
|
172 |
+ } |
|
173 |
+ |
|
156 | 174 |
return(.Object) |
157 | 175 |
} |
158 | 176 |
|
177 |
+# == title |
|
178 |
+# Construct row annotations |
|
179 |
+# |
|
180 |
+# == param |
|
181 |
+# -... pass to `HeatmapAnnotation` |
|
182 |
+# |
|
183 |
+# == details |
|
184 |
+# The function is identical to |
|
185 |
+# |
|
186 |
+# HeatmapAnnotation(..., which = "row") |
|
187 |
+# |
|
188 |
+# == value |
|
189 |
+# A `HeatmapAnnotation-class` object. |
|
190 |
+# |
|
191 |
+# == author |
|
192 |
+# Zuguang Gu <z.gu@dkfz.de> |
|
193 |
+# |
|
194 |
+rowAnnotation = function(...) { |
|
195 |
+ HeatmapAnnotation(..., which = "row") |
|
196 |
+} |
|
197 |
+ |
|
198 |
+# == title |
|
199 |
+# Construct column annotations |
|
200 |
+# |
|
201 |
+# == param |
|
202 |
+# -... pass to `HeatmapAnnotation` |
|
203 |
+# |
|
204 |
+# == details |
|
205 |
+# The function is identical to |
|
206 |
+# |
|
207 |
+# HeatmapAnnotation(..., which = "column") |
|
208 |
+# |
|
209 |
+# == value |
|
210 |
+# A `HeatmapAnnotation-class` object. |
|
211 |
+# |
|
212 |
+# == author |
|
213 |
+# Zuguang Gu <z.gu@dkfz.de> |
|
214 |
+# |
|
215 |
+columnAnnotation = function(...) { |
|
216 |
+ HeatmapAnnotation(..., which = "column") |
|
217 |
+} |
|
218 |
+ |
|
159 | 219 |
# == title |
160 | 220 |
# Get a list of color mapping objects |
161 | 221 |
# |
... | ... |
@@ -210,13 +270,14 @@ setMethod(f = "draw", |
210 | 270 |
which = object@which |
211 | 271 |
n_anno = length(object@anno_list) |
212 | 272 |
anno_size = object@anno_size |
273 |
+ gap = object@gap |
|
213 | 274 |
|
214 | 275 |
pushViewport(viewport(...)) |
215 | 276 |
for(i in seq_len(n_anno)) { |
216 | 277 |
if(which == "column") { |
217 |
- pushViewport(viewport(y = sum(anno_size[seq_len(i)]), height = anno_size[i], just = c("center", "top"))) |
|
278 |
+ pushViewport(viewport(y = sum(anno_size[seq_len(i)]) + sum(gap[seq_len(i)]) - gap[i], height = anno_size[i], just = c("center", "top"))) |
|
218 | 279 |
} else { |
219 |
- pushViewport(viewport(x = sum(anno_size[seq_len(i)]), width = anno_size[i], just = c("right", "center"))) |
|
280 |
+ pushViewport(viewport(x = sum(anno_size[seq_len(i)]) + sum(gap[seq_len(i)]) - gap[i], width = anno_size[i], just = c("right", "center"))) |
|
220 | 281 |
} |
221 | 282 |
draw(object@anno_list[[i]], index) |
222 | 283 |
upViewport() |
... | ... |
@@ -668,8 +668,30 @@ setMethod(f = "draw_heatmap_list", |
668 | 668 |
|
669 | 669 |
gap = object@ht_list_param$gap |
670 | 670 |
ht_index = which(sapply(object@ht_list, inherits, "Heatmap")) |
671 |
- |
|
672 | 671 |
n = length(object@ht_list) |
672 |
+ |
|
673 |
+ # if there is only one heatmap but with zero column, width for one |
|
674 |
+ # row annotations is allowed to have no width set |
|
675 |
+ if(length(ht_index) == 1) { |
|
676 |
+ ht = object@ht_list[[ht_index]] |
|
677 |
+ i_row_anno_nofix_width = which(sapply(object@ht_list, function(ht) { |
|
678 |
+ if(inherits(ht, "Heatmap")) { |
|
679 |
+ return(FALSE) |
|
680 |
+ } else { |
|
681 |
+ return(is.null(ht@size)) |
|
682 |
+ } |
|
683 |
+ })) |
|
684 |
+ i_row_anno_fix_width = setdiff(seq_len(n), c(i_row_anno_nofix_width, ht_index)) |
|
685 |
+ if(!is.null(ht@heatmap_param$width) && length(i_row_anno_nofix_width) == 1) { |
|
686 |
+ if(length(i_row_anno_fix_width)) { |
|
687 |
+ row_anno_fix_width = sum(do.call("unit.c", lapply(object@ht_list[i_row_anno_fix_width], function(x) x@size))) |
|
688 |
+ } else { |
|
689 |
+ row_anno_fix_width = unit(0, "null") |
|
690 |
+ } |
|
691 |
+ object@ht_list[[i_row_anno_nofix_width]]@size = unit(1, "npc") - ht@heatmap_param$width - row_anno_fix_width - sum(gap) + gap[length(gap)] |
|
692 |
+ } |
|
693 |
+ } |
|
694 |
+ |
|
673 | 695 |
# since each heatmap actually has nine rows, calculate the maximum height of corresponding rows in all heatmap |
674 | 696 |
max_component_height = unit.c( |
675 | 697 |
max(do.call("unit.c", lapply(object@ht_list[ht_index], function(ht) component_height(ht, k = 1)))), |
... | ... |
@@ -730,13 +752,17 @@ setMethod(f = "draw_heatmap_list", |
730 | 752 |
}) |
731 | 753 |
heatmap_fixed_width = do.call("unit.c", heatmap_fixed_width) |
732 | 754 |
# width for body for each heatmap |
733 |
- heatmap_body_width = (unit(1, "npc") - sum(width_without_heatmap_body) - sum(heatmap_fixed_width) - sum(gap) + gap[length(gap)]) * (1/sum(heatmap_ncol)) * heatmap_ncol |
|
755 |
+ if(sum(heatmap_ncol) == 0) { |
|
756 |
+ heatmap_nofixed_width = unit(rep(0, n), "null") |
|
757 |
+ } else { |
|
758 |
+ heatmap_nofixed_width = (unit(1, "npc") - sum(width_without_heatmap_body) - sum(heatmap_fixed_width) - sum(gap) + gap[length(gap)]) * (1/sum(heatmap_ncol)) * heatmap_ncol |
|
759 |
+ } |
|
734 | 760 |
|
735 | 761 |
# width of heatmap including body, and other components |
736 | 762 |
# width without fixed width |
737 |
- heatmap_width = sum(width_without_heatmap_body[1:3]) + heatmap_body_width[1] + sum(width_without_heatmap_body[5:7-1]) |
|
763 |
+ heatmap_width = sum(width_without_heatmap_body[1:3]) + heatmap_nofixed_width[1] + sum(width_without_heatmap_body[5:7-1]) |
|
738 | 764 |
for(i in seq_len(n - 1) + 1) { |
739 |
- heatmap_width = unit.c(heatmap_width, sum(width_without_heatmap_body[6*(i-1) + 1:3]) + heatmap_body_width[i] + sum(width_without_heatmap_body[6*(i-1) + 5:7-1])) |
|
765 |
+ heatmap_width = unit.c(heatmap_width, sum(width_without_heatmap_body[6*(i-1) + 1:3]) + heatmap_nofixed_width[i] + sum(width_without_heatmap_body[6*(i-1) + 5:7-1])) |
|
740 | 766 |
} |
741 | 767 |
# width with fixed width |
742 | 768 |
heatmap_width = heatmap_width + heatmap_fixed_width |
... | ... |
@@ -13,7 +13,8 @@ Constructor method for HeatmapAnnotation class |
13 | 13 |
\usage{ |
14 | 14 |
HeatmapAnnotation(df, name, col, show_legend, ..., |
15 | 15 |
which = c("column", "row"), annotation_height = 1, annotation_width = 1, |
16 |
- height = unit(1, "cm"), width = unit(1, "cm"), gp = gpar(col = NA)) |
|
16 |
+ height = unit(1, "cm"), width = unit(1, "cm"), gp = gpar(col = NA), |
|
17 |
+ gap = NULL) |
|
17 | 18 |
} |
18 | 19 |
\arguments{ |
19 | 20 |
|
... | ... |
@@ -26,8 +27,9 @@ HeatmapAnnotation(df, name, col, show_legend, ..., |
26 | 27 |
\item{annotation_height}{height of each annotation if annotations are column annotations.} |
27 | 28 |
\item{annotation_width}{width of each annotation if annotations are row annotations.} |
28 | 29 |
\item{height}{not using currently.} |
29 |
- \item{width}{width of the whole heatmap annotations, only used for column annotation when appending to the list of heatmaps.} |
|
30 |
+ \item{width}{width of the whole heatmap annotations, only used for row annotation when appending to the list of heatmaps.} |
|
30 | 31 |
\item{gp}{graphic parameters for simple annotations.} |
32 |
+ \item{gap}{gap between each annotation} |
|
31 | 33 |
|
32 | 34 |
} |
33 | 35 |
\details{ |
... | ... |
@@ -39,6 +41,11 @@ The simple annotations are defined by \code{df} and \code{col} arguments. Comple |
39 | 41 |
A \code{\link{HeatmapAnnotation-class}} object. |
40 | 42 |
|
41 | 43 |
|
44 |
+} |
|
45 |
+\seealso{ |
|
46 |
+There are two shortcut functions: \code{\link{rowAnnotation}} and \code{\link{columnAnnotation}}. |
|
47 |
+ |
|
48 |
+ |
|
42 | 49 |
} |
43 | 50 |
\author{ |
44 | 51 |
Zuguang Gu <z.gu@dkfz.de> |
27 | 27 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,39 @@ |
1 |
+\name{columnAnnotation} |
|
2 |
+\alias{columnAnnotation} |
|
3 |
+\title{ |
|
4 |
+Construct column annotations |
|
5 |
+ |
|
6 |
+ |
|
7 |
+} |
|
8 |
+\description{ |
|
9 |
+Construct column annotations |
|
10 |
+ |
|
11 |
+ |
|
12 |
+} |
|
13 |
+\usage{ |
|
14 |
+columnAnnotation(...) |
|
15 |
+} |
|
16 |
+\arguments{ |
|
17 |
+ |
|
18 |
+ \item{...}{pass to \code{\link{HeatmapAnnotation}}} |
|
19 |
+ |
|
20 |
+} |
|
21 |
+\details{ |
|
22 |
+The function is identical to |
|
23 |
+ |
|
24 |
+ \preformatted{ |
|
25 |
+ HeatmapAnnotation(..., which = "column") |
|
26 |
+ } |
|
27 |
+ |
|
28 |
+ |
|
29 |
+} |
|
30 |
+\value{ |
|
31 |
+A \code{\link{HeatmapAnnotation-class}} object. |
|
32 |
+ |
|
33 |
+ |
|
34 |
+} |
|
35 |
+\author{ |
|
36 |
+Zuguang Gu <z.gu@dkfz.de> |
|
37 |
+ |
|
38 |
+ |
|
39 |
+} |
0 | 40 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,39 @@ |
1 |
+\name{rowAnnotation} |
|
2 |
+\alias{rowAnnotation} |
|
3 |
+\title{ |
|
4 |
+Construct row annotations |
|
5 |
+ |
|
6 |
+ |
|
7 |
+} |
|
8 |
+\description{ |
|
9 |
+Construct row annotations |
|
10 |
+ |
|
11 |
+ |
|
12 |
+} |
|
13 |
+\usage{ |
|
14 |
+rowAnnotation(...) |
|
15 |
+} |
|
16 |
+\arguments{ |
|
17 |
+ |
|
18 |
+ \item{...}{pass to \code{\link{HeatmapAnnotation}}} |
|
19 |
+ |
|
20 |
+} |
|
21 |
+\details{ |
|
22 |
+The function is identical to |
|
23 |
+ |
|
24 |
+ \preformatted{ |
|
25 |
+ HeatmapAnnotation(..., which = "row") |
|
26 |
+ } |
|
27 |
+ |
|
28 |
+ |
|
29 |
+} |
|
30 |
+\value{ |
|
31 |
+A \code{\link{HeatmapAnnotation-class}} object. |
|
32 |
+ |
|
33 |
+ |
|
34 |
+} |
|
35 |
+\author{ |
|
36 |
+Zuguang Gu <z.gu@dkfz.de> |
|
37 |
+ |
|
38 |
+ |
|
39 |
+} |
... | ... |
@@ -649,6 +649,14 @@ ha = HeatmapAnnotation(df = df, which = "row", width = unit(1, "cm")) |
649 | 649 |
draw(ha, 1:12) |
650 | 650 |
``` |
651 | 651 |
|
652 |
+Similar, there can be more than one row annotation: |
|
653 |
+ |
|
654 |
+```{r, fig.width = 3, fig.height = 7} |
|
655 |
+ha_combined = HeatmapAnnotation(df = df, boxplot = anno_boxplot(mat, which = "row"), |
|
656 |
+ which = "row", annotation_width = c(1, 3)) |
|
657 |
+draw(ha_combined, 1:12) |
|
658 |
+``` |
|
659 |
+ |
|
652 | 660 |
### Mix heatmaps and row annotations |
653 | 661 |
|
654 | 662 |
Essentially, row annotations and column annotations are identical graphics, but in applications, |
... | ... |
@@ -677,7 +685,7 @@ For row annotations, more complex annotation graphics can help to visualize the |
677 | 685 |
ht1 = Heatmap(mat, name = "ht1", km = 2) |
678 | 686 |
random_data = lapply(1:12, function(x) runif(20)) |
679 | 687 |
random_data[1:6] = lapply(random_data[1:6], function(x) x*0.5) |
680 |
-ha = HeatmapAnnotation(distribution = function(index) { |
|
688 |
+ha2 = HeatmapAnnotation(distribution = function(index) { |
|
681 | 689 |
random_data = random_data[index] |
682 | 690 |
n = length(index) |
683 | 691 |
|
... | ... |
@@ -692,7 +700,17 @@ ha = HeatmapAnnotation(distribution = function(index) { |
692 | 700 |
upViewport() |
693 | 701 |
} |
694 | 702 |
}, which = "row", width = unit(10, "cm")) |
695 |
-draw(ht1 + ha, row_hclust_side = "left", row_sub_title_side = "right") |
|
703 |
+draw(ht1 + ha2, row_hclust_side = "left", row_sub_title_side = "right") |
|
704 |
+``` |
|
705 |
+ |
|
706 |
+If no heatmap is needed to draw and users only want to arrange a list of row annotations, an empty |
|
707 |
+matrix with no column can be added to the heatmap list. (This functionality will be improved in the future) |
|
708 |
+ |
|
709 |
+```{r all_row_annotations, fig.width = 4} |
|
710 |
+nr = nrow(mat) |
|
711 |
+ha = HeatmapAnnotation(df = df, which = "row", width = NULL) |
|
712 |
+Heatmap(matrix(nrow = nr, ncol = 0), split = sample(c("A", "B"), nr, replace = TRUE)) + |
|
713 |
+ ha + ha_boxplot |
|
696 | 714 |
``` |
697 | 715 |
|
698 | 716 |
## Access components |