Browse code

add show_name in anno_empty()

Zuguang Gu authored on 03/02/2022 09:53:48
Showing 34 changed files

... ...
@@ -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())