... | ... |
@@ -6,7 +6,7 @@ Date: 2021-11-08 |
6 | 6 |
Author: Zuguang Gu |
7 | 7 |
Maintainer: Zuguang Gu <z.gu@dkfz.de> |
8 | 8 |
Depends: R (>= 3.5.0), methods, grid, graphics, stats, grDevices |
9 |
-Imports: circlize (>= 0.4.5), GetoptLong, colorspace, clue, |
|
9 |
+Imports: circlize (>= 0.4.14), GetoptLong, colorspace, clue, |
|
10 | 10 |
RColorBrewer, GlobalOptions (>= 0.1.0), png, |
11 | 11 |
digest, IRanges, matrixStats, foreach, doParallel |
12 | 12 |
Suggests: testthat (>= 1.0.0), knitr, markdown, dendsort, |
... | ... |
@@ -48,6 +48,8 @@ S3method("heightDetails", "legend_body") |
48 | 48 |
export("heightDetails.legend_body") |
49 | 49 |
S3method("heightDetails", "packed_legends") |
50 | 50 |
export("heightDetails.packed_legends") |
51 |
+S3method("heightDetails", "text_box") |
|
52 |
+export("heightDetails.text_box") |
|
51 | 53 |
S3method("length", "HeatmapAnnotation") |
52 | 54 |
export("length.HeatmapAnnotation") |
53 | 55 |
S3method("length", "HeatmapList") |
... | ... |
@@ -122,6 +124,8 @@ S3method("widthDetails", "legend_body") |
122 | 124 |
export("widthDetails.legend_body") |
123 | 125 |
S3method("widthDetails", "packed_legends") |
124 | 126 |
export("widthDetails.packed_legends") |
127 |
+S3method("widthDetails", "text_box") |
|
128 |
+export("widthDetails.text_box") |
|
125 | 129 |
export("%v%") |
126 | 130 |
export("AdditiveUnit") |
127 | 131 |
export("AnnotationFunction") |
... | ... |
@@ -149,11 +153,13 @@ export("anno_joyplot") |
149 | 153 |
export("anno_lines") |
150 | 154 |
export("anno_link") |
151 | 155 |
export("anno_mark") |
156 |
+export("anno_numeric") |
|
152 | 157 |
export("anno_oncoprint_barplot") |
153 | 158 |
export("anno_points") |
154 | 159 |
export("anno_simple") |
155 | 160 |
export("anno_summary") |
156 | 161 |
export("anno_text") |
162 |
+export("anno_text_box") |
|
157 | 163 |
export("anno_zoom") |
158 | 164 |
export("annotation_axis_grob") |
159 | 165 |
export("bar3D") |
... | ... |
@@ -193,6 +199,7 @@ export("getXY_in_parent_vp") |
193 | 199 |
export("grid.annotation_axis") |
194 | 200 |
export("grid.boxplot") |
195 | 201 |
export("grid.dendrogram") |
202 |
+export("grid.text_box") |
|
196 | 203 |
export("gt_render") |
197 | 204 |
export("ht_global_opt") |
198 | 205 |
export("ht_opt") |
... | ... |
@@ -228,6 +235,7 @@ export("subset_matrix_by_row") |
228 | 235 |
export("subset_no") |
229 | 236 |
export("subset_vector") |
230 | 237 |
export("test_alter_fun") |
238 |
+export("text_box_grob") |
|
231 | 239 |
export("unify_mat_list") |
232 | 240 |
export("upset_left_annotation") |
233 | 241 |
export("upset_right_annotation") |
... | ... |
@@ -3,6 +3,9 @@ CHANGES in VERSION 2.11.1 |
3 | 3 |
* add a global option `ht_opt$COLOR` to control colors for continuous color mapping. |
4 | 4 |
* `annotation_label` can be an `expression` object. |
5 | 5 |
* `recycle_gp()`: now consider when n = 0. |
6 |
+* `anno_block()`: add `align_to` argument. |
|
7 |
+* add `anno_text_box()` and `grid.text_box()`. |
|
8 |
+* add `show_name` argument in `anno_empty()`. |
|
6 | 9 |
|
7 | 10 |
========================= |
8 | 11 |
|
... | ... |
@@ -1,32 +1,32 @@ |
1 |
+setGeneric('set_component_width', function(object, ...) standardGeneric('set_component_width')) |
|
2 |
+setGeneric('annotation_legend_size', function(object, ...) standardGeneric('annotation_legend_size')) |
|
3 |
+setGeneric('re_size', function(object, ...) standardGeneric('re_size')) |
|
4 |
+setGeneric('component_height', function(object, ...) standardGeneric('component_height')) |
|
5 |
+setGeneric('draw_heatmap_list', function(object, ...) standardGeneric('draw_heatmap_list')) |
|
6 |
+setGeneric('make_row_cluster', function(object, ...) standardGeneric('make_row_cluster')) |
|
1 | 7 |
setGeneric('draw', function(object, ...) standardGeneric('draw')) |
2 |
-setGeneric('component_width', function(object, ...) standardGeneric('component_width')) |
|
3 |
-setGeneric('column_dend', function(object, ...) standardGeneric('column_dend')) |
|
4 |
-setGeneric('draw_dimnames', function(object, ...) standardGeneric('draw_dimnames')) |
|
5 |
-setGeneric('draw_title', function(object, ...) standardGeneric('draw_title')) |
|
8 |
+setGeneric('draw_annotation', function(object, ...) standardGeneric('draw_annotation')) |
|
9 |
+setGeneric('attach_annotation', function(object, ...) standardGeneric('attach_annotation')) |
|
6 | 10 |
setGeneric('add_heatmap', function(object, ...) standardGeneric('add_heatmap')) |
7 |
-setGeneric('row_order', function(object, ...) standardGeneric('row_order')) |
|
8 |
-setGeneric('color_mapping_legend', function(object, ...) standardGeneric('color_mapping_legend')) |
|
9 |
-setGeneric('make_column_cluster', function(object, ...) standardGeneric('make_column_cluster')) |
|
11 |
+setGeneric('column_dend', function(object, ...) standardGeneric('column_dend')) |
|
10 | 12 |
setGeneric('get_color_mapping_list', function(object, ...) standardGeneric('get_color_mapping_list')) |
11 |
-setGeneric('draw_heatmap_body', function(object, ...) standardGeneric('draw_heatmap_body')) |
|
12 |
-setGeneric('draw_heatmap_list', function(object, ...) standardGeneric('draw_heatmap_list')) |
|
13 |
+setGeneric('map_to_colors', function(object, ...) standardGeneric('map_to_colors')) |
|
14 |
+setGeneric('draw_dend', function(object, ...) standardGeneric('draw_dend')) |
|
13 | 15 |
setGeneric('make_layout', function(object, ...) standardGeneric('make_layout')) |
14 |
-setGeneric('attach_annotation', function(object, ...) standardGeneric('attach_annotation')) |
|
15 |
-setGeneric('draw_annotation_legend', function(object, ...) standardGeneric('draw_annotation_legend')) |
|
16 |
-setGeneric('get_legend_param_list', function(object, ...) standardGeneric('get_legend_param_list')) |
|
17 |
-setGeneric('component_height', function(object, ...) standardGeneric('component_height')) |
|
18 |
-setGeneric('set_component_height', function(object, ...) standardGeneric('set_component_height')) |
|
19 |
-setGeneric('draw_heatmap_legend', function(object, ...) standardGeneric('draw_heatmap_legend')) |
|
20 | 16 |
setGeneric('row_dend', function(object, ...) standardGeneric('row_dend')) |
21 |
-setGeneric('draw_dend', function(object, ...) standardGeneric('draw_dend')) |
|
22 |
-setGeneric('set_component_width', function(object, ...) standardGeneric('set_component_width')) |
|
23 |
-setGeneric('draw_annotation', function(object, ...) standardGeneric('draw_annotation')) |
|
24 |
-setGeneric('annotation_legend_size', function(object, ...) standardGeneric('annotation_legend_size')) |
|
25 |
-setGeneric('column_order', function(object, ...) standardGeneric('column_order')) |
|
26 |
-setGeneric('map_to_colors', function(object, ...) standardGeneric('map_to_colors')) |
|
27 |
-setGeneric('make_row_cluster', function(object, ...) standardGeneric('make_row_cluster')) |
|
17 |
+setGeneric('draw_heatmap_body', function(object, ...) standardGeneric('draw_heatmap_body')) |
|
28 | 18 |
setGeneric('heatmap_legend_size', function(object, ...) standardGeneric('heatmap_legend_size')) |
29 |
-setGeneric('re_size', function(object, ...) standardGeneric('re_size')) |
|
30 |
-setGeneric('adjust_heatmap_list', function(object, ...) standardGeneric('adjust_heatmap_list')) |
|
19 |
+setGeneric('component_width', function(object, ...) standardGeneric('component_width')) |
|
20 |
+setGeneric('make_column_cluster', function(object, ...) standardGeneric('make_column_cluster')) |
|
21 |
+setGeneric('draw_title', function(object, ...) standardGeneric('draw_title')) |
|
22 |
+setGeneric('draw_annotation_legend', function(object, ...) standardGeneric('draw_annotation_legend')) |
|
31 | 23 |
setGeneric('prepare', function(object, ...) standardGeneric('prepare')) |
24 |
+setGeneric('set_component_height', function(object, ...) standardGeneric('set_component_height')) |
|
25 |
+setGeneric('column_order', function(object, ...) standardGeneric('column_order')) |
|
26 |
+setGeneric('draw_dimnames', function(object, ...) standardGeneric('draw_dimnames')) |
|
32 | 27 |
setGeneric('copy_all', function(object, ...) standardGeneric('copy_all')) |
28 |
+setGeneric('get_legend_param_list', function(object, ...) standardGeneric('get_legend_param_list')) |
|
29 |
+setGeneric('row_order', function(object, ...) standardGeneric('row_order')) |
|
30 |
+setGeneric('adjust_heatmap_list', function(object, ...) standardGeneric('adjust_heatmap_list')) |
|
31 |
+setGeneric('draw_heatmap_legend', function(object, ...) standardGeneric('draw_heatmap_legend')) |
|
32 |
+setGeneric('color_mapping_legend', function(object, ...) standardGeneric('color_mapping_legend')) |
... | ... |
@@ -24,7 +24,7 @@ AnnotationFunction = setClass("AnnotationFunction", |
24 | 24 |
var_env = "environment", |
25 | 25 |
fun = "function", |
26 | 26 |
subset_rule = "list", |
27 |
- subsetable = "logical", |
|
27 |
+ subsettable = "logical", |
|
28 | 28 |
data_scale = "numeric", |
29 | 29 |
extended = "ANY", |
30 | 30 |
show_name = "logical" |
... | ... |
@@ -34,7 +34,7 @@ AnnotationFunction = setClass("AnnotationFunction", |
34 | 34 |
width = unit(1, "npc"), |
35 | 35 |
height = unit(1, "npc"), |
36 | 36 |
subset_rule = list(), |
37 |
- subsetable = FALSE, |
|
37 |
+ subsettable = FALSE, |
|
38 | 38 |
data_scale = c(0, 1), |
39 | 39 |
n = NA_integer_, |
40 | 40 |
extended = unit(c(0, 0, 0, 0), "mm"), |
... | ... |
@@ -92,8 +92,8 @@ anno_width_and_height = function(which, width = NULL, height = NULL, |
92 | 92 |
# -data_scale The data scale on the data axis (y-axis for column annotation and x-axis for row annotation). It is only used |
93 | 93 |
# when `decorate_annotation` is used with "native" unit coordinates. |
94 | 94 |
# -subset_rule The rule of subsetting variables in ``var_import``. It should be set when users want the final object to |
95 |
-# be subsetable. See **Details** section. |
|
96 |
-# -subsetable Whether the object is subsetable? |
|
95 |
+# be subsettable. See **Details** section. |
|
96 |
+# -subsettable Whether the object is subsettable? |
|
97 | 97 |
# -show_name It is used to turn off the drawing of annotation names in `HeatmapAnnotation`. Annotations always have names |
98 | 98 |
# associated and normally they will be drawn beside the annotation graphics to tell what the annotation is about. |
99 | 99 |
# e.g. the annotation names put beside the points annotation graphics. However, for some of the annotations, the names |
... | ... |
@@ -133,7 +133,7 @@ anno_width_and_height = function(which, width = NULL, height = NULL, |
133 | 133 |
# }, |
134 | 134 |
# var_import = list(x = x), |
135 | 135 |
# n = 10, |
136 |
-# subsetable = TRUE, |
|
136 |
+# subsettable = TRUE, |
|
137 | 137 |
# height = unit(2, "cm") |
138 | 138 |
# ) |
139 | 139 |
# m = rbind(1:10, 11:20) |
... | ... |
@@ -141,7 +141,7 @@ anno_width_and_height = function(which, width = NULL, height = NULL, |
141 | 141 |
# Heatmap(m, top_annotation = HeatmapAnnotation(foo = anno1), column_km = 2) |
142 | 142 |
AnnotationFunction = function(fun, fun_name = "", which = c("column", "row"), cell_fun = NULL, |
143 | 143 |
var_import = list(), n = NA, data_scale = c(0, 1), subset_rule = list(), |
144 |
- subsetable = length(subset_rule) > 0, show_name = TRUE, width = NULL, height = NULL) { |
|
144 |
+ subsettable = length(subset_rule) > 0, show_name = TRUE, width = NULL, height = NULL) { |
|
145 | 145 |
|
146 | 146 |
which = match.arg(which)[1] |
147 | 147 |
|
... | ... |
@@ -183,7 +183,7 @@ AnnotationFunction = function(fun, fun_name = "", which = c("column", "row"), ce |
183 | 183 |
} |
184 | 184 |
} |
185 | 185 |
} |
186 |
- subsetable = TRUE |
|
186 |
+ subsettable = TRUE |
|
187 | 187 |
} |
188 | 188 |
|
189 | 189 |
if(length(var_import)) { |
... | ... |
@@ -232,13 +232,13 @@ AnnotationFunction = function(fun, fun_name = "", which = c("column", "row"), ce |
232 | 232 |
} |
233 | 233 |
} |
234 | 234 |
|
235 |
- if(missing(subsetable)) { |
|
235 |
+ if(missing(subsettable)) { |
|
236 | 236 |
# is user defined subset rule |
237 | 237 |
if(length(anno@subset_rule)) { |
238 |
- anno@subsetable = TRUE |
|
238 |
+ anno@subsettable = TRUE |
|
239 | 239 |
} |
240 | 240 |
} else { |
241 |
- anno@subsetable = subsetable |
|
241 |
+ anno@subsettable = subsettable |
|
242 | 242 |
} |
243 | 243 |
|
244 | 244 |
return(anno) |
... | ... |
@@ -263,8 +263,8 @@ AnnotationFunction = function(fun, fun_name = "", which = c("column", "row"), ce |
263 | 263 |
if(nargs() == 1) { |
264 | 264 |
return(x) |
265 | 265 |
} else { |
266 |
- if(!x@subsetable) { |
|
267 |
- stop_wrap("This object is not subsetable.") |
|
266 |
+ if(!x@subsettable) { |
|
267 |
+ stop_wrap("This object is not subsettable.") |
|
268 | 268 |
} |
269 | 269 |
x = copy_all(x) |
270 | 270 |
if(x@fun_name == "anno_mark") { |
... | ... |
@@ -425,12 +425,12 @@ setMethod(f = "show", |
425 | 425 |
var_imported = names(object@var_env) |
426 | 426 |
if(length(var_imported)) { |
427 | 427 |
cat(" imported variable:", paste(var_imported, collapse = ", "), "\n") |
428 |
- var_subsetable = names(object@subset_rule) |
|
429 |
- if(length(var_subsetable)) { |
|
430 |
- cat(" subsetable variable:", paste(var_subsetable, collapse = ", "), "\n") |
|
428 |
+ var_subsettable = names(object@subset_rule) |
|
429 |
+ if(length(var_subsettable)) { |
|
430 |
+ cat(" subsettable variable:", paste(var_subsettable, collapse = ", "), "\n") |
|
431 | 431 |
} |
432 | 432 |
} |
433 |
- cat(" this object is ", ifelse(object@subsetable, "", "not "), "subsetable\n", sep = "") |
|
433 |
+ cat(" this object is ", ifelse(object@subsettable, "", "not "), "subsettable\n", sep = "") |
|
434 | 434 |
dirt = c("bottom", "left", "top", "right") |
435 | 435 |
for(i in 1:4) { |
436 | 436 |
if(!identical(unit(0, "mm"), object@extended[i])) { |
... | ... |
@@ -10,6 +10,7 @@ |
10 | 10 |
# and the original heatmap slices. |
11 | 11 |
# -width Width of the annotation. The value should be an absolute unit. Width is not allowed to be set for column annotation. |
12 | 12 |
# -height Height of the annotation. The value should be an absolute unit. Height is not allowed to be set for row annotation. |
13 |
+# -show_name Whether to show annotation name. |
|
13 | 14 |
# |
14 | 15 |
# == details |
15 | 16 |
# It creates an empty annotation and holds space, later users can add graphics |
... | ... |
@@ -46,7 +47,7 @@ |
46 | 47 |
# anno = anno_empty(border = FALSE) |
47 | 48 |
# draw(anno, test = "anno_empty without border") |
48 | 49 |
anno_empty = function(which = c("column", "row"), border = TRUE, zoom = FALSE, |
49 |
- width = NULL, height = NULL) { |
|
50 |
+ width = NULL, height = NULL, show_name = FALSE) { |
|
50 | 51 |
|
51 | 52 |
if(is.null(.ENV$current_annotation_which)) { |
52 | 53 |
which = match.arg(which)[1] |
... | ... |
@@ -68,10 +69,10 @@ anno_empty = function(which = c("column", "row"), border = TRUE, zoom = FALSE, |
68 | 69 |
which = which, |
69 | 70 |
var_import = list(border, zoom), |
70 | 71 |
subset_rule = list(), |
71 |
- subsetable = TRUE, |
|
72 |
+ subsettable = TRUE, |
|
72 | 73 |
height = anno_size$height, |
73 | 74 |
width = anno_size$width, |
74 |
- show_name = FALSE |
|
75 |
+ show_name = show_name |
|
75 | 76 |
) |
76 | 77 |
|
77 | 78 |
return(anno) |
... | ... |
@@ -242,10 +243,15 @@ anno_simple = function(x, col, na_col = "grey", |
242 | 243 |
pch = pch[index, , drop = FALSE] |
243 | 244 |
|
244 | 245 |
for(i in seq_len(nc)) { |
245 |
- if(color_mapping@type == "continuous") { |
|
246 |
+ if(color_mapping@type == "continuous" || !is.null(gp$col)) { |
|
246 | 247 |
fill = map_to_colors(color_mapping, value[index, i]) |
247 |
- if(is.null(gp$col)) gp$col = fill |
|
248 |
+ flag = 0 |
|
249 |
+ if(is.null(gp$col)) { |
|
250 |
+ gp$col = fill |
|
251 |
+ flag = 1 |
|
252 |
+ } |
|
248 | 253 |
grid.rect(x = (i-0.5)/nc, y, height = 1/n, width = 1/nc, gp = do.call("gpar", c(list(fill = fill), gp))) |
254 |
+ if(flag) gp$col = NULL |
|
249 | 255 |
} else { |
250 | 256 |
r = rle(value[index, i]) |
251 | 257 |
fill = map_to_colors(color_mapping, r$values) |
... | ... |
@@ -269,7 +275,7 @@ anno_simple = function(x, col, na_col = "grey", |
269 | 275 |
} |
270 | 276 |
} |
271 | 277 |
} else { |
272 |
- if(color_mapping@type == "continuous") { |
|
278 |
+ if(color_mapping@type == "continuous" || !is.null(gp$col)) { |
|
273 | 279 |
fill = map_to_colors(color_mapping, value[index]) |
274 | 280 |
if(is.null(gp$col)) gp$col = fill |
275 | 281 |
grid.rect(x = 0.5, y, height = 1/n, width = 1, gp = do.call("gpar", c(list(fill = fill), gp))) |
... | ... |
@@ -308,12 +314,16 @@ anno_simple = function(x, col, na_col = "grey", |
308 | 314 |
|
309 | 315 |
nc = ncol(value) |
310 | 316 |
pch = pch[index, , drop = FALSE] |
311 |
- |
|
312 | 317 |
for(i in seq_len(nc)) { |
313 |
- if(color_mapping@type == "continuous") { |
|
318 |
+ if(color_mapping@type == "continuous" || !is.null(gp$col)) { |
|
314 | 319 |
fill = map_to_colors(color_mapping, value[index, i]) |
315 |
- if(is.null(gp$col)) gp$col = fill |
|
320 |
+ flag = 0 |
|
321 |
+ if(is.null(gp$col)) { |
|
322 |
+ gp$col = fill |
|
323 |
+ flag = 1 |
|
324 |
+ } |
|
316 | 325 |
grid.rect(x, y = (nc-i +0.5)/nc, width = 1/n, height = 1/nc, gp = do.call("gpar", c(list(fill = fill), gp))) |
326 |
+ if(flag) gp$col = NULL |
|
317 | 327 |
} else { |
318 | 328 |
r = rle(value[index, i]) |
319 | 329 |
fill = map_to_colors(color_mapping, r$values) |
... | ... |
@@ -337,7 +347,7 @@ anno_simple = function(x, col, na_col = "grey", |
337 | 347 |
} |
338 | 348 |
} |
339 | 349 |
} else { |
340 |
- if(color_mapping@type == "continuous") { |
|
350 |
+ if(color_mapping@type == "continuous" || !is.null(gp$col)) { |
|
341 | 351 |
fill = map_to_colors(color_mapping, value[index]) |
342 | 352 |
if(is.null(gp$col)) gp$col = fill |
343 | 353 |
grid.rect(x, y = 0.5, width = 1/n, height = 1, gp = do.call("gpar", c(list(fill = fill), gp))) |
... | ... |
@@ -400,7 +410,7 @@ anno_simple = function(x, col, na_col = "grey", |
400 | 410 |
} |
401 | 411 |
} |
402 | 412 |
|
403 |
- anno@subsetable = TRUE |
|
413 |
+ anno@subsettable = TRUE |
|
404 | 414 |
|
405 | 415 |
return(anno) |
406 | 416 |
} |
... | ... |
@@ -563,7 +573,13 @@ anno_image = function(image, which = c("column", "row"), border = TRUE, |
563 | 573 |
grid.picture(image_list[[ index[i] ]], x = (i-0.5)/n, width = width, height = height) |
564 | 574 |
} |
565 | 575 |
} |
566 |
- if(border) grid.rect(gp = gpar(fill = "transparent")) |
|
576 |
+ if(is.logical(border)) { |
|
577 |
+ if(border) { |
|
578 |
+ grid.rect(gp = gpar(fill = "transparent")) |
|
579 |
+ } |
|
580 |
+ } else { |
|
581 |
+ grid.rect(gp = gpar(fill = "transparent", col = border)) |
|
582 |
+ } |
|
567 | 583 |
popViewport() |
568 | 584 |
} |
569 | 585 |
|
... | ... |
@@ -592,7 +608,13 @@ anno_image = function(image, which = c("column", "row"), border = TRUE, |
592 | 608 |
grid.picture(image_list[[ index[i] ]], y = (n - i + 0.5)/n, width = width, height = height) |
593 | 609 |
} |
594 | 610 |
} |
595 |
- if(border) grid.rect(gp = gpar(fill = "transparent")) |
|
611 |
+ if(is.logical(border)) { |
|
612 |
+ if(border) { |
|
613 |
+ grid.rect(gp = gpar(fill = "transparent")) |
|
614 |
+ } |
|
615 |
+ } else { |
|
616 |
+ grid.rect(gp = gpar(fill = "transparent", col = border)) |
|
617 |
+ } |
|
596 | 618 |
popViewport() |
597 | 619 |
} |
598 | 620 |
|
... | ... |
@@ -617,7 +639,7 @@ anno_image = function(image, which = c("column", "row"), border = TRUE, |
617 | 639 |
anno@subset_rule$image_list = subset_vector |
618 | 640 |
anno@subset_rule$image_class = subset_vector |
619 | 641 |
|
620 |
- anno@subsetable = TRUE |
|
642 |
+ anno@subsettable = TRUE |
|
621 | 643 |
|
622 | 644 |
return(anno) |
623 | 645 |
} |
... | ... |
@@ -914,7 +936,7 @@ anno_points = function(x, which = c("column", "row"), border = TRUE, gp = gpar() |
914 | 936 |
anno@subset_rule$pch = subset_vector |
915 | 937 |
} |
916 | 938 |
|
917 |
- anno@subsetable = TRUE |
|
939 |
+ anno@subsettable = TRUE |
|
918 | 940 |
|
919 | 941 |
anno@extended = update_anno_extend(anno, axis_grob, axis_param) |
920 | 942 |
|
... | ... |
@@ -1185,7 +1207,7 @@ anno_lines = function(x, which = c("column", "row"), border = TRUE, gp = gpar(), |
1185 | 1207 |
anno@subset_rule$pch = subset_vector |
1186 | 1208 |
} |
1187 | 1209 |
|
1188 |
- anno@subsetable = TRUE |
|
1210 |
+ anno@subsettable = TRUE |
|
1189 | 1211 |
|
1190 | 1212 |
anno@extended = update_anno_extend(anno, axis_grob, axis_param) |
1191 | 1213 |
|
... | ... |
@@ -1205,6 +1227,7 @@ anno_lines = function(x, which = c("column", "row"), border = TRUE, gp = gpar(), |
1205 | 1227 |
# -border Wether draw borders of the annotation region? |
1206 | 1228 |
# -bar_width Relative width of the bars. The value should be smaller than one. |
1207 | 1229 |
# -beside When ``x`` is a matrix, will bars be positioned beside each other or as stacked bars? |
1230 |
+# -attach When ``beside`` is ``TRUE``, it controls whether bars should be attached. |
|
1208 | 1231 |
# -gp Graphic parameters for bars. The length of each graphic parameter can be 1, length of ``x`` if ``x`` |
1209 | 1232 |
# is a vector, or number of columns of ``x`` is ``x`` is a matrix. |
1210 | 1233 |
# -ylim Data ranges. By default it is ``range(x)`` if ``x`` is a vector, or ``range(rowSums(x))`` if ``x`` is a matrix. |
... | ... |
@@ -1233,7 +1256,8 @@ anno_lines = function(x, which = c("column", "row"), border = TRUE, gp = gpar(), |
1233 | 1256 |
# m = t(apply(m, 1, function(x) x/sum(x))) |
1234 | 1257 |
# anno = anno_barplot(m, gp = gpar(fill = 2:5), bar_width = 1, height = unit(6, "cm")) |
1235 | 1258 |
# draw(anno, test = "proportion matrix") |
1236 |
-anno_barplot = function(x, baseline = 0, which = c("column", "row"), border = TRUE, bar_width = 0.6, beside = FALSE, |
|
1259 |
+anno_barplot = function(x, baseline = 0, which = c("column", "row"), border = TRUE, bar_width = 0.6, |
|
1260 |
+ beside = FALSE, attach = FALSE, |
|
1237 | 1261 |
gp = gpar(fill = "#CCCCCC"), ylim = NULL, extend = 0.05, axis = TRUE, |
1238 | 1262 |
axis_param = default_axis_param(which), |
1239 | 1263 |
add_numbers = FALSE, numbers_gp = gpar(fontsize = 8), |
... | ... |
@@ -1375,13 +1399,23 @@ anno_barplot = function(x, baseline = 0, which = c("column", "row"), border = TR |
1375 | 1399 |
nr = nrow(value) |
1376 | 1400 |
for(i in seq_along(index)) { |
1377 | 1401 |
for(j in 1:nbar) { |
1378 |
- if(axis_param$direction == "normal") { |
|
1379 |
- grid.rect(x = baseline, y = nr-i+0.5 + (j-0.5)/nbar, width = value[index[i], j], height = 1/nbar*bar_width, just = c("left"), |
|
1380 |
- default.units = "native", gp = subset_gp(gp, j)) |
|
1381 |
- } else { |
|
1382 |
- grid.rect(x = baseline, y = nr-i+0.5 + (j-0.5)/nbar, width = value[index[i], j], height = 1/nbar*bar_width, just = c("right"), |
|
1383 |
- default.units = "native", gp = subset_gp(gp, j)) |
|
1384 |
- } |
|
1402 |
+ if(attach) { |
|
1403 |
+ if(axis_param$direction == "normal") { |
|
1404 |
+ grid.rect(x = baseline, y = nr-i+0.5 + (1-bar_width)/2 + (nbar - j + 0.5)/nbar*bar_width, width = value[index[i], j], height = 1/nbar*bar_width, just = c("left"), |
|
1405 |
+ default.units = "native", gp = subset_gp(gp, j)) |
|
1406 |
+ } else { |
|
1407 |
+ grid.rect(x = baseline, y = nr-i+0.5 + (1-bar_width)/2 + (nbar - j + 0.5)/nbar*bar_width, width = value[index[i], j], height = 1/nbar*bar_width, just = c("right"), |
|
1408 |
+ default.units = "native", gp = subset_gp(gp, j)) |
|
1409 |
+ } |
|
1410 |
+ } else { |
|
1411 |
+ if(axis_param$direction == "normal") { |
|
1412 |
+ grid.rect(x = baseline, y = nr-i+0.5 + (nbar - j + 0.5)/nbar, width = value[index[i], j], height = 1/nbar*bar_width, just = c("left"), |
|
1413 |
+ default.units = "native", gp = subset_gp(gp, j)) |
|
1414 |
+ } else { |
|
1415 |
+ grid.rect(x = baseline, y = nr-i+0.5 + (nbar - j + 0.5)/nbar, width = value[index[i], j], height = 1/nbar*bar_width, just = c("right"), |
|
1416 |
+ default.units = "native", gp = subset_gp(gp, j)) |
|
1417 |
+ } |
|
1418 |
+ } |
|
1385 | 1419 |
} |
1386 | 1420 |
} |
1387 | 1421 |
} else { |
... | ... |
@@ -1440,13 +1474,23 @@ anno_barplot = function(x, baseline = 0, which = c("column", "row"), border = TR |
1440 | 1474 |
nr = nrow(value) |
1441 | 1475 |
for(i in seq_along(index)) { |
1442 | 1476 |
for(j in 1:nbar) { |
1443 |
- if(axis_param$direction == "normal") { |
|
1444 |
- grid.rect(y = baseline, x = nr-i+0.5 + (j-0.5)/nbar, height = value[index[i], j], width = 1/nbar*bar_width, just = c("bottom"), |
|
1445 |
- default.units = "native", gp = subset_gp(gp, j)) |
|
1446 |
- } else { |
|
1447 |
- grid.rect(y = baseline, x = nr-i+0.5 + (j-0.5)/nbar, height = value[index[i], j], width = 1/nbar*bar_width, just = c("top"), |
|
1448 |
- default.units = "native", gp = subset_gp(gp, j)) |
|
1449 |
- } |
|
1477 |
+ if(attach) { |
|
1478 |
+ if(axis_param$direction == "normal") { |
|
1479 |
+ grid.rect(y = baseline, x = i-0.5 + (1-bar_width)/2 + (j-0.5)/nbar*bar_width, height = value[index[i], j], width = 1/nbar*bar_width, just = c("bottom"), |
|
1480 |
+ default.units = "native", gp = subset_gp(gp, j)) |
|
1481 |
+ } else { |
|
1482 |
+ grid.rect(y = baseline, x = i-0.5 + (1-bar_width)/2 + (j-0.5)/nbar*bar_width, height = value[index[i], j], width = 1/nbar*bar_width, just = c("top"), |
|
1483 |
+ default.units = "native", gp = subset_gp(gp, j)) |
|
1484 |
+ } |
|
1485 |
+ } else { |
|
1486 |
+ if(axis_param$direction == "normal") { |
|
1487 |
+ grid.rect(y = baseline, x = i-0.5 + (j-0.5)/nbar, height = value[index[i], j], width = 1/nbar*bar_width, just = c("bottom"), |
|
1488 |
+ default.units = "native", gp = subset_gp(gp, j)) |
|
1489 |
+ } else { |
|
1490 |
+ grid.rect(y = baseline, x = i-0.5 + (j-0.5)/nbar, height = value[index[i], j], width = 1/nbar*bar_width, just = c("top"), |
|
1491 |
+ default.units = "native", gp = subset_gp(gp, j)) |
|
1492 |
+ } |
|
1493 |
+ } |
|
1450 | 1494 |
} |
1451 | 1495 |
} |
1452 | 1496 |
} else { |
... | ... |
@@ -1489,7 +1533,7 @@ anno_barplot = function(x, baseline = 0, which = c("column", "row"), border = TR |
1489 | 1533 |
height = anno_size$height, |
1490 | 1534 |
n = n, |
1491 | 1535 |
data_scale = data_scale, |
1492 |
- var_import = list(value, gp, border, bar_width, baseline, beside, axis, axis_param, axis_grob, data_scale, add_numbers, numbers_gp, numbers_offset, numbers_rot) |
|
1536 |
+ var_import = list(value, gp, border, bar_width, baseline, beside, attach, axis, axis_param, axis_grob, data_scale, add_numbers, numbers_gp, numbers_offset, numbers_rot) |
|
1493 | 1537 |
) |
1494 | 1538 |
|
1495 | 1539 |
anno@subset_rule$value = subset_matrix_by_row |
... | ... |
@@ -1497,7 +1541,7 @@ anno_barplot = function(x, baseline = 0, which = c("column", "row"), border = TR |
1497 | 1541 |
anno@subset_rule$gp = subset_gp |
1498 | 1542 |
} |
1499 | 1543 |
|
1500 |
- anno@subsetable = TRUE |
|
1544 |
+ anno@subsettable = TRUE |
|
1501 | 1545 |
|
1502 | 1546 |
anno@extended = update_anno_extend(anno, axis_grob, axis_param) |
1503 | 1547 |
|
... | ... |
@@ -1734,7 +1778,7 @@ anno_boxplot = function(x, which = c("column", "row"), border = TRUE, |
1734 | 1778 |
anno@subset_rule$pch = subset_vector |
1735 | 1779 |
anno@subset_rule$size = subset_vector |
1736 | 1780 |
|
1737 |
- anno@subsetable = TRUE |
|
1781 |
+ anno@subsettable = TRUE |
|
1738 | 1782 |
|
1739 | 1783 |
anno@extended = update_anno_extend(anno, axis_grob, axis_param) |
1740 | 1784 |
|
... | ... |
@@ -1897,7 +1941,7 @@ anno_histogram = function(x, which = c("column", "row"), n_breaks = 11, |
1897 | 1941 |
anno@subset_rule$histogram_breaks = subset_vector |
1898 | 1942 |
anno@subset_rule$histogram_counts = subset_vector |
1899 | 1943 |
|
1900 |
- anno@subsetable = TRUE |
|
1944 |
+ anno@subsettable = TRUE |
|
1901 | 1945 |
|
1902 | 1946 |
anno@extended = update_anno_extend(anno, axis_grob, axis_param) |
1903 | 1947 |
|
... | ... |
@@ -2176,7 +2220,7 @@ anno_density = function(x, which = c("column", "row"), |
2176 | 2220 |
anno@subset_rule$density_x = subset_vector |
2177 | 2221 |
anno@subset_rule$density_y = subset_vector |
2178 | 2222 |
|
2179 |
- anno@subsetable = TRUE |
|
2223 |
+ anno@subsettable = TRUE |
|
2180 | 2224 |
|
2181 | 2225 |
anno@extended = update_anno_extend(anno, axis_grob, axis_param) |
2182 | 2226 |
|
... | ... |
@@ -2360,7 +2404,7 @@ anno_text = function(x, which = c("column", "row"), gp = gpar(), |
2360 | 2404 |
anno@subset_rule$value = subset_vector |
2361 | 2405 |
anno@subset_rule$gp = subset_gp |
2362 | 2406 |
|
2363 |
- anno@subsetable = TRUE |
|
2407 |
+ anno@subsettable = TRUE |
|
2364 | 2408 |
|
2365 | 2409 |
return(anno) |
2366 | 2410 |
} |
... | ... |
@@ -2549,7 +2593,7 @@ anno_joyplot = function(x, which = c("column", "row"), gp = gpar(fill = "#000000 |
2549 | 2593 |
anno@subset_rule$value = subset_vector |
2550 | 2594 |
anno@subset_rule$gp = subset_gp |
2551 | 2595 |
|
2552 |
- anno@subsetable = TRUE |
|
2596 |
+ anno@subsettable = TRUE |
|
2553 | 2597 |
|
2554 | 2598 |
anno@extended = update_anno_extend(anno, axis_grob, axis_param) |
2555 | 2599 |
|
... | ... |
@@ -2733,7 +2777,7 @@ anno_horizon = function(x, which = c("column", "row"), |
2733 | 2777 |
anno@subset_rule$value = subset_vector |
2734 | 2778 |
anno@subset_rule$gp = subset_gp |
2735 | 2779 |
|
2736 |
- anno@subsetable = TRUE |
|
2780 |
+ anno@subsettable = TRUE |
|
2737 | 2781 |
|
2738 | 2782 |
anno@extended = update_anno_extend(anno, axis_grob, axis_param) |
2739 | 2783 |
|
... | ... |
@@ -3220,7 +3264,7 @@ anno_mark = function(at, labels, which = c("column", "row"), |
3220 | 3264 |
|
3221 | 3265 |
anno@subset_rule$at = subset_by_intersect |
3222 | 3266 |
|
3223 |
- anno@subsetable = TRUE |
|
3267 |
+ anno@subsettable = TRUE |
|
3224 | 3268 |
|
3225 | 3269 |
attr(anno, "called_args") = list( |
3226 | 3270 |
at = at, |
... | ... |
@@ -3427,7 +3471,7 @@ anno_summary = function(which = c("column", "row"), border = TRUE, bar_width = 0 |
3427 | 3471 |
show_name = FALSE |
3428 | 3472 |
) |
3429 | 3473 |
|
3430 |
- anno@subsetable = FALSE |
|
3474 |
+ anno@subsettable = FALSE |
|
3431 | 3475 |
anno@extended = update_anno_extend(anno, axis_grob, axis_param) |
3432 | 3476 |
|
3433 | 3477 |
return(anno) |
... | ... |
@@ -3437,6 +3481,8 @@ anno_summary = function(which = c("column", "row"), border = TRUE, bar_width = 0 |
3437 | 3481 |
# Block annotation |
3438 | 3482 |
# |
3439 | 3483 |
# == param |
3484 |
+# -align_to If you don't want to create block annotation for all slices, you can specify a list of indices that cover continuously adjacent |
|
3485 |
+# rows or columns. |
|
3440 | 3486 |
# -gp Graphic parameters. |
3441 | 3487 |
# -labels Labels put on blocks. |
3442 | 3488 |
# -labels_gp Graphic parameters for labels. |
... | ... |
@@ -3447,7 +3493,7 @@ anno_summary = function(which = c("column", "row"), border = TRUE, bar_width = 0 |
3447 | 3493 |
# -width Width of the annotation. The value should be an absolute unit. Width is not allowed to be set for column annotation. |
3448 | 3494 |
# -height Height of the annotation. The value should be an absolute unit. Height is not allowed to be set for row annotation. |
3449 | 3495 |
# -show_name Whether show annotatio name. |
3450 |
-# -graphics A self-defined function that draws graphics in each slice. It must have two arguments: 1. row/column indices for the |
|
3496 |
+# -panel_fun A self-defined function that draws graphics in each slice. It must have two arguments: 1. row/column indices for the |
|
3451 | 3497 |
# current slice and 2. a vector of levels from the split variable that correspond to current slice. When ``graphics`` is set, |
3452 | 3498 |
# all other graphics parameters in `anno_block` are ignored. |
3453 | 3499 |
# |
... | ... |
@@ -3470,11 +3516,11 @@ anno_summary = function(which = c("column", "row"), border = TRUE, bar_width = 0 |
3470 | 3516 |
# row_km = 3) |
3471 | 3517 |
# |
3472 | 3518 |
# |
3473 |
-# # ============= set the graphics argument ============== |
|
3519 |
+# # ============= set the panel_fun argument ============== |
|
3474 | 3520 |
# col = c("1" = "red", "2" = "blue", "A" = "green", "B" = "orange") |
3475 | 3521 |
# Heatmap(matrix(rnorm(100), 10), row_km = 2, row_split = sample(c("A", "B"), 10, replace = TRUE)) + |
3476 | 3522 |
# rowAnnotation(foo = anno_block( |
3477 |
-# graphics = function(index, levels) { |
|
3523 |
+# panel_fun = function(index, levels) { |
|
3478 | 3524 |
# grid.rect(gp = gpar(fill = col[levels[2]], col = "black")) |
3479 | 3525 |
# grid.text(paste(levels, collapse = ","), 0.5, 0.5, rot = 90, |
3480 | 3526 |
# gp = gpar(col = col[levels[1]])) |
... | ... |
@@ -3483,7 +3529,7 @@ anno_summary = function(which = c("column", "row"), border = TRUE, bar_width = 0 |
3483 | 3529 |
# |
3484 | 3530 |
# labels = c("1" = "one", "2" = "two", "A" = "Group_A", "B" = "Group_B") |
3485 | 3531 |
# Heatmap(matrix(rnorm(100), 10), row_km = 2, row_split = sample(c("A", "B"), 10, replace = TRUE)) + |
3486 |
-# rowAnnotation(foo = anno_block(graphics = function(index, levels) { |
|
3532 |
+# rowAnnotation(foo = anno_block(panel_fun = function(index, levels) { |
|
3487 | 3533 |
# grid.rect(gp = gpar(fill = col[levels[2]], col = "black")) |
3488 | 3534 |
# grid.text(paste(labels[levels], collapse = ","), 0.5, 0.5, rot = 90, |
3489 | 3535 |
# gp = gpar(col = col[levels[1]])) |
... | ... |
@@ -3491,7 +3537,7 @@ anno_summary = function(which = c("column", "row"), border = TRUE, bar_width = 0 |
3491 | 3537 |
# |
3492 | 3538 |
# Heatmap(matrix(rnorm(100), 10), row_km = 2, row_split = sample(c("A", "B"), 10, replace = TRUE)) + |
3493 | 3539 |
# rowAnnotation(foo = anno_block( |
3494 |
-# graphics = function(index, levels) { |
|
3540 |
+# panel_fun = function(index, levels) { |
|
3495 | 3541 |
# grid.rect(gp = gpar(fill = col[levels[2]], col = "black")) |
3496 | 3542 |
# txt = paste(levels, collapse = ",") |
3497 | 3543 |
# txt = paste0(txt, "\n", length(index), " rows") |
... | ... |
@@ -3501,17 +3547,40 @@ anno_summary = function(which = c("column", "row"), border = TRUE, bar_width = 0 |
3501 | 3547 |
# width = unit(3, "cm") |
3502 | 3548 |
# )) |
3503 | 3549 |
# |
3504 |
-anno_block = function(gp = gpar(), labels = NULL, labels_gp = gpar(), |
|
3550 |
+# # =========== set align_to ################ |
|
3551 |
+# col = c("foo" = "red", "bar" = "blue") |
|
3552 |
+# Heatmap(matrix(rnorm(100), 10), cluster_rows = FALSE) + |
|
3553 |
+# rowAnnotation(foo = anno_block( |
|
3554 |
+# align_to = list(foo = 1:4, bar = 6:10), |
|
3555 |
+# panel_fun = function(index, nm) { |
|
3556 |
+# grid.rect(gp = gpar(fill = col[nm])) |
|
3557 |
+# grid.text(nm, 0.5, 0.5) |
|
3558 |
+# }, |
|
3559 |
+# width = unit(2, "cm")) |
|
3560 |
+# ) |
|
3561 |
+anno_block = function(align_to = NULL, gp = gpar(), labels = NULL, labels_gp = gpar(), |
|
3505 | 3562 |
labels_rot = ifelse(which == "row", 90, 0), |
3506 | 3563 |
labels_offset = unit(0.5, "npc"), labels_just = "center", |
3507 | 3564 |
which = c("column", "row"), width = NULL, height = NULL, show_name = FALSE, |
3508 |
- graphics = NULL) { |
|
3565 |
+ panel_fun = NULL) { |
|
3509 | 3566 |
|
3510 | 3567 |
if(is.null(.ENV$current_annotation_which)) { |
3511 | 3568 |
which = match.arg(which)[1] |
3512 | 3569 |
} else { |
3513 | 3570 |
which = .ENV$current_annotation_which |
3514 | 3571 |
} |
3572 |
+ if(!is.null(align_to)) { |
|
3573 |
+ if(is.numeric(align_to)) { |
|
3574 |
+ align_to = list(v = align_to) |
|
3575 |
+ } |
|
3576 |
+ if(!is.list(align_to)) { |
|
3577 |
+ stop_wrap("`align_to` should be a list.") |
|
3578 |
+ } |
|
3579 |
+ if(is.null(names(align_to))) { |
|
3580 |
+ stop_wrap("`align_to` should be a named list.") |
|
3581 |
+ } |
|
3582 |
+ } |
|
3583 |
+ |
|
3515 | 3584 |
if(length(labels)) { |
3516 | 3585 |
if(which == "column") { |
3517 | 3586 |
if(missing(height)) { |
... | ... |
@@ -3534,10 +3603,40 @@ anno_block = function(gp = gpar(), labels = NULL, labels_gp = gpar(), |
3534 | 3603 |
} |
3535 | 3604 |
} |
3536 | 3605 |
|
3606 |
+ if(!is.null(panel_fun)) { |
|
3607 |
+ if(length(as.list(formals(panel_fun))) == 1) { |
|
3608 |
+ formals(panel_fun) = alist(index = , nm = NULL) |
|
3609 |
+ } |
|
3610 |
+ } |
|
3611 |
+ |
|
3537 | 3612 |
anno_size = anno_width_and_height(which, width, height, unit(5, "mm")) |
3538 | 3613 |
|
3539 | 3614 |
fun = function(index, k, n) { |
3540 |
- if(is.null(graphics)) { |
|
3615 |
+ if(!is.null(align_to)) { |
|
3616 |
+ is_in = sapply(align_to, function(x) any(x %in% index)) |
|
3617 |
+ |
|
3618 |
+ ind_aln = which(is_in) |
|
3619 |
+ |
|
3620 |
+ for(ai in ind_aln) { |
|
3621 |
+ ind = which(index %in% align_to[[ai]]) |
|
3622 |
+ if(any(diff(ind) > 1)) { |
|
3623 |
+ stop_wrap("Indices in `align_to` should be continuously adjacent in the heatmap.") |
|
3624 |
+ } |
|
3625 |
+ |
|
3626 |
+ ni = length(index) |
|
3627 |
+ |
|
3628 |
+ if(which == "row") { |
|
3629 |
+ pushViewport(viewport(y = (ni - ind[length(ind)])/ni, height = length(ind)/ni, default.units = "npc", just = "bottom")) |
|
3630 |
+ panel_fun(index[ind], names(align_to)[ai]) |
|
3631 |
+ popViewport() |
|
3632 |
+ } else { |
|
3633 |
+ pushViewport(viewport(x = (ind[length(ind)])/ni, width = length(ind)/ni, default.units = "npc", just = "right")) |
|
3634 |
+ panel_fun(index[ind], names(align_to)[ai]) |
|
3635 |
+ popViewport() |
|
3636 |
+ } |
|
3637 |
+ } |
|
3638 |
+ |
|
3639 |
+ } else if(is.null(panel_fun)) { |
|
3541 | 3640 |
gp = subset_gp(recycle_gp(gp, n), k) |
3542 | 3641 |
grid.rect(gp = gp) |
3543 | 3642 |
if(length(labels)) { |
... | ... |
@@ -3551,7 +3650,7 @@ anno_block = function(gp = gpar(), labels = NULL, labels_gp = gpar(), |
3551 | 3650 |
if(which == "row") x = labels_offset |
3552 | 3651 |
grid.text(label, x = x, y = y, gp = labels_gp, rot = labels_rot, just = labels_just) |
3553 | 3652 |
} |
3554 |
- } else { |
|
3653 |
+ } else { |
|
3555 | 3654 |
|
3556 | 3655 |
for(ifa in 1:30) { |
3557 | 3656 |
if(exists("ht_main", envir = parent.frame(ifa))) { |
... | ... |
@@ -3568,9 +3667,9 @@ anno_block = function(gp = gpar(), labels = NULL, labels_gp = gpar(), |
3568 | 3667 |
order_list = ht@column_order_list |
3569 | 3668 |
} |
3570 | 3669 |
if(is.null(split)) { |
3571 |
- graphics(index, NULL) |
|
3670 |
+ panel_fun(index, NULL) |
|
3572 | 3671 |
} else { |
3573 |
- graphics(index, unlist(split[order_list[[k]][1], ])) |
|
3672 |
+ panel_fun(index, unlist(split[order_list[[k]][1], ])) |
|
3574 | 3673 |
} |
3575 | 3674 |
} |
3576 | 3675 |
} |
... | ... |
@@ -3580,9 +3679,9 @@ anno_block = function(gp = gpar(), labels = NULL, labels_gp = gpar(), |
3580 | 3679 |
n = NA, |
3581 | 3680 |
fun_name = "anno_block", |
3582 | 3681 |
which = which, |
3583 |
- var_import = list(gp, labels, labels_gp, labels_rot, labels_offset, labels_just, graphics, which), |
|
3682 |
+ var_import = list(gp, labels, labels_gp, labels_rot, labels_offset, labels_just, panel_fun, which, align_to), |
|
3584 | 3683 |
subset_rule = list(), |
3585 |
- subsetable = TRUE, |
|
3684 |
+ subsettable = TRUE, |
|
3586 | 3685 |
height = anno_size$height, |
3587 | 3686 |
width = anno_size$width, |
3588 | 3687 |
show_name = show_name |
... | ... |
@@ -4087,7 +4186,7 @@ anno_zoom = function(align_to, panel_fun = function(index, nm = NULL) { grid.rec |
4087 | 4186 |
} |
4088 | 4187 |
} |
4089 | 4188 |
|
4090 |
- anno@subsetable = TRUE |
|
4189 |
+ anno@subsettable = TRUE |
|
4091 | 4190 |
return(anno) |
4092 | 4191 |
} |
4093 | 4192 |
|
... | ... |
@@ -4202,8 +4301,147 @@ anno_customize = function(x, graphics = list(), which = c("column", "row"), |
4202 | 4301 |
|
4203 | 4302 |
anno@subset_rule$value = subset_vector |
4204 | 4303 |
|
4205 |
- anno@subsetable = TRUE |
|
4304 |
+ anno@subsettable = TRUE |
|
4206 | 4305 |
|
4207 | 4306 |
return(anno) |
4208 | 4307 |
} |
4209 | 4308 |
|
4309 |
+ |
|
4310 |
+ |
|
4311 |
+# == title |
|
4312 |
+# Numeric labels annotation |
|
4313 |
+# |
|
4314 |
+# == param |
|
4315 |
+# -x A vector of numeric values. |
|
4316 |
+# -rg Range. A numeric vector of length two. |
|
4317 |
+# -labels_gp. Graphics parameters for labels. |
|
4318 |
+# -x_convert. A function applied on ``x``. E.g. when ``x`` contains p-values, to map ``x`` to the heights of bars, a transformation of ``-log10(x)`` |
|
4319 |
+# is normally applied. |
|
4320 |
+# -labels_format A function applied on ``x``. E.g., when ``x`` is a numeric, ``labels_format`` can be set to ``function(x) sprintf("\%.2f", x)``. |
|
4321 |
+# -labels_offset Offset of labels to the left or right of bars. |
|
4322 |
+# -bg_gp Graphics parameters for the background bars. |
|
4323 |
+# -bar_width Width of bars. Note it corresponds to the vertical direction. |
|
4324 |
+# -round_corners Whether to draw bars with round corners? |
|
4325 |
+# -r Radius of the round corners. |
|
4326 |
+# -which Row or column. Currently it only supports row annotation. |
|
4327 |
+# -align_to Which side bars as well as the labels are aligned to. Values can be "left" or "right". If ``x`` contains both positive and negative values, |
|
4328 |
+# ``align_to`` can also be set to 0 so that bars are aligned to ``pos = 0``. |
|
4329 |
+# -width Width of the annotation. |
|
4330 |
+# |
|
4331 |
+# == example |
|
4332 |
+# m = matrix(rnorm(100), 10) |
|
4333 |
+# x = numeric(10) |
|
4334 |
+# Heatmap(m, right_annotation = rowAnnotation(numeric = anno_numeric(x))) |
|
4335 |
+anno_numeric = function(x, rg = range(x), labels_gp = gpar(), x_convert = NULL, |
|
4336 |
+ labels_format = NULL, labels_offset = unit(4, "pt"), |
|
4337 |
+ bg_gp = gpar(fill = "#8080FF", col = "#8080FF"), |
|
4338 |
+ bar_width = unit(1, "npc") - unit(4, "pt"), |
|
4339 |
+ round_corners = TRUE, r = unit(0.05, "snpc"), |
|
4340 |
+ which = c("row", "column"), align_to = "left", width = NULL) { |
|
4341 |
+ |
|
4342 |
+ which = match.arg(which)[1] |
|
4343 |
+ if(which == "column") { |
|
4344 |
+ stop_wrap("`anno_numeric()` can only be used as row annotation.") |
|
4345 |
+ } |
|
4346 |
+ |
|
4347 |
+ if(!is.numeric(x)) { |
|
4348 |
+ stop_wrap("Input for `anno_numeric()` should be a numeric vector.") |
|
4349 |
+ } |
|
4350 |
+ |
|
4351 |
+ if(!is.null(labels_format)) { |
|
4352 |
+ labels = labels_format(x) |
|
4353 |
+ } else { |
|
4354 |
+ labels = x |
|
4355 |
+ } |
|
4356 |
+ |
|
4357 |
+ if(!is.null(x_convert)) { |
|
4358 |
+ x = x_convert(x) |
|
4359 |
+ rg = range(x_convert(rg)) |
|
4360 |
+ } |
|
4361 |
+ |
|
4362 |
+ x[x < rg[1]] = rg[1] |
|
4363 |
+ x[x > rg[2]] = rg[2] |
|
4364 |
+ |
|
4365 |
+ if(missing(align_to) && (any(x > 0) & any(x < 0))) { |
|
4366 |
+ align_to = 0 |
|
4367 |
+ } |
|
4368 |
+ |
|
4369 |
+ cell_fun_pct = function(i) { |
|
4370 |
+ |
|
4371 |
+ min_x = rg[1] |
|
4372 |
+ max_x = rg[2] |
|
4373 |
+ pushViewport(viewport(xscale = rg)) |
|
4374 |
+ if(align_to == "right") { |
|
4375 |
+ if(round_corners) { |
|
4376 |
+ grid.roundrect(x = unit(1, "npc"), |
|
4377 |
+ width = unit(x[i] - min_x, "native"), height = bar_width, r = r, |
|
4378 |
+ just = "right", gp = subset_gp(bg_gp, i)) |
|
4379 |
+ } else { |
|
4380 |
+ grid.rect(x = unit(1, "npc"), |
|
4381 |
+ width = unit(x[i] - min_x, "native"), height = bar_width, |
|
4382 |
+ just = "right", gp = subset_gp(bg_gp, i)) |
|
4383 |
+ } |
|
4384 |
+ grid.text(labels[i], x = unit(1, "npc") - labels_offset, just = "right", gp = subset_gp(labels_gp, i)) |
|
4385 |
+ } else if(align_to == "left") { |
|
4386 |
+ if(round_corners) { |
|
4387 |
+ grid.roundrect(x = unit(0, "npc"), |
|
4388 |
+ width = unit(x[i] - min_x, "native"), height = bar_width, r = r, |
|
4389 |
+ just = "left", gp = subset_gp(bg_gp, i)) |
|
4390 |
+ } else { |
|
4391 |
+ grid.rect(x = unit(0, "npc"), |
|
4392 |
+ width = unit(x[i] - min_x, "native"), height = bar_width, |
|
4393 |
+ just = "left", gp = subset_gp(bg_gp, i)) |
|
4394 |
+ } |
|
4395 |
+ grid.text(labels[i], x = unit(0, "npc") + labels_offset, just = "left", gp = subset_gp(labels_gp, i)) |
|
4396 |
+ } else if(align_to == 0) { |
|
4397 |
+ if(x[i] <= 0) { |
|
4398 |
+ if(round_corners) { |
|
4399 |
+ grid.roundrect(x = unit(0, "native"), |
|
4400 |
+ width = unit(-x[i], "native"), height = bar_width, r = r, |
|
4401 |
+ just = "right", gp = subset_gp(bg_gp, 1)) |
|
4402 |
+ } else { |
|
4403 |
+ grid.rect(x = unit(0, "native"), |
|
4404 |
+ width = unit(-x[i], "native"), height = bar_width, |
|
4405 |
+ just = "right", gp = subset_gp(bg_gp, 1)) |
|
4406 |
+ } |
|
4407 |
+ grid.text(labels[i], x = unit(0, "native") - labels_offset, just = "right", gp = subset_gp(labels_gp, 1)) |
|
4408 |
+ } else { |
|
4409 |
+ if(round_corners) { |
|
4410 |
+ grid.roundrect(x = unit(0, "native"), |
|
4411 |
+ width = unit(x[i], "native"), height = bar_width, r = r, |
|
4412 |
+ just = "left", gp = subset_gp(bg_gp, 2)) |
|
4413 |
+ } else { |
|
4414 |
+ grid.rect(x = unit(0, "native"), |
|
4415 |
+ width = unit(x[i], "native"), height = bar_width, |
|
4416 |
+ just = "left", gp = subset_gp(bg_gp, 2)) |
|
4417 |
+ } |
|
4418 |
+ grid.text(labels[i], x = unit(0, "native") + labels_offset, just = "left", gp = subset_gp(labels_gp, 2)) |
|
4419 |
+ } |
|
4420 |
+ } |
|
4421 |
+ popViewport() |
|
4422 |
+ } |
|
4423 |
+ |
|
4424 |
+ if(is.null(width)) { |
|
4425 |
+ if(align_to == "left" || align_to == "right") { |
|
4426 |
+ width = convertWidth(max(unit.c(unit(2, "cm"), max_text_width(labels, gp = labels_gp) + labels_offset*2)), "mm") |
|
4427 |
+ } else { |
|
4428 |
+ l1 = x >= 0 |
|
4429 |
+ l2 = x < 0 |
|
4430 |
+ if(any(l1) && any(l2)) { |
|
4431 |
+ w1 = max_text_width(labels[l1], gp = subset_gp(labels_gp, l1)) + labels_offset*2 |
|
4432 |
+ w2 = max_text_width(labels[l2], gp = subset_gp(labels_gp, l2)) + labels_offset*2 |
|
4433 |
+ width = convertWidth(max(unit.c(unit(2, "cm"), w1 + w2)), "mm") |
|
4434 |
+ |
|
4435 |
+ } else { |
|
4436 |
+ width = convertWidth(max(unit.c(unit(2, "cm"), max_text_width(labels, gp = labels_gp) + labels_offset*2)), "mm") |
|
4437 |
+ } |
|
4438 |
+ } |
|
4439 |
+ } |
|
4440 |
+ AnnotationFunction( |
|
4441 |
+ cell_fun = cell_fun_pct, |
|
4442 |
+ var_import = list(rg, labels, x, labels_gp, align_to, bg_gp, bar_width, labels_offset, round_corners, r), |
|
4443 |
+ which = "row", |
|
4444 |
+ width = width |
|
4445 |
+ ) |
|
4446 |
+} |
|
4447 |
+ |
... | ... |
@@ -974,7 +974,17 @@ Heatmap = function(matrix, col, name, |
974 | 974 |
.Object@heatmap_param$height = heatmap_height |
975 | 975 |
.Object@heatmap_param$show_heatmap_legend = show_heatmap_legend |
976 | 976 |
.Object@heatmap_param$use_raster = use_raster |
977 |
- .Object@heatmap_param$raster_device = match.arg(raster_device)[1] |
|
977 |
+ |
|
978 |
+ if(missing(raster_device)) { |
|
979 |
+ if(requireNamespace("Cairo", quietly = TRUE)) { |
|
980 |
+ raster_device = "CairoPNG" |
|
981 |
+ } else { |
|
982 |
+ raster_device = "png" |
|
983 |
+ } |
|
984 |
+ } else { |
|
985 |
+ raster_device = match.arg(raster_device)[1] |
|
986 |
+ } |
|
987 |
+ .Object@heatmap_param$raster_device = raster_device |
|
978 | 988 |
.Object@heatmap_param$raster_quality = raster_quality |
979 | 989 |
.Object@heatmap_param$raster_device_param = raster_device_param |
980 | 990 |
.Object@heatmap_param$raster_resize_mat = raster_resize_mat |
... | ... |
@@ -25,7 +25,7 @@ HeatmapAnnotation = setClass("HeatmapAnnotation", |
25 | 25 |
width = "ANY", |
26 | 26 |
height = "ANY", |
27 | 27 |
gap = "ANY", |
28 |
- subsetable = "logical", |
|
28 |
+ subsettable = "logical", |
|
29 | 29 |
extended = "ANY", |
30 | 30 |
param = "list" |
31 | 31 |
), |
... | ... |
@@ -33,7 +33,7 @@ HeatmapAnnotation = setClass("HeatmapAnnotation", |
33 | 33 |
anno_list = list(), |
34 | 34 |
which = "column", |
35 | 35 |
gap = unit(0, "mm"), |
36 |
- subsetable = FALSE, |
|
36 |
+ subsettable = FALSE, |
|
37 | 37 |
extended = unit(c(0, 0, 0, 0), "mm"), |
38 | 38 |
param = list() |
39 | 39 |
), |
... | ... |
@@ -526,7 +526,7 @@ HeatmapAnnotation = function(..., |
526 | 526 |
.Object@width = width |
527 | 527 |
.Object@height = height |
528 | 528 |
|
529 |
- .Object@subsetable = all(sapply(anno_list, function(x) x@subsetable)) |
|
529 |
+ .Object@subsettable = all(sapply(anno_list, function(x) x@subsettable)) |
|
530 | 530 |
extended = unit(c(0, 0, 0, 0), "mm") |
531 | 531 |
for(i in 1:4) { |
532 | 532 |
extended[i] = unit(max(sapply(anno_list, function(anno) { |
... | ... |
@@ -795,7 +795,7 @@ setMethod(f = "show", |
795 | 795 |
cat(" items:", ifelse(length(len), len[1], "unknown"), "\n") |
796 | 796 |
cat(" width:", as.character(object@width), "\n") |
797 | 797 |
cat(" height:", as.character(object@height), "\n") |
798 |
- cat(" this object is ", ifelse(object@subsetable, "", "not "), "subsetable\n", sep = "") |
|
798 |
+ cat(" this object is ", ifelse(object@subsettable, "", "not "), "subsettable\n", sep = "") |
|
799 | 799 |
dirt = c("bottom", "left", "top", "right") |
800 | 800 |
for(i in 1:4) { |
801 | 801 |
if(!identical(unit(0, "mm"), object@extended[i])) { |
... | ... |
@@ -36,7 +36,7 @@ SingleAnnotation = setClass("SingleAnnotation", |
36 | 36 |
width = "ANY", |
37 | 37 |
height = "ANY", |
38 | 38 |
extended = "ANY", |
39 |
- subsetable = "logical" |
|
39 |
+ subsettable = "logical" |
|
40 | 40 |
), |
41 | 41 |
prototype = list( |
42 | 42 |
color_mapping = NULL, |
... | ... |
@@ -45,7 +45,7 @@ SingleAnnotation = setClass("SingleAnnotation", |
45 | 45 |
color_is_random = FALSE, |
46 | 46 |
name_to_data_vp = FALSE, |
47 | 47 |
extended = unit(c(0, 0, 0, 0), "mm"), |
48 |
- subsetable = FALSE |
|
48 |
+ subsettable = FALSE |
|
49 | 49 |
) |
50 | 50 |
) |
51 | 51 |
|
... | ... |
@@ -548,7 +548,7 @@ SingleAnnotation = function(name, value, col, fun, |
548 | 548 |
} |
549 | 549 |
|
550 | 550 |
.Object@show_legend = show_legend |
551 |
- .Object@subsetable = TRUE |
|
551 |
+ .Object@subsettable = TRUE |
|
552 | 552 |
} else { |
553 | 553 |
|
554 | 554 |
f_which = fun@which |
... | ... |
@@ -579,7 +579,7 @@ SingleAnnotation = function(name, value, col, fun, |
579 | 579 |
.Object@height = height |
580 | 580 |
.Object@fun@height = height |
581 | 581 |
} |
582 |
- .Object@subsetable = .Object@fun@subsetable |
|
582 |
+ .Object@subsettable = .Object@fun@subsettable |
|
583 | 583 |
} |
584 | 584 |
|
585 | 585 |
return(.Object) |
... | ... |
@@ -774,7 +774,7 @@ setMethod(f = "show", |
774 | 774 |
|
775 | 775 |
cat(" width:", as.character(object@width), "\n") |
776 | 776 |
cat(" height:", as.character(object@height), "\n") |
777 |
- cat(" this object is", ifelse(object@subsetable, "\b", "not"), "subsetable\n") |
|
777 |
+ cat(" this object is", ifelse(object@subsettable, "\b", "not"), "subsettable\n") |
|
778 | 778 |
dirt = c("bottom", "left", "top", "right") |
779 | 779 |
for(i in 1:4) { |
780 | 780 |
if(!identical(unit(0, "mm"), object@extended[i])) { |
... | ... |
@@ -816,9 +816,9 @@ has_AnnotationFunction = function(single_anno) { |
816 | 816 |
# -i A vector of indices. |
817 | 817 |
# |
818 | 818 |
# == details |
819 |
-# The SingleAnnotation class object is subsetable only if the containing `AnnotationFunction-class` |
|
820 |
-# object is subsetable. All the ``anno_*`` functions are subsetable, so if the SingleAnnotation object |
|
821 |
-# is constructed by one of these functions, it is also subsetable. |
|
819 |
+# The SingleAnnotation class object is subsettable only if the containing `AnnotationFunction-class` |
|
820 |
+# object is subsettable. All the ``anno_*`` functions are subsettable, so if the SingleAnnotation object |
|
821 |
+# is constructed by one of these functions, it is also subsettable. |
|
822 | 822 |
# |
823 | 823 |
# == example |
824 | 824 |
# ha = SingleAnnotation(value = 1:10) |
... | ... |
@@ -829,7 +829,7 @@ has_AnnotationFunction = function(single_anno) { |
829 | 829 |
if(nargs() == 2) { |
830 | 830 |
x2 = x |
831 | 831 |
if(inherits(x@fun, "AnnotationFunction")) { |
832 |
- if(x@fun@subsetable) { |
|
832 |
+ if(x@fun@subsettable) { |
|
833 | 833 |
x2@fun = x@fun[i] |
834 | 834 |
if(x@which == "row") { |
835 | 835 |
x2@width = x2@fun@width |
836 | 836 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,419 @@ |
1 |
+ |
|
2 |
+# == title |
|
3 |
+# A simple grob for the word cloud |
|
4 |
+# |
|
5 |
+# == param |
|
6 |
+# -text A vector of texts. The value can be single words or phrases/sentenses. |
|
7 |
+# -x X position. |
|
8 |
+# -y Y position. |
|
9 |
+# -just Justification of the box in the viewport. |
|
10 |
+# -gp Graphics parameters of texts. |
|
11 |
+# -background_gp Graphics parameters for the box. |
|
12 |
+# -round_corners Whether to draw round corners for the box. |
|
13 |
+# -r Radius of the round corners. |
|
14 |
+# -line_space Space between lines. The value can be a `grid::unit` object or a numeric scalar which is measured in mm. |
|
15 |
+# -word_space Space between texts The value can be a `grid::unit` object or a numeric scalar which is measured in mm. |
|
16 |
+# -max_width The maximal width of the viewport to put the word cloud. The value can be a `grid::unit` object or a numeric scalar which is measured in mm. |
|
17 |
+# Note this might be larger than the final width of the returned grob object. |
|
18 |
+# -padding Padding of the box, i.e. space between text and the four box borders. The value should be a `grid::unit` object with length 1, 2 or 4. If |
|
19 |
+# length of the input unit is 2, the first value is the padding both to the top and to the bottom, and the second value is the padding to the left and right. |
|
20 |
+# If length of the input unit is 4, the four values correspond to paddings to the bottom, left, top and right of the box. |
|
21 |
+# -first_text_from Should the texts be added from the top of the box or from the bottom? Value should be either "top" or "bottom". |
|
22 |
+# -add_new_line Whether to add new line after every text? If ``TRUE``, each text will be in a separated line. |
|
23 |
+# -word_wrap Whether to apply word wrap for phrases/sentenses. |
|
24 |
+# |
|
25 |
+# == value |
|
26 |
+# A `grid::grob` object. The width and height of the grob can be get by `grid::grobWidth` and `grid::grobHeight`. |
|
27 |
+# |
|
28 |
+# == example |
|
29 |
+# words = sapply(1:30, function(x) strrep(sample(letters, 1), sample(3:10, 1))) |
|
30 |
+# grid.newpage() |
|
31 |
+# grid.text_box(words, gp = gpar(fontsize = runif(30, min = 5, max = 30))) |
|
32 |
+# |
|
33 |
+# sentenses = c("This is sentense 1", "This is a long long long long long long long sentense.") |
|
34 |
+# grid.newpage() |
|
35 |
+# grid.text_box(sentenses) |
|
36 |
+# grid.text_box(sentenses, word_wrap = TRUE) |
|
37 |
+# grid.text_box(sentenses, word_wrap = TRUE, add_new_line = TRUE) |
|
38 |
+# |
|
39 |
+text_box_grob = function(text, x = unit(0.5, "npc"), y = unit(0.5, "npc"), just = "centre", |
|
40 |
+ gp = gpar(), background_gp = gpar(col = "black", fill = "transparent"), round_corners = FALSE, r = unit(0.1, "snpc"), |
|
41 |
+ line_space = unit(4, "pt"), text_space = unit(4, "pt"), max_width = unit(100, "mm"), |
|
42 |
+ padding = unit(4, "pt"), first_text_from = "top", add_new_line = FALSE, word_wrap = FALSE) { # width in mm |
|
43 |
+ |
|
44 |
+ n_text = length(text) |
|
45 |
+ if(is.null(gp$col)) { |
|
46 |
+ if(package_version(packageDescription("circlize", fields = "Version")) < "0.4.14") { |
|
47 |
+ stop_wrap("Random color generation needs circlize package >= 0.4.14. Please upgrade it.") |
|
48 |
+ } |
|
49 |
+ gp$col = rand_color(n_text, friendly = TRUE) |
|
50 |
+ } |
|
51 |
+ for(nm in c("fontsize", "fontfamily", "fontface")) { |
|
52 |
+ if(is.null(gp[[nm]])) { |
|
53 |
+ gp[[nm]] = rep(get.gpar(nm)[[1]], n_text) |
|
54 |
+ } |
|
55 |
+ } |
|
56 |
+ |
|
57 |
+ gp = recycle_gp(gp, n_text) |
|
58 |
+ |
|
59 |
+ vp_x = x |
|
60 |
+ vp_y = y |
|
61 |
+ vp_just = just |
|
62 |
+ |
|
63 |
+ text_lt = list(text = text, space_after = rep(TRUE, n_text), new_line_after = rep(FALSE, n_text)) |
|
64 |
+ if(add_new_line && !word_wrap) { |
|
65 |
+ text_lt$new_line_after = rep(TRUE, n_text) |
|
66 |
+ } else if(word_wrap) { |
|
67 |
+ |
|
68 |
+ if(first_text_from == "bottom") { |
|
69 |
+ od = rev(seq_len(n_text)) |
|
70 |
+ text = text[od] |
|
71 |
+ gp = subset_gp(gp, od) |
|
72 |
+ first_text_from = "top" |
|
73 |
+ } |
|
74 |
+ |
|
75 |
+ words = strsplit(text, "\\s+") |
|
76 |
+ words = lapply(words, function(x) { |
|
77 |
+ n = length(x) |
|
78 |
+ x2 = rep(" ", 2*n - 1) |
|
79 |
+ x2[2*(1:n) - 1] = x |
|
80 |
+ x2 |
|
81 |
+ }) |
|
82 |
+ nw = sapply(words, length) |
|
83 |
+ |
|
84 |
+ gp2 = gpar() |
|
85 |
+ gp2$col = rep(gp$col, times = nw) |
|
86 |
+ gp2$fontsize = rep(gp$fontsize, times = nw) |
|
87 |
+ gp2$fontfamily = rep(gp$fontfamily, times = nw) |
|
88 |
+ gp2$fontface = rep(gp$fontface, times = nw) |
|
89 |
+ |
|
90 |
+ text_lt = list(text = unlist(words), space_after = rep(FALSE, sum(nw)), new_line_after = rep(FALSE, sum(nw))) |
|
91 |
+ text_lt$space_after[cumsum(nw)] = TRUE |
|
92 |
+ if(add_new_line) { |
|
93 |
+ text_lt$new_line_after[cumsum(nw)] = TRUE |
|
94 |
+ } |
|
95 |
+ gp = gp2 |
|
96 |
+ } |
|
97 |
+ |
|
98 |
+ if(length(dev.list()) == 0) { |
|
99 |
+ dev.new() |
|
100 |
+ } |
|
101 |
+ |
|
102 |
+ n = length(text_lt$text) |
|
103 |
+ text_gb_lt = lapply(seq_len(n), function(i) textGrob(text_lt$text[i], gp = subset_gp(gp, i))) |
|
104 |
+ text_width = vapply(text_gb_lt, function(gb) convertWidth(grobWidth(gb), "mm", valueOnly = TRUE), 0) |
|
105 |
+ text_height = vapply(text_gb_lt, function(gb) convertHeight(grobHeight(gb), "mm", valueOnly = TRUE), 0) |
|
106 |
+ |
|
107 |
+ if(is.unit(line_space)) line_space = convertHeight(line_space, "mm", valueOnly = TRUE) |
|
108 |
+ if(is.unit(text_space)) text_space = convertWidth(text_space, "mm", valueOnly = TRUE) |
|
109 |
+ |
|
110 |
+ x = numeric(n) |
|
111 |
+ y = numeric(n) |
|
112 |
+ |
|
113 |
+ if(is.unit(max_width)) { |
|
114 |
+ max_width = convertWidth(max_width, "mm", valueOnly = TRUE) |
|
115 |
+ } |
|
116 |
+ |
|
117 |
+ w = max(text_width) |
|
118 |
+ max_width = max(max_width, max(text_width)) |
|
119 |
+ |
|
120 |
+ if(first_text_from == "bottom") { |
|
121 |
+ # the first text |
|
122 |
+ current_line_width = text_width[1] |
|
123 |
+ x[1] = 0 |
|
124 |
+ y[1] = 0 |
|
125 |
+ |
|
126 |
+ h = text_height[1] |
|
127 |
+ |
|
128 |
+ for(i in seq_len(n)[-1]) { |
|
129 |
+ # the next text can be put on the same line |
|
130 |
+ if(current_line_width + text_width[i] + text_space > max_width || text_lt$new_line_after[i-1]) { |
|
131 |
+ x[i] = 0 |
|
132 |
+ y[i] = h + line_space |
|
133 |
+ current_line_width = text_width[i] |
|
134 |
+ w = max(w, current_line_width) |
|
135 |
+ h = y[i] + text_height[i] |
|
136 |
+ |
|
137 |
+ } else { |
|
138 |
+ x[i] = current_line_width + text_space*text_lt$space_after[i-1] |
|
139 |
+ y[i] = y[i-1] # same as previous one |
|
140 |
+ current_line_width = x[i] + text_width[i] |
|
141 |
+ w = max(w, current_line_width) |
|
142 |
+ h = max(h, y[i] + text_height[i]) |
|
143 |
+ } |
|
144 |
+ } |
|
145 |
+ just = c(0, 0) |
|
146 |
+ } else if(first_text_from == "top") { |
|
147 |
+ current_line_width = text_width[1] |
|
148 |
+ x[1] = 0 |
|
149 |
+ y[1] = 0 |
|
150 |
+ |
|
151 |
+ h = -text_height[1] |
|
152 |
+ |
|
153 |
+ prev_line_ind = 1 |
|
154 |
+ |
|
155 |
+ for(i in seq_len(n)[-1]) { |
|
156 |
+ if(current_line_width + text_width[i] + text_space > max_width || text_lt$new_line_after[i-1]) { |
|
157 |
+ y[prev_line_ind] = h |
|
158 |
+ |
|
159 |
+ prev_line_ind = i |
|
160 |
+ x[i] = 0 |
|
161 |
+ y[i] = h - line_space |
|
162 |
+ current_line_width = text_width[i] |
|
163 |
+ w = max(w, current_line_width) |
|
164 |
+ h = y[i] - text_height[i] |
|
165 |
+ } else { |
|
166 |
+ x[i] = current_line_width + text_space*text_lt$space_after[i-1] |
|
167 |
+ y[i] = y[i-1] # same as previous one |
|
168 |
+ current_line_width = x[i] + text_width[i] |
|
169 |
+ w = max(w, current_line_width) |
|
170 |
+ h = min(h, y[i] - text_height[i]) |
|
171 |
+ |
|
172 |
+ prev_line_ind = c(prev_line_ind, i) |
|
173 |
+ } |
|
174 |
+ } |
|
175 |
+ y[prev_line_ind] = h |
|
176 |
+ y = y - h |
|
177 |
+ h = -h |
|
178 |
+ |
|
179 |
+ just = c(0, 0) |
|
180 |
+ } else { |
|
181 |
+ stop("`first_text_from` can be 'top' or 'bottom'") |
|
182 |
+ } |
|
183 |
+ |
|
184 |
+ if(length(padding) == 1) { |
|
185 |
+ padding = rep(padding, 4) |
|
186 |
+ } else if(length(padding) == 2) { |
|
187 |
+ padding = unit.c(padding[1], padding[2], padding[1], padding[2]) |
|
188 |
+ } |
|
189 |
+ padding = convertWidth(padding, "mm", valueOnly = TRUE) |
|
190 |
+ |
|
191 |
+ w = w + padding[2] + padding[4] |
|
192 |
+ h = h + padding[1] + padding[3] |
|
193 |
+ x = x + padding[2] |
|
194 |
+ y = y + padding[1] |
|
195 |
+ |
|
196 |
+ gl = gList( |
|
197 |
+ if(round_corners) { |
|
198 |
+ roundrectGrob(gp = background_gp, r = r) |
|
199 |
+ } else { |
|
200 |
+ rectGrob(gp = background_gp) |
|
201 |
+ }, |
|
202 |
+ textGrob(text_lt$text, x = x, y = y, gp = gp, default.units = "mm", just = just) |
|
203 |
+ # rectGrob(x = x, y = y, width = text_width, height = text_height, default.units = "mm", just = c(0, 0)) |
|
204 |
+ ) |
|
205 |
+ |
|
206 |
+ gb = gTree(children = gl, cl = "text_box", |
|
207 |
+ vp = viewport(x = vp_x, y = vp_y, just = vp_just, width = unit(w, "mm"), |
|
208 |
+ height = unit(h, "mm"))) |
|
209 |
+ return(gb) |
|
210 |
+} |
|
211 |
+ |
|
212 |
+# == title |
|
213 |
+# Width for text_box grob |
|
214 |
+# |
|
215 |
+# == param |
|
216 |
+# -x The ``text_box`` grob returned by `text_boxd_grob`. |
|
217 |
+# |
|
218 |
+# == value |
|
219 |
+# A `grid::unit` object. |
|
220 |
+widthDetails.text_box = function(x) { |
|
221 |
+ x$vp$width |
|
222 |
+} |
|
223 |
+ |
|
224 |
+# == title |
|
225 |
+# Height for text_box grob |
|
226 |
+# |
|
227 |
+# == param |
|
228 |
+# -x The ``text_box`` grob returned by `text_box_grob`. |
|
229 |
+# |
|
230 |
+# == value |
|
231 |
+# A `grid::unit` object. |
|
232 |
+heightDetails.text_box = function(x) { |
|
233 |
+ x$vp$height |
|
234 |
+} |
|
235 |
+ |
|
236 |
+# == title |
|
237 |
+# Draw multiple texts in a box |
|
238 |
+# |
|
239 |
+# == param |
|
240 |
+# -text A vector of texts. The value can be single words or phrases/sentenses. |
|
241 |
+# -x X position. |
|
242 |
+# -y Y position. |
|
243 |
+# -gp Graphics parameters of texts. |
|
244 |
+# -... Pass to `text_box_grob`. |
|
245 |
+# |
|
246 |
+# == details |
|
247 |
+# All details can be found in the help page of `text_box_grob`. |
|
248 |
+# |
|
249 |
+grid.text_box = function(text, x = unit(0.5, "npc"), y = unit(0.5, "npc"), gp = gpar(), ...) { |
|
250 |
+ gb = text_box_grob(text, x = x, y = y, gp = gp, ...) |
|
251 |
+ grid.draw(gb) |
|
252 |
+} |
|
253 |
+ |
|
254 |
+ |
|
255 |
+# == title |
|
256 |
+# Text box annotations |
|
257 |
+# |
|
258 |
+# == param |
|
259 |
+# -align_to It controls how the text boxes are aligned to the heatmap rows. The value can be a categorical vector which have the same |
|
260 |
+# length as heatmap rows, or a list of row indices. |
|
261 |
+# -text The corresponding texts. The value should be a list of texts. To control graphics parameters of texts in the boxes, The value |
|
262 |
+# of ``text`` can also be set as a list of data frames where the first column contains the text, from the second column contains |
|
263 |
+# graphics parameters for each text. The column names should be "col", "fontsize", "fontfamily" and "fontface". |
|
264 |
+# -background_gp Graphics for the background. |
|
265 |
+# -which Only "row" is allowed. |
|
266 |
+# -by Are text boxed arranged by `anno_link` or by `anno_block`? |
|
267 |
+# -side Side of the annotation to the heatmap. |
|
268 |
+# -... Pass to `text_box_grob`. |
|
269 |
+# |
|
270 |
+# == example |
|
271 |
+# require(circlize) |
|
272 |
+# mat = matrix(rnorm(100*10), nrow = 100) |
|
273 |
+# |
|
274 |
+# split = sample(letters[1:10], 100, replace = TRUE) |
|
275 |
+# text = lapply(unique(split), function(x) { |
|
276 |
+# data.frame(month.name, col = rand_color(12, friendly = TRUE), fontsize = runif(12, 6, 14)) |
|
277 |
+# }) |
|
278 |
+# names(text) = unique(split) |
|
279 |
+# |
|
280 |
+# Heatmap(mat, cluster_rows = FALSE, row_split = split, |
|
281 |
+# right_annotation = rowAnnotation(wc = anno_text_box(split, text)) |
|
282 |
+# ) |
|
283 |
+anno_text_box = function(align_to, text, background_gp = gpar(fill = "#DDDDDD", col = "#AAAAAA"), |
|
284 |
+ which = c("row", "column"), by = "anno_link", side = c("right", "left"), ...) { |
|
285 |
+ |
|
286 |
+ if(is.null(background_gp$fill)) background_gp$fill = "#DDDDDD" |
|
287 |
+ if(is.null(background_gp$col)) background_gp$col = "#AAAAAA" |
|
288 |
+ if(is.null(background_gp$lty)) background_gp$lty = 1 |
|
289 |
+ if(is.null(background_gp$lwd)) background_gp$lwd = 1 |
|
290 |
+ |
|
291 |
+ which = match.arg(which)[1] |
|
292 |
+ if(which == "column") { |
|
293 |
+ stop_wrap("`anno_text_box()` can only be used as row annotation.") |
|
294 |
+ } |
|
295 |
+ |
|
296 |
+ # 1. align_to numeric index, text: a data frame |
|
297 |
+ if(is.numeric(align_to) && (is.character(text) || is.data.frame(text))) { |
|
298 |
+ align_to = list(v = align_to) |
|
299 |
+ text = list(v = text) |
|
300 |
+ } else if(is.atomic(align_to) && is.list(text)) { |
|
301 |
+ align_to = split(seq_along(align_to), align_to) |
|
302 |
+ |
|
303 |
+ cn = intersect(names(align_to), names(text)) |
|
304 |
+ if(length(cn) == 0) { |
|
305 |
+ stop_wrap("names of `text` should have overlap to levels in `align_to`.") |
|
306 |
+ } else { |
|
307 |
+ align_to = align_to[cn] |
|
308 |
+ text = text[cn] |
|
309 |
+ } |
|
310 |
+ } else if(is.list(align_to)) { |
|
311 |
+ if(!is.list(text)) { |
|
312 |
+ stop_wrap("Since `align_to` is a list, `text` should have the same format as `align_to`, which is a list. The elements in the list can either be character vectors or data frames that contain texts and graphics parameters.") |
|
313 |
+ } else { |
|
314 |
+ if(length(align_to) != length(text)) { |
|
315 |
+ stop_wrap("`align_to` and `text` should be two list with the same length.") |
|
316 |
+ } |
|
317 |
+ } |
|
318 |
+ if(!is.null(names(align_to)) && !is.null(names(text))) { |
|
319 |
+ if(length(setdiff(names(align_to), names(text))) == 0) { |
|
320 |
+ text = text[names(align_to)] |
|
321 |
+ } else { |
|
322 |
+ stop_wrap("Since `align_to` and `text` are all lists. They should have the same set of names.") |
|
323 |
+ } |
|
324 |
+ } else { |
|
325 |
+ stop_wrap("Since `align_to` and `text` are all lists. They should have the same set of names.") |
|
326 |
+ } |
|
327 |
+ } else { |
|
328 |
+ stop_wrap("Format of `align_to` or `text` is wrong.") |
|
329 |
+ } |
|
330 |
+ |
|
331 |
+ # a list of text_box grobs |
|
332 |
+ dev.null() |
|
333 |
+ |
|
334 |
+ gbl = lapply(text, function(x) { |
|
335 |
+ if(is.atomic(x)) { |
|
336 |
+ text_box_grob(text = x, background_gp = gpar(col = NA, fill = "transparent"), ...) |
|
337 |
+ } else if(is.data.frame(x)) { |
|
338 |
+ if("col" %in% colnames(x)) { |
|
339 |
+ col = x$col |
|
340 |
+ } else { |
|
341 |
+ col = get.gpar("col")[[1]] |
|
342 |
+ } |
|
343 |
+ |
|
344 |
+ if("fontsize" %in% colnames(x)) { |
|
345 |
+ fontsize = x$fontsize |
|
346 |
+ } else { |
|
347 |
+ fontsize = get.gpar("fontsize")[[1]] |
|
348 |
+ } |
|
349 |
+ |
|
350 |
+ if("fontfamily" %in% colnames(x)) { |
|
351 |
+ fontfamily = x$fontfamily |
|
352 |
+ } else { |
|
353 |
+ fontfamily = get.gpar("fontfamily")[[1]] |
|
354 |
+ } |
|
355 |
+ |
|
356 |
+ if("fontface" %in% colnames(x)) { |
|
357 |
+ fontface = x$fontface |
|
358 |
+ } else { |
|
359 |
+ fontface = get.gpar("fontface")[[1]] |
|
360 |
+ } |
|
361 |
+ text_box_grob(text = x[[1]], gp = gpar(col = col, fontsize = fontsize, fontfamily = fontfamily, fontface = fontface), |
|
362 |
+ background_gp = gpar(col = NA, fill = "transparent"), ...) |
|
363 |
+ } |
|
364 |
+ }) |
|
365 |
+ |
|
366 |
+ margin = unit(0, "pt") |
|
367 |
+ gbl_h = lapply(gbl, function(x) convertHeight(grobHeight(x), "cm") + margin) |
|
368 |
+ gbl_h = do.call(unit.c, gbl_h) |
|
369 |
+ |
|
370 |
+ gbl_w = lapply(gbl, function(x) convertWidth(grobWidth(x), "cm")) |
|
371 |
+ gbl_w = do.call(unit.c, gbl_w) |
|
372 |
+ gbl_w = max(gbl_w) + margin |
|
373 |
+ |
|
374 |
+ dev.off2() |
|
375 |
+ |
|
376 |
+ side = match.arg(side)[1] |
|
377 |
+ |
|
378 |
+ if(by %in% c("anno_link", "anno_zoom")) { |
|
379 |
+ panel_fun = function(index, nm) { |
|
380 |
+ pushViewport(viewport()) |
|
381 |
+ grid.rect(gp = gpar(fill = background_gp$fill, col = background_gp$fill, lty = background_gp$lty, lwd = background_gp$lwd)) |
|
382 |
+ if(side == "right") { |
|
383 |
+ grid.lines(c(0, 1, 1, 0), c(0, 0, 1, 1), gp = gpar(col = background_gp$col, lty = background_gp$lty, lwd = background_gp$lwd), default.units = "npc") |
|
384 |
+ } else { |
|
385 |
+ grid.lines(c(1, 0, 0, 1), c(0, 0, 1, 1), gp = gpar(col = background_gp$col, lty = background_gp$lty, lwd = background_gp$lwd), default.units = "npc") |
|
386 |
+ } |
|
387 |
+ pushViewport(viewport(width = unit(1, "npc") - margin, height = unit(1, "npc") - margin)) |
|
388 |
+ gb = gbl[[nm]] |
|
389 |
+ gb$vp$x = gb$vp$width*0.5 |
|
390 |
+ gb$vp$y = gb$vp$height*0.5 |
|
391 |
+ grid.draw(gb) |
|
392 |
+ popViewport() |
|
393 |
+ popViewport() |
|
394 |
+ } |
|
395 |
+ |
|
396 |
+ anno = anno_link(align_to = align_to, which = "row", panel_fun = panel_fun, |
|
397 |
+ size = gbl_h, gap = unit(2, "mm"), width = gbl_w + unit(5, "mm"), |
|
398 |
+ link_gp = background_gp, internal_line = FALSE, side = side) |
|
399 |
+ } else { |
|
400 |
+ panel_fun = function(index, nm) { |
|
401 |
+ pushViewport(viewport()) |
|