git-svn-id: https://hedgehog.fhcrc.org/bioconductor/trunk/madman/Rpacks/ComplexHeatmap@111679 bc3139a8-67e5-0310-9ffc-ced21a209358
... | ... |
@@ -1,12 +1,12 @@ |
1 | 1 |
Package: ComplexHeatmap |
2 | 2 |
Type: Package |
3 | 3 |
Title: Making Complex Heatmaps |
4 |
-Version: 1.7.3 |
|
4 |
+Version: 1.7.4 |
|
5 | 5 |
Date: 2015-11-24 |
6 | 6 |
Author: Zuguang Gu |
7 | 7 |
Maintainer: Zuguang Gu <z.gu@dkfz.de> |
8 | 8 |
Depends: R (>= 3.1.2), grid, graphics, stats, grDevices |
9 |
-Imports: methods, circlize (>= 0.3.1), GetoptLong, colorspace, |
|
9 |
+Imports: methods, circlize (>= 0.3.4), GetoptLong, colorspace, |
|
10 | 10 |
RColorBrewer, dendextend (>= 1.0.1), GlobalOptions (>= 0.0.6) |
11 | 11 |
Suggests: testthat (>= 0.3), knitr, markdown, cluster, MASS, pvclust, |
12 | 12 |
dendsort, HilbertCurve |
... | ... |
@@ -43,8 +43,9 @@ export(anno_barplot) |
43 | 43 |
exportMethods(row_dend) |
44 | 44 |
export(row_anno_boxplot) |
45 | 45 |
export(max_text_width) |
46 |
-export(decorate_row_title) |
|
46 |
+export(anno_link) |
|
47 | 47 |
exportMethods(make_layout) |
48 |
+export(decorate_row_title) |
|
48 | 49 |
export(anno_histogram) |
49 | 50 |
export(plotDataFrame) |
50 | 51 |
exportMethods(draw_dimnames) |
... | ... |
@@ -68,9 +69,10 @@ export(Heatmap) |
68 | 69 |
exportMethods(draw_annotation_legend) |
69 | 70 |
exportMethods(column_dend) |
70 | 71 |
exportMethods(set_component_height) |
72 |
+export(row_anno_link) |
|
73 |
+exportMethods(make_column_cluster) |
|
71 | 74 |
export(HeatmapList) |
72 | 75 |
exportMethods(draw_annotation) |
73 |
-exportMethods(make_column_cluster) |
|
74 | 76 |
export(SingleAnnotation) |
75 | 77 |
export(row_anno_histogram) |
76 | 78 |
exportMethods(get_color_mapping_list) |
... | ... |
@@ -83,6 +85,7 @@ export(grid.dendrogram) |
83 | 85 |
export(decorate_title) |
84 | 86 |
export(decorate_dend) |
85 | 87 |
export(rowAnnotation) |
88 |
+export(column_anno_link) |
|
86 | 89 |
export(columnAnnotation) |
87 | 90 |
export(decorate_row_names) |
88 | 91 |
export(anno_text) |
... | ... |
@@ -94,6 +97,7 @@ importFrom("methods", setMethod) |
94 | 97 |
importFrom("methods", setGeneric) |
95 | 98 |
importFrom("circlize", colorRamp2) |
96 | 99 |
importFrom("circlize", rand_color) |
100 |
+importFrom("circlize", smartAlign) |
|
97 | 101 |
importFrom("GetoptLong", qq) |
98 | 102 |
importFrom("GetoptLong", qqcat) |
99 | 103 |
importFrom("GetoptLong", qq.options) |
... | ... |
@@ -101,6 +105,7 @@ importFrom("colorspace", rainbow_hcl) |
101 | 105 |
importFrom("colorspace", diverge_hcl) |
102 | 106 |
importFrom("RColorBrewer", brewer.pal) |
103 | 107 |
importFrom("dendextend", get_branches_heights) |
108 |
+importFrom("dendextend", nnodes) |
|
104 | 109 |
import(graphics) |
105 | 110 |
import(stats) |
106 | 111 |
import(grDevices) |
... | ... |
@@ -1,9 +1,19 @@ |
1 |
+CHANEGS in VERSION 1.7.4 |
|
2 |
+ |
|
3 |
+* width of the heatmap body are calculated correctly if it is set as a fixed unit |
|
4 |
+* there is no dendrogram is nrows in a row-slice is 1 |
|
5 |
+* add `anno_link()` annotation function |
|
6 |
+ |
|
7 |
+=============================== |
|
8 |
+ |
|
1 | 9 |
CHANGES in VERSION 1.7.3 |
2 | 10 |
|
3 | 11 |
* `oncoPrint()`: add `barplot_ignore` option to remove alterations |
4 | 12 |
that are not put on the barplot. |
5 | 13 |
* `oncoPrint()`: delete extra alter_fun if they are not in the matrix |
6 | 14 |
|
15 |
+================================ |
|
16 |
+ |
|
7 | 17 |
CHANGES in VERSION 1.7.2 |
8 | 18 |
|
9 | 19 |
* for `anno_points()`, `anno_barplot()`, `anno_boxplot()`, the name is assigned |
... | ... |
@@ -1310,6 +1310,9 @@ setMethod(f = "draw_dend", |
1310 | 1310 |
|
1311 | 1311 |
dend = as.dendrogram(hc) |
1312 | 1312 |
n = length(labels(dend)) |
1313 |
+ if(nnodes(dend) <= 1) { |
|
1314 |
+ return(invisible(NULL)) |
|
1315 |
+ } |
|
1313 | 1316 |
|
1314 | 1317 |
dend_padding = unit(1, "mm") |
1315 | 1318 |
pushViewport(viewport(name = paste(object@name, which, "cluster", k, sep = "_"), ...)) |
... | ... |
@@ -1555,7 +1558,7 @@ setMethod(f = "component_width", |
1555 | 1558 |
if(!is.unit(object@heatmap_param$width)) { |
1556 | 1559 |
unit(1, "null") |
1557 | 1560 |
} else { |
1558 |
- object@heatmap_param$width - sum(component_width(object, c(1:3, 5:7))) |
|
1561 |
+ object@heatmap_param$width |
|
1559 | 1562 |
} |
1560 | 1563 |
} |
1561 | 1564 |
} else if(k == 5) { |
... | ... |
@@ -1699,7 +1702,6 @@ setMethod(f = "draw", |
1699 | 1702 |
pushViewport(viewport(layout = layout)) |
1700 | 1703 |
ht_layout_index = object@layout$layout_index |
1701 | 1704 |
ht_graphic_fun_list = object@layout$graphic_fun_list |
1702 |
- |
|
1703 | 1705 |
for(j in seq_len(nrow(ht_layout_index))) { |
1704 | 1706 |
if(ht_layout_index[j, 1] == 5 && ht_layout_index[j, 2] == 4) { |
1705 | 1707 |
pushViewport(viewport(layout.pos.row = ht_layout_index[j, 1], layout.pos.col = ht_layout_index[j, 2], name = paste(object@name, "heatmap_body_wrap", sep = "_"))) |
... | ... |
@@ -951,3 +951,161 @@ column_anno_text = function(...) { |
951 | 951 |
anno_text(..., which = "column") |
952 | 952 |
} |
953 | 953 |
|
954 |
+# == title |
|
955 |
+# Link annotation with labels |
|
956 |
+# |
|
957 |
+# == param |
|
958 |
+# -at numeric index in the original matrix |
|
959 |
+# -labels corresponding labels |
|
960 |
+# -which column annotaiton or row annotation |
|
961 |
+# -side side of the labels. If it is a column annotation, permitted values are "top" and "bottom"; |
|
962 |
+# If it is a row annotation, permitted values are "left" and "right". |
|
963 |
+# -lines_gp graphic settings for the segments |
|
964 |
+# -labels_gp graphic settings for the labels |
|
965 |
+# -padding padding between labels if they are attached to each other |
|
966 |
+# -link_width, width of the segments. |
|
967 |
+# |
|
968 |
+# == details |
|
969 |
+# Sometimes there are many rows or columns in the heatmap and we want to mark some of the rows. |
|
970 |
+# This annotation function is used to mark these rows and connect labels and corresponding rows |
|
971 |
+# with links. |
|
972 |
+# |
|
973 |
+# == author |
|
974 |
+# Zuguang Gu <z.gu@dkfz.de> |
|
975 |
+anno_link = function(at, labels, which = c("column", "row"), side = ifelse(which == "column", "top", "right"), |
|
976 |
+ lines_gp = gpar(), labels_gp = gpar(), padding = 0.25, link_width = NULL) { |
|
977 |
+ |
|
978 |
+ at = at |
|
979 |
+ if(!is.numeric(at)) { |
|
980 |
+ stop("`at` should be numeric index.") |
|
981 |
+ } |
|
982 |
+ labels = labels |
|
983 |
+ which = match.arg(which)[1] |
|
984 |
+ lines_gp = check_gp(lines_gp) |
|
985 |
+ labels_gp = check_gp(labels_gp) |
|
986 |
+ padding = padding |
|
987 |
+ |
|
988 |
+ od = order(at) |
|
989 |
+ at = at[od] |
|
990 |
+ labels = labels[od] |
|
991 |
+ |
|
992 |
+ f = switch(which, |
|
993 |
+ row = function(index, k = NULL, N = NULL, vp_name = NULL) { |
|
994 |
+ n = length(index) |
|
995 |
+ l = which(at %in% index) |
|
996 |
+ at = at[l] |
|
997 |
+ labels = labels[l] |
|
998 |
+ int = intersect(index, at) |
|
999 |
+ int = structure(seq_along(int), names = int) |
|
1000 |
+ labels = rev(labels[int[as.character(intersect(at, index))]]) |
|
1001 |
+ |
|
1002 |
+ pushViewport(viewport(xscale = c(0, 1), yscale = c(0.5, n+0.5))) |
|
1003 |
+ if(length(labels)) { |
|
1004 |
+ text_height = convertHeight(grobHeight(textGrob(labels, gp = labels_gp))*(1+padding), "native", valueOnly = TRUE) |
|
1005 |
+ i2 = rev(which(index %in% at)) |
|
1006 |
+ h1 = n-i2+1 - text_height*0.5 |
|
1007 |
+ h2 = n-i2+1 + text_height*0.5 |
|
1008 |
+ pos = rev(smartAlign(h1, h2, c(0.5, n+0.5))) |
|
1009 |
+ h = (pos[, 1] + pos[, 2])/2 |
|
1010 |
+ |
|
1011 |
+ if(is.null(link_width)) { |
|
1012 |
+ if(convertWidth(unit(1, "npc") - max_text_width(labels, gp = labels_gp), "mm", valueOnly = TRUE) < 0) { |
|
1013 |
+ link_width = unit(0.5, "npc") |
|
1014 |
+ } else { |
|
1015 |
+ link_width = unit(1, "npc") - max_text_width(labels, gp = labels_gp) |
|
1016 |
+ } |
|
1017 |
+ } |
|
1018 |
+ n2 = length(labels) |
|
1019 |
+ if(side == "right") { |
|
1020 |
+ grid.text(labels, rep(link_width, n2), h, default.units = "native", gp = labels_gp, just = "left") |
|
1021 |
+ link_width = link_width - unit(1, "mm") |
|
1022 |
+ grid.segments(unit(rep(0, n2), "npc"), n-i2+1, rep(link_width*(1/3), n2), n-i2+1, default.units = "native", gp = lines_gp) |
|
1023 |
+ grid.segments(rep(link_width*(1/3), n2), n-i2+1, rep(link_width*(2/3), n2), h, default.units = "native", gp = lines_gp) |
|
1024 |
+ grid.segments(rep(link_width*(2/3), n2), h, rep(link_width, n2), h, default.units = "native", gp = lines_gp) |
|
1025 |
+ } else { |
|
1026 |
+ grid.text(labels, rep(link_width, n2), h, default.units = "native", gp = labels_gp, just = "right") |
|
1027 |
+ link_width = link_width - unit(1, "mm") |
|
1028 |
+ grid.segments(unit(rep(1, n2), "npc"), n-i2+1, unit(1, "npc")-rep(link_width*(1/3), n2), n-i2+1, default.units = "native", gp = lines_gp) |
|
1029 |
+ grid.segments(unit(1, "npc")-rep(link_width*(1/3), n2), n-i2+1, unit(1, "npc")-rep(link_width*(2/3), n2), h, default.units = "native", gp = lines_gp) |
|
1030 |
+ grid.segments(unit(1, "npc")-rep(link_width*(2/3), n2), h, unit(1, "npc")-rep(link_width, n2), h, default.units = "native", gp = lines_gp) |
|
1031 |
+ } |
|
1032 |
+ } |
|
1033 |
+ upViewport() |
|
1034 |
+ }, |
|
1035 |
+ column = function(index, vp_name = NULL) { |
|
1036 |
+ n = length(index) |
|
1037 |
+ int = intersect(index, at) |
|
1038 |
+ int = structure(seq_along(int), names = int) |
|
1039 |
+ labels = rev(labels[int[as.character(intersect(at, index))]]) |
|
1040 |
+ pushViewport(viewport(yscale = c(0, 1), xscale = c(0.5, n+0.5))) |
|
1041 |
+ text_height = convertWidth(grobHeight(textGrob(labels, gp = labels_gp))*(1+padding), "native", valueOnly = TRUE) |
|
1042 |
+ i2 = which(index %in% at) |
|
1043 |
+ h1 = i2 - text_height*0.5 |
|
1044 |
+ h2 = i2 + text_height*0.5 |
|
1045 |
+ pos = smartAlign(h1, h2, c(0.5, n+0.5)) |
|
1046 |
+ h = (pos[, 1] + pos[, 2])/2 |
|
1047 |
+ if(is.null(link_width)) { |
|
1048 |
+ if(convertHeight(unit(1, "npc") - max_text_width(labels, gp = labels_gp), "mm", valueOnly = TRUE) < 0) { |
|
1049 |
+ link_width = unit(0.5, "npc") |
|
1050 |
+ } else { |
|
1051 |
+ link_width = unit(1, "npc") - max_text_width(labels, gp = labels_gp) |
|
1052 |
+ } |
|
1053 |
+ } |
|
1054 |
+ n2 = length(labels) |
|
1055 |
+ if(side == "top") { |
|
1056 |
+ grid.text(labels, h, rep(link_width, n2), default.units = "native", gp = labels_gp, rot = 90, just = "left") |
|
1057 |
+ link_width = link_width - unit(1, "mm") |
|
1058 |
+ grid.segments(i2, unit(rep(0, n2), "npc"), i2, rep(link_width*(1/3), n2), default.units = "native", gp = lines_gp) |
|
1059 |
+ grid.segments(i2, rep(link_width*(1/3), n2), h, rep(link_width*(2/3), n2), default.units = "native", gp = lines_gp) |
|
1060 |
+ grid.segments(h, rep(link_width*(2/3), n2), h, rep(link_width, n), default.units = "native", gp = lines_gp) |
|
1061 |
+ } else { |
|
1062 |
+ grid.text(labels, h, rep(link_width, n2), default.units = "native", gp = labels_gp, rot = 90, just = "right") |
|
1063 |
+ link_width = link_width - unit(1, "mm") |
|
1064 |
+ grid.segments(i2, unit(rep(1, n2), "npc"), i2, unit(1, "npc")-rep(link_width*(1/3), n2), default.units = "native", gp = lines_gp) |
|
1065 |
+ grid.segments(i2, unit(1, "npc")-rep(link_width*(1/3), n2), h, unit(1, "npc")-rep(link_width*(2/3), n2), default.units = "native", gp = lines_gp) |
|
1066 |
+ grid.segments(h, unit(1, "npc")-rep(link_width*(2/3), n2), h, unit(1, "npc")-rep(link_width, n2), default.units = "native", gp = lines_gp) |
|
1067 |
+ } |
|
1068 |
+ upViewport() |
|
1069 |
+ }) |
|
1070 |
+ attr(f, "which") = which |
|
1071 |
+ attr(f, "fun") = "anno_link" |
|
1072 |
+ return(f) |
|
1073 |
+} |
|
1074 |
+ |
|
1075 |
+# == title |
|
1076 |
+# Column annotation which is represented as links |
|
1077 |
+# |
|
1078 |
+# == param |
|
1079 |
+# -... pass to `anno_link` |
|
1080 |
+# |
|
1081 |
+# == details |
|
1082 |
+# A wrapper of `anno_link` with pre-defined ``which`` to ``row``. |
|
1083 |
+# |
|
1084 |
+# == value |
|
1085 |
+# See help page of `anno_link` |
|
1086 |
+# |
|
1087 |
+# == author |
|
1088 |
+# Zuguang Gu <z.gu@dkfz.de> |
|
1089 |
+# |
|
1090 |
+row_anno_link = function(...) { |
|
1091 |
+ anno_link(..., which = "row") |
|
1092 |
+} |
|
1093 |
+ |
|
1094 |
+# == title |
|
1095 |
+# Column annotation which is represented as links |
|
1096 |
+# |
|
1097 |
+# == param |
|
1098 |
+# -... pass to `anno_link` |
|
1099 |
+# |
|
1100 |
+# == details |
|
1101 |
+# A wrapper of `anno_link` with pre-defined ``which`` to ``column``. |
|
1102 |
+# |
|
1103 |
+# == value |
|
1104 |
+# See help page of `anno_link` |
|
1105 |
+# |
|
1106 |
+# == author |
|
1107 |
+# Zuguang Gu <z.gu@dkfz.de> |
|
1108 |
+# |
|
1109 |
+column_anno_link = function(...) { |
|
1110 |
+ anno_link(..., which = "column") |
|
1111 |
+} |
954 | 1112 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,36 @@ |
1 |
+\name{anno_link} |
|
2 |
+\alias{anno_link} |
|
3 |
+\title{ |
|
4 |
+Link annotation with labels |
|
5 |
+} |
|
6 |
+\description{ |
|
7 |
+Link annotation with labels |
|
8 |
+} |
|
9 |
+\usage{ |
|
10 |
+anno_link(at, labels, which = c("column", "row"), side = ifelse(which == "column", "top", "right"), |
|
11 |
+ lines_gp = gpar(), labels_gp = gpar(), padding = 0.25, link_width = NULL) |
|
12 |
+} |
|
13 |
+\arguments{ |
|
14 |
+ |
|
15 |
+ \item{at}{numeric index in the original matrix} |
|
16 |
+ \item{labels}{corresponding labels} |
|
17 |
+ \item{which}{column annotaiton or row annotation} |
|
18 |
+ \item{side}{side of the labels. If it is a column annotation, permitted values are "top" and "bottom"; If it is a row annotation, permitted values are "left" and "right".} |
|
19 |
+ \item{lines_gp}{graphic settings for the segments} |
|
20 |
+ \item{labels_gp}{graphic settings for the labels} |
|
21 |
+ \item{padding}{padding between labels if they are attached to each other} |
|
22 |
+ \item{link_width,}{width of the segments.} |
|
23 |
+ |
|
24 |
+} |
|
25 |
+\details{ |
|
26 |
+Sometimes there are many rows or columns in the heatmap and we want to mark some of the rows. |
|
27 |
+This annotation function is used to mark these rows and connect labels and corresponding rows |
|
28 |
+with links. |
|
29 |
+} |
|
30 |
+\author{ |
|
31 |
+Zuguang Gu <z.gu@dkfz.de> |
|
32 |
+} |
|
33 |
+\examples{ |
|
34 |
+# There is no example |
|
35 |
+NULL |
|
36 |
+} |
0 | 37 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,29 @@ |
1 |
+\name{column_anno_link} |
|
2 |
+\alias{column_anno_link} |
|
3 |
+\title{ |
|
4 |
+Column annotation which is represented as links |
|
5 |
+} |
|
6 |
+\description{ |
|
7 |
+Column annotation which is represented as links |
|
8 |
+} |
|
9 |
+\usage{ |
|
10 |
+column_anno_link(...) |
|
11 |
+} |
|
12 |
+\arguments{ |
|
13 |
+ |
|
14 |
+ \item{...}{pass to \code{\link{anno_link}}} |
|
15 |
+ |
|
16 |
+} |
|
17 |
+\details{ |
|
18 |
+A wrapper of \code{\link{anno_link}} with pre-defined \code{which} to \code{column}. |
|
19 |
+} |
|
20 |
+\value{ |
|
21 |
+See help page of \code{\link{anno_link}} |
|
22 |
+} |
|
23 |
+\author{ |
|
24 |
+Zuguang Gu <z.gu@dkfz.de> |
|
25 |
+} |
|
26 |
+\examples{ |
|
27 |
+# There is no example |
|
28 |
+NULL |
|
29 |
+} |
0 | 30 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,29 @@ |
1 |
+\name{row_anno_link} |
|
2 |
+\alias{row_anno_link} |
|
3 |
+\title{ |
|
4 |
+Column annotation which is represented as links |
|
5 |
+} |
|
6 |
+\description{ |
|
7 |
+Column annotation which is represented as links |
|
8 |
+} |
|
9 |
+\usage{ |
|
10 |
+row_anno_link(...) |
|
11 |
+} |
|
12 |
+\arguments{ |
|
13 |
+ |
|
14 |
+ \item{...}{pass to \code{\link{anno_link}}} |
|
15 |
+ |
|
16 |
+} |
|
17 |
+\details{ |
|
18 |
+A wrapper of \code{\link{anno_link}} with pre-defined \code{which} to \code{row}. |
|
19 |
+} |
|
20 |
+\value{ |
|
21 |
+See help page of \code{\link{anno_link}} |
|
22 |
+} |
|
23 |
+\author{ |
|
24 |
+Zuguang Gu <z.gu@dkfz.de> |
|
25 |
+} |
|
26 |
+\examples{ |
|
27 |
+# There is no example |
|
28 |
+NULL |
|
29 |
+} |
... | ... |
@@ -529,6 +529,23 @@ draw(ht_list, column_title = "reverse axis direction", newpage = FALSE) |
529 | 529 |
upViewport(2) |
530 | 530 |
``` |
531 | 531 |
|
532 |
+## Mark some of the rows/columns |
|
533 |
+ |
|
534 |
+From version 1.7.4, a new annotation function `anno_link()` was added which connects labels and subset of the rows |
|
535 |
+by links. It is helpful when there are many rows/columns and we want to mark some of the rows (e.g. in a gene expression |
|
536 |
+matrix, we want to mark some important genes of interest.) |
|
537 |
+ |
|
538 |
+```{r} |
|
539 |
+mat = matrix(rnorm(10000), nr = 1000) |
|
540 |
+labels = sample(letters, 20, replace = TRUE) |
|
541 |
+Heatmap(mat, show_row_dend = FALSE, show_column_dend = FALSE) + |
|
542 |
+rowAnnotation(link = row_anno_link(at = sample(1000, 20), labels = labels), |
|
543 |
+ width = unit(1, "cm") + max_text_width(labels)) |
|
544 |
+# here unit(1, "cm") is width of segments |
|
545 |
+``` |
|
546 |
+ |
|
547 |
+There are also two shortcut functions: `row_anno_link()` and `column_anno_link()`. |
|
548 |
+ |
|
532 | 549 |
## Session info |
533 | 550 |
|
534 | 551 |
```{r} |