Browse code

add a line at dendrogram

Zuguang Gu authored on 24/10/2018 13:37:30
Showing18 changed files

... ...
@@ -4,6 +4,7 @@ This a major update of the package. The main changes are:
4 4
 * support column split
5 5
 * support align heatmaps vertically
6 6
 * add a naive `AnnotationFunction` class to handle annotation functions
7
+* add more annotation functions
7 8
 
8 9
 =======================
9 10
 
... ...
@@ -60,12 +60,12 @@ AdditiveUnit = function(...) {
60 60
 "+.AdditiveUnit" = function(x, y) {
61 61
     if(inherits(x, "HeatmapAnnotation")) {
62 62
     	if(x@which != "row") {
63
-    		stop("You should specify `which` to `row` or use `rowAnnotation()` directly if you want to add row annotations.")
63
+    		stop_wrap("You should specify `which = row` or use `rowAnnotation()` directly if you want to add row annotations horizontally.")
64 64
     	}
65 65
     }
66 66
     if(inherits(y, "HeatmapAnnotation")) {
67 67
     	if(y@which != "row") {
68
-            stop("You should specify `which` to `row` or use `rowAnnotation()` directly if you want to add row annotations.")
68
+            stop_wrap("You should specify `which = row` or use `rowAnnotation()` directly if you want to add row annotations horizontally.")
69 69
     	}
70 70
     }
71 71
     if(is.null(x)) {
... ...
@@ -112,12 +112,12 @@ AdditiveUnit = function(...) {
112 112
 "%v%" = function(x, y) {
113 113
     if(inherits(x, "HeatmapAnnotation")) {
114 114
         if(x@which != "column") {
115
-            stop("You should specify `which` to `column` or use `columnAnnotation()` directly if you want to add column annotations vertically.")
115
+            stop_wrap("You should specify `which = column` or use `columnAnnotation()` directly if you want to add column annotations vertically.")
116 116
         }
117 117
     }
118 118
     if(inherits(y, "HeatmapAnnotation")) {
119 119
         if(y@which != "column") {
120
-            stop("You should specify `which` to `column` or use `columnAnnotation()` directly if you want to add column annotations vertically.")
120
+            stop_wrap("You should specify `which = column` or use `columnAnnotation()` directly if you want to add column annotations vertically.")
121 121
         }
122 122
     }
123 123
     if(is.null(x)) {
... ...
@@ -1856,7 +1856,7 @@ anno_text = function(x, which = c("column", "row"), gp = gpar(),
1856 1856
 	rot = rot[1] %% 360
1857 1857
 	just = just[1]
1858 1858
 	if(!missing(offset)) {
1859
-		warning("`offset` is deprecated, use `location` instead.")
1859
+		warning_wrap("`offset` is deprecated, use `location` instead.")
1860 1860
 		if(missing(location)) {
1861 1861
 			location = offset
1862 1862
 		}
... ...
@@ -73,12 +73,12 @@ ColorMapping = function(name, colors = NULL, levels = NULL,
73 73
 	if(!is.null(colors)) {
74 74
 		if(is.null(levels)) {
75 75
 			if(is.null(names(colors))) {
76
-				stop("either provide `levels` or provide named `colors`.\n")
76
+				stop_wrap("either provide `levels` or provide named `colors`.\n")
77 77
 			}
78 78
 			levels = names(colors)
79 79
 		}
80 80
 		if(length(colors) != length(levels)) {
81
-			stop("length of colors and length of levels should be the same.\n")
81
+			stop_wrap("length of colors and length of levels should be the same.\n")
82 82
 		}
83 83
 		colors = t(col2rgb(colors, alpha = TRUE))
84 84
 		colors = rgb(colors[, 1:3, drop = FALSE], alpha = colors[, 4], maxColorValue = 255)
... ...
@@ -95,7 +95,7 @@ ColorMapping = function(name, colors = NULL, levels = NULL,
95 95
 		if(is.null(breaks)) {
96 96
 			breaks = attr(col_fun, "breaks")
97 97
 			if(is.null(breaks)) {
98
-				stop("You should provide breaks.\n")
98
+				stop_wrap("You should provide breaks.\n")
99 99
 			}
100 100
 		
101 101
 
... ...
@@ -115,7 +115,7 @@ ColorMapping = function(name, colors = NULL, levels = NULL,
115 115
 		.Object@col_fun = col_fun
116 116
 		.Object@type = "continuous"
117 117
 	} else {
118
-		stop("initialization failed. Either specify `colors` + `levels` or `col_fun` + `breaks`\n")
118
+		stop_wrap("initialization failed. Either specify `colors` + `levels` or `col_fun` + `breaks`\n")
119 119
 	}
120 120
 
121 121
 	.Object@name = name
... ...
@@ -204,7 +204,7 @@ setMethod(f = "map_to_colors",
204 204
 		if(is.numeric(x)) x = as.character(x)
205 205
 		if(any(! x[!lna] %in% object@levels)) {
206 206
 			msg = paste0(object@name, ": cannot map colors to some of the levels:\n", paste(setdiff(x[!lna], object@levels), sep = ", ", collapse = ", "))
207
-			stop(msg)
207
+			stop_wrap(msg)
208 208
 		}
209 209
 
210 210
 		x2[lna] = object@na_col
... ...
@@ -293,12 +293,12 @@ setMethod(f = "color_mapping_legend",
293 293
 	labels_gp = check_gp(labels_gp)
294 294
 
295 295
 	if(object@type == "discrete" && color_bar == "continuous") {
296
-		stop("'color_bar' can only be set to 'discrete' only if the color mapping is discrete")
296
+		stop_wrap("'color_bar' can only be set to 'discrete' only if the color mapping is discrete")
297 297
 	}
298 298
 
299 299
 	# get labels
300 300
 	if(length(at) != length(labels)) {
301
-		stop("Length of 'at' should be same as length of 'labels'.")
301
+		stop_wrap("Length of 'at' should be same as length of 'labels'.")
302 302
 	}
303 303
 	# if it is character color mapping, remove items in `at` which are not in the available optinos
304 304
 	if(color_bar == "discrete" && is.character(at)) {
... ...
@@ -426,7 +426,7 @@ Heatmap = function(matrix, col, name,
426 426
             } else {
427 427
                 if(!is.data.frame(column_split)) column_split = data.frame(column_split)
428 428
                 if(nrow(column_split) != ncol(matrix)) {
429
-                    stop("Length or ncol of `column_split` should be same as ncol of `matrix`.")
429
+                    stop_wrap("Length or ncol of `column_split` should be same as ncol of `matrix`.")
430 430
                 }
431 431
             }
432 432
         }
... ...
@@ -868,6 +868,8 @@ make_cluster = function(object, which = c("row", "column")) {
868 868
 
869 869
     names_param = slot(object, paste0(which, "_names_param"))
870 870
 
871
+    dend_param$split_by_cutree = FALSE
872
+
871 873
     if(cluster) {
872 874
 
873 875
         if(is.numeric(split) && length(split) == 1) {
... ...
@@ -900,8 +902,9 @@ make_cluster = function(object, which = c("row", "column")) {
900 902
                     stop_wrap(qq("Since you specified a clustering object, you can only split @{which}s by providing a number (number of @{which} slices)."))
901 903
                 }
902 904
                 if(split < 2) {
903
-                    stop_wrap("Here `split` should be equal or larger than 2.")
905
+                    stop_wrap(qq("`@{which}_split` should be >= 2."))
904 906
                 }
907
+                dend_param$split_by_cutree = TRUE
905 908
                 
906 909
                 ct = cut_dendrogram(dend_param$obj, split)
907 910
                 dend_list = ct$lower
... ...
@@ -67,16 +67,16 @@ setMethod(f = "draw_heatmap_body",
67 67
             CairoTIFF = c("Cairo", "tiff", "readTIFF")
68 68
         )
69 69
         if(!requireNamespace(device_info[1])) {
70
-            stop(paste0("Need ", device_info[1], " package to write image."))
70
+            stop_wrap(paste0("Need ", device_info[1], " package to write image."))
71 71
         }
72 72
         if(!requireNamespace(device_info[2])) {
73
-            stop(paste0("Need ", device_info[2], " package to read image."))
73
+            stop_wrap(paste0("Need ", device_info[2], " package to read image."))
74 74
         }
75 75
         # can we get the size of the heatmap body?
76 76
         heatmap_width = convertWidth(unit(1, "npc"), "bigpts", valueOnly = TRUE)
77 77
         heatmap_height = convertHeight(unit(1, "npc"), "bigpts", valueOnly = TRUE)
78 78
         if(heatmap_width <= 0 || heatmap_height <= 0) {
79
-            stop("The width or height of the raster image is zero, maybe you forget to turn off the previous graphic device or it was corrupted. Run `dev.off()` to close it.")
79
+            stop_wrap("The width or height of the raster image is zero, maybe you forget to turn off the previous graphic device or it was corrupted. Run `dev.off()` to close it.")
80 80
         }
81 81
         
82 82
         temp_dir = tempdir()
... ...
@@ -163,7 +163,11 @@ setMethod(f = "make_layout",
163 163
             object@layout$layout_size$row_dend_right_width = row_dend_width
164 164
             object@layout$layout_index = rbind(object@layout$layout_index, row_dend_right = heatmap_layout_index("row_dend_right"))
165 165
         }
166
-        row_dend_max_height = dend_heights(row_dend_slice) + max(dend_heights(object@row_dend_list))
166
+        if(object@row_dend_param$split_by_cutree) {
167
+            row_dend_max_height = dend_heights(row_dend_slice)
168
+        } else {
169
+            row_dend_max_height = dend_heights(row_dend_slice) + max(dend_heights(object@row_dend_list))
170
+        }
167 171
         object@layout$graphic_fun_list = c(object@layout$graphic_fun_list, function(object) {
168 172
             
169 173
             if(row_dend_side == "left") {
... ...
@@ -192,9 +196,27 @@ setMethod(f = "make_layout",
192 196
                 for(i in seq_len(nr_slice)) {
193 197
                     slice_leaf_pos[i] = slice_leaf_pos[i] - slice_height[i]*p[i]
194 198
                 }
195
-                row_dend_slice = merge_dendrogram(row_dend_slice, object@row_dend_list, only_parent = TRUE)
199
+                if(!object@row_dend_param$split_by_cutree) {
200
+                    row_dend_slice = merge_dendrogram(row_dend_slice, object@row_dend_list, only_parent = TRUE)
201
+                }
196 202
                 row_dend_slice = adjust_dend_by_x(row_dend_slice, slice_leaf_pos)
197
-                grid.dendrogram(row_dend_slice, facing = ifelse(row_dend_side == "left", "right", "left"))
203
+                grid.dendrogram(row_dend_slice, facing = ifelse(row_dend_side == "left", "right", "left"), gp = object@row_dend_param$gp)
204
+                if(!object@row_dend_param$split_by_cutree) {
205
+                    dh = dend_heights(object@row_dend_list)
206
+                    if(row_dend_side == "left") {
207
+                        grid.segments(unit(row_dend_max_height - max(dh), "native") - unit(0.5, "mm"), 
208
+                            slice_leaf_pos[1] + unit(5, "mm"), 
209
+                            unit(row_dend_max_height - max(dh), "native") - unit(0.5, "mm"), 
210
+                            slice_leaf_pos[length(slice_leaf_pos)] - unit(5, "mm"),
211
+                            gp = gpar(lty = 3, col = "#666666"))
212
+                    } else {
213
+                        grid.segments(unit(max(dh), "native") + unit(0.5, "mm"), 
214
+                            slice_leaf_pos[1] + unit(5, "mm"), 
215
+                            unit(max(dh), "native") + unit(0.5, "mm"), 
216
+                            slice_leaf_pos[length(slice_leaf_pos)] - unit(5, "mm"),
217
+                            gp = gpar(lty = 3, col = "#666666"))
218
+                    }
219
+                }
198 220
                 popViewport()
199 221
             }
200 222
             upViewport()
... ...
@@ -215,7 +237,11 @@ setMethod(f = "make_layout",
215 237
             object@layout$layout_size$column_dend_bottom_height = column_dend_height
216 238
             object@layout$layout_index = rbind(object@layout$layout_index, column_dend_bottom = heatmap_layout_index("column_dend_bottom"))
217 239
         }
218
-        column_dend_max_height = dend_heights(column_dend_slice) + max(dend_heights(object@column_dend_list))
240
+        if(object@column_dend_param$split_by_cutree) {
241
+            column_dend_max_height = dend_heights(column_dend_slice)
242
+        } else {
243
+            column_dend_max_height = dend_heights(column_dend_slice) + max(dend_heights(object@column_dend_list))
244
+        }
219 245
         object@layout$graphic_fun_list = c(object@layout$graphic_fun_list, function(object) {
220 246
             if(column_dend_side == "top") {
221 247
                 pushViewport(viewport(y = ht_opt$DENDROGRAM_PADDING, height = unit(1, "npc") - ht_opt$DENDROGRAM_PADDING, just = "bottom"))
... ...
@@ -243,9 +269,27 @@ setMethod(f = "make_layout",
243 269
                 for(i in seq_len(nc_slice)) {
244 270
                     slice_leaf_pos[i] = slice_leaf_pos[i] + slice_width[i]*p[i]
245 271
                 }
246
-                column_dend_slice = merge_dendrogram(column_dend_slice, object@column_dend_list, only_parent = TRUE)
272
+                if(!object@column_dend_param$split_by_cutree) {
273
+                    column_dend_slice = merge_dendrogram(column_dend_slice, object@column_dend_list, only_parent = TRUE)
274
+                }
247 275
                 column_dend_slice = adjust_dend_by_x(column_dend_slice, slice_leaf_pos)
248
-                grid.dendrogram(column_dend_slice, facing = ifelse(column_dend_side == "top", "bottom", "top"))
276
+                grid.dendrogram(column_dend_slice, facing = ifelse(column_dend_side == "top", "bottom", "top"), gp = object@column_dend_param$gp)
277
+                if(!object@column_dend_param$split_by_cutree) {
278
+                    dh = dend_heights(object@column_dend_list)
279
+                    if(row_dend_side == "bottom") {
280
+                        grid.segments(slice_leaf_pos[1] - unit(5, "mm"), 
281
+                            unit(column_dend_max_height - max(dh), "native") - unit(0.5, "mm"), 
282
+                            slice_leaf_pos[length(slice_leaf_pos)] + unit(5, "mm"),
283
+                            unit(column_dend_max_height - max(dh), "native") - unit(0.5, "mm"), 
284
+                            gp = gpar(lty = 3, col = "#666666"))
285
+                    } else {
286
+                        grid.segments(slice_leaf_pos[1] - unit(5, "mm"), 
287
+                            unit(max(dh), "native") + unit(0.5, "mm"), 
288
+                            slice_leaf_pos[length(slice_leaf_pos)] + unit(5, "mm"),
289
+                            unit(max(dh), "native") + unit(0.5, "mm"), 
290
+                            gp = gpar(lty = 3, col = "#666666"))
291
+                    }
292
+                }
249 293
                 popViewport()
250 294
             }
251 295
             upViewport()
... ...
@@ -38,7 +38,7 @@
38 38
 subset_heatmap_by_row = function(ht, ind) {
39 39
     ht@row_order = order(intersect(ht@row_order, ind))
40 40
     if(!is.null(ht@row_dend_param$obj)) {
41
-        stop("row dend is specified as a clustering object, cannot do subsetting.")
41
+        stop_wrap("row dend is specified as a clustering object, cannot do subsetting.")
42 42
     }
43 43
     ht@matrix = ht@matrix[ind, , drop = FALSE]
44 44
     if(!is.null(ht@row_names_param$labels)) {
... ...
@@ -58,7 +58,7 @@ subset_heatmap_by_row = function(ht, ind) {
58 58
 subset_heatmap_by_column = function(ht, ind) {
59 59
     ht@column_order = order(intersect(ht@column_order, ind))
60 60
     if(!is.null(ht@column_dend_param$obj)) {
61
-        stop("column dend is specified as a clustering object, cannot do subsetting.")
61
+        stop_wrap("column dend is specified as a clustering object, cannot do subsetting.")
62 62
     }
63 63
     ht@matrix = ht@matrix[, ind, drop = FALSE]
64 64
     if(!is.null(ht@column_names_param$labels)) {
... ...
@@ -159,7 +159,7 @@ HeatmapAnnotation = function(...,
159 159
 
160 160
     called_args = names(arg_list)
161 161
     anno_args = setdiff(called_args, fun_args)
162
-    if(any(anno_args == "")) stop("annotations should have names.")
162
+    if(any(anno_args == "")) stop_wrap("annotations should have names.")
163 163
     if(is.null(called_args)) {
164 164
     	stop_wrap("It seems you are putting only one argument to the function. If it is a simple vector annotation or a function annotation (e.g. anno_*()), specify it as HeatmapAnnotation(name = value). If it is a data frame annotation, specify it as HeatmapAnnotation(df = value)")
165 165
     }
... ...
@@ -368,7 +368,9 @@ HeatmapAnnotation = function(...,
368 368
     global_width = NULL
369 369
     if(which == "column") {
370 370
 		anno_size = do.call("unit.c", lapply(anno_list, height))
371
-		height = sum(anno_size) + sum(gap) - gap[n_total_anno]
371
+		if(is.null(height)) {
372
+			height = sum(anno_size) + sum(gap) - gap[n_total_anno]
373
+    	}
372 374
     	
373 375
     	# for width, only look at `width`
374 376
     	if(is.null(width)) {
... ...
@@ -587,7 +589,7 @@ setMethod(f = "draw",
587 589
 			index = seq_len(len[1])
588 590
 		} 
589 591
 		if(!length(index)) {
590
-			stop("Cannot infer the number of observations of the annotation.")
592
+			stop_wrap("Cannot infer the number of observations of the annotation.")
591 593
 		}
592 594
     }
593 595
 
... ...
@@ -803,7 +805,7 @@ c.HeatmapAnnotation = function(..., gap = unit(0, "mm")) {
803 805
 	anno_list = list(...)
804 806
 	n = length(anno_list)
805 807
 	if(length(unique(sapply(anno_list, function(x) x@which))) != 1) {
806
-		stop("All annotations should be all row annotation or all column annotation.")
808
+		stop_wrap("All annotations should be all row annotation or all column annotation.")
807 809
 	}
808 810
 	if(length(gap) == 1) gap = rep(gap, n)
809 811
 	if(length(gap) == n - 1) gap = unit.c(gap, unit(0, "mm"))
... ...
@@ -830,7 +832,7 @@ c.HeatmapAnnotation = function(..., gap = unit(0, "mm")) {
830 832
 	ld = duplicated(nm)
831 833
 	if(any(ld)) {
832 834
 		dup = unique(nm[ld])
833
-		warning(paste0("Following annotation names are duplicated:\n  ", paste(dup, collapse = ", ")))
835
+		warning_wrap(paste0("Following annotation names are duplicated:\n  ", paste(dup, collapse = ", ")))
834 836
 		nm2 = nm
835 837
 		nm2[unlist(split(seq_along(nm), nm))] = unlist(lapply(split(nm, nm), seq_along))
836 838
 		l = nm %in% dup
... ...
@@ -875,10 +877,10 @@ names.HeatmapAnnotation = function(x) {
875 877
 # names(ha)
876 878
 "names<-.HeatmapAnnotation" = function(x, value) {
877 879
 	if(length(value) != length(x@anno_list)) {
878
-		stop("Length of `value` should be same as number of annotations.")
880
+		stop_wrap("Length of `value` should be same as number of annotations.")
879 881
 	}
880 882
 	if(any(duplicated(value))) {
881
-		stop("Annotation names should be unique.")
883
+		stop_wrap("Annotation names should be unique.")
882 884
 	}
883 885
 	names(x@anno_list) = value
884 886
 	for(i in seq_along(value)) {
... ...
@@ -1011,12 +1013,12 @@ setMethod(f = "re_size",
1011 1013
 
1012 1014
 	if(object@which == "column") {
1013 1015
 		if(!missing(width) || !missing(annotation_width)) {
1014
-			stop("Please use width() directly")
1016
+			stop_wrap("Please use ComplexHeatmap:::width() directly")
1015 1017
 		}
1016 1018
 	}
1017 1019
 	if(object@which == "colrowumn") {
1018 1020
 		if(!missing(height) || !missing(annotation_height)) {
1019
-			stop("Please use height() directly")
1021
+			stop_wrap("Please use ComplexHeatmap:::height() directly")
1020 1022
 		}
1021 1023
 	}
1022 1024
 
... ...
@@ -1032,10 +1034,10 @@ setMethod(f = "re_size",
1032 1034
 			is_size_set = FALSE
1033 1035
 		} else {
1034 1036
 			if(!inherits(height, "unit")) {
1035
-				stop("`height` should be a `unit` object")
1037
+				stop_wrap("`height` should be a `unit` object")
1036 1038
 			}
1037 1039
 			if(!is_abs_unit(height)) {
1038
-				stop("`height` should be an absolute unit.")
1040
+				stop_wrap("`height` should be an absolute unit.")
1039 1041
 			}
1040 1042
 			is_size_set = TRUE
1041 1043
 		}
... ...
@@ -1052,10 +1054,10 @@ setMethod(f = "re_size",
1052 1054
 			is_size_set = FALSE
1053 1055
 		} else {
1054 1056
 			if(!inherits(width, "unit")) {
1055
-				stop("`width` should be a `unit` object")
1057
+				stop_wrap("`width` should be a `unit` object")
1056 1058
 			}
1057 1059
 			if(!is_abs_unit(width)) {
1058
-				stop("`width` should be an absolute unit.")
1060
+				stop_wrap("`width` should be an absolute unit.")
1059 1061
 			}
1060 1062
 			is_size_set = TRUE
1061 1063
 		}
... ...
@@ -1096,7 +1098,7 @@ setMethod(f = "re_size",
1096 1098
 			annotation_size_adjusted = rep(1, n)
1097 1099
 		}
1098 1100
 		if(length(annotation_size_adjusted) != n) {
1099
-			stop(paste0("Length of annotation_", size_name, " should be same as number of annotations.", sep = ""))
1101
+			stop_wrap(paste0("Length of annotation_", size_name, " should be same as number of annotations.", sep = ""))
1100 1102
 		}
1101 1103
 
1102 1104
 		if(!inherits(annotation_size_adjusted, "unit")) {
... ...
@@ -1111,10 +1113,10 @@ setMethod(f = "re_size",
1111 1113
 					rel_num = sapply(which(l_rel_unit), function(i) {
1112 1114
 						if(identical(class(annotation_size_adjusted[i]), "unit")) {
1113 1115
 							if(attr(annotation_size_adjusted[i], "unit") != "null") {
1114
-								stop("relative unit should be defined as `unit(..., 'null')")
1116
+								stop_wrap("relative unit should be defined as `unit(..., 'null')")
1115 1117
 							}
1116 1118
 						} else {
1117
-							stop("relative unit should be defined as `unit(..., 'null')")
1119
+							stop_wrap("relative unit should be defined as `unit(..., 'null')")
1118 1120
 						}
1119 1121
 						annotation_size_adjusted[i][[1]]
1120 1122
 					})
... ...
@@ -1125,17 +1127,17 @@ setMethod(f = "re_size",
1125 1127
 						ts = size_adjusted - sum(gap)
1126 1128
 					}
1127 1129
 					if(convertUnitFun(ts, "mm", valueOnly = TRUE) <= 0) {
1128
-						stop(paste0(size_name, "is too small."))
1130
+						stop_wrap(paste0(size_name, "is too small."))
1129 1131
 					}
1130 1132
 					ind = which(l_rel_unit)
1131 1133
 					for(i in seq_along(ind)) {
1132 1134
 						annotation_size_adjusted[ ind[i] ] = ts*rel_num[i]
1133 1135
 					}
1134 1136
 				} else {
1135
-					stop(paste0("Since annotation_", size_name, " contains relative units, ", size_name, " must be set as an absolute unit."))
1137
+					stop_wrap(paste0("Since annotation_", size_name, " contains relative units, ", size_name, " must be set as an absolute unit."))
1136 1138
 				}
1137 1139
 			} else {
1138
-				stop(paste0("Since annotation_", size_name, " contains relative units, ", size_name, " must be set."))
1140
+				stop_wrap(paste0("Since annotation_", size_name, " contains relative units, ", size_name, " must be set."))
1139 1141
 			}
1140 1142
 		}
1141 1143
 	}
... ...
@@ -1177,13 +1179,13 @@ setMethod(f = "re_size",
1177 1179
 				anno_simple_size = convertUnitFun(anno_simple_size, "mm", valueOnly = TRUE)
1178 1180
 			}
1179 1181
 			if(size_adjusted <= sum(gap)) {
1180
-				stop(paste0(size_name, " you set is smaller than sum of gaps."))
1182
+				stop_wrap(paste0(size_name, " you set is smaller than sum of gaps."))
1181 1183
 			}
1182 1184
 
1183 1185
 			## fix the size of simple annotation and zoom function annotations
1184 1186
 			ts = size_adjusted - sum(gap) - sum(anno_size[l_simple_anno]*anno_simple_size/5)
1185 1187
 			if(ts < 0) {
1186
-				stop(paste0(size_name, " you set is too small."))
1188
+				stop_wrap(paste0(size_name, " you set is too small."))
1187 1189
 			}
1188 1190
 			anno_size2[!l_simple_anno] = anno_size[!l_simple_anno]/sum(anno_size[!l_simple_anno]) * ts
1189 1191
 			anno_size2[l_simple_anno] = anno_size[l_simple_anno]*anno_simple_size/5
... ...
@@ -131,7 +131,7 @@ setMethod(f = "add_heatmap",
131 131
     ht_name = names(object@ht_list)
132 132
     which_duplicated = duplicated(ht_name)
133 133
     if(any(which_duplicated)) {
134
-        warning(paste0("Heatmap/annotation names are duplicated: ", paste(ht_name[which_duplicated], collapse = ", ")))
134
+        warning_wrap(paste0("Heatmap/annotation names are duplicated: ", paste(ht_name[which_duplicated], collapse = ", ")))
135 135
     }
136 136
 
137 137
     l = which(sapply(object@ht_list, inherits, "Heatmap"))
... ...
@@ -113,7 +113,7 @@ setMethod(f = "adjust_heatmap_list",
113 113
             total_fixed_width = total_fixed_width + sum(ht_gap[seq_len(n-1)])
114 114
         }
115 115
         if(!all(sapply(total_null_units_lt, is.unit))) {
116
-            warning("Since some of the heatmap_body_width is numeric, all heatmaps should explicitly specify heatmap_body_width as null units or numeric, or else the numeric width is treated as number of columns and will be normalized to other heatmaps.")
116
+            warning_wrap("Since some of the heatmap_body_width is numeric, all heatmaps should explicitly specify heatmap_body_width as null units or numeric, or else the numeric width is treated as number of columns and will be normalized to other heatmaps.")
117 117
         }
118 118
         total_null_units = sum(unlist(total_null_units_lt))
119 119
         if(total_null_units == 0) {
... ...
@@ -314,7 +314,7 @@ setMethod(f = "adjust_heatmap_list",
314 314
             total_fixed_height = total_fixed_height + sum(ht_gap[seq_len(n-1)])
315 315
         }
316 316
         if(!all(sapply(total_null_units_lt, is.unit))) {
317
-            warning("Since some of the heatmap_body_height is numeric, all heatmaps should explicitly specify heatmap_body_height as null units or numeric, or else the numeric height is treated as number of rows and will be normalized to other heatmaps.")
317
+            warning_wrap("Since some of the heatmap_body_height is numeric, all heatmaps should explicitly specify heatmap_body_height as null units or numeric, or else the numeric height is treated as number of rows and will be normalized to other heatmaps.")
318 318
         }
319 319
         total_null_units = sum(unlist(total_null_units_lt))
320 320
         if(total_null_units == 0) {
... ...
@@ -172,11 +172,11 @@ setMethod(f = "make_layout",
172 172
         } else if(length(ht_gap) == n_ht - 1) {
173 173
             ht_gap = unit.c(ht_gap, unit(0, "mm"))
174 174
         } else if(length(ht_gap) > n_ht) {
175
-            stop(paste0("length of `ht_gap` can only be 1 or ", n_ht-1, "."))
175
+            stop_wrap(paste0("length of `ht_gap` can only be 1 or ", n_ht-1, "."))
176 176
         }
177 177
     } else {
178 178
         if(!is.unit(ht_gap)) {
179
-            warning("`ht_gap` should be a unit object, reset it to unit(0, 'mm').")
179
+            warning_wrap("`ht_gap` should be a unit object, reset it to unit(0, 'mm').")
180 180
             ht_gap = unit(rep(0, n_ht), "mm")    
181 181
         }
182 182
     }
... ...
@@ -521,7 +521,7 @@ setMethod(f = "make_layout",
521 521
         } else if(length(padding) == 2) {
522 522
             padding = rep(padding, 2)
523 523
         } else if(length(padding) != 4) {
524
-            stop("`padding` can only have length of 1, 2, 4")
524
+            stop_wrap("`padding` can only have length of 1, 2, 4")
525 525
         }
526 526
     }
527 527
     object@ht_list_param$padding = padding
... ...
@@ -955,7 +955,7 @@ setMethod(f = "make_layout",
955 955
                         # if same set but different order
956 956
                         if(setequal(main_matrix_rn, matrix_rn)) {
957 957
                             if(!identical(main_matrix_rn, matrix_rn)) {
958
-                                warning("Row names of heatmap ", i, " is not consistent as the main heatmap (", i_main, ")", sep = "")
958
+                                warning_wrap("Row names of heatmap ", i, " is not consistent as the main heatmap (", i_main, ")", sep = "")
959 959
                             }
960 960
                         }
961 961
                     }
... ...
@@ -973,7 +973,7 @@ setMethod(f = "make_layout",
973 973
                         # if same set but different order
974 974
                         if(setequal(main_matrix_cn, matrix_cn)) {
975 975
                             if(!identical(main_matrix_cn, matrix_cn)) {
976
-                                warning("Column names of heatmap ", i, " is not consistent as the main heatmap (", i_main, ")", sep = "")
976
+                                warning_wrap("Column names of heatmap ", i, " is not consistent as the main heatmap (", i_main, ")", sep = "")
977 977
                             }
978 978
                         }
979 979
                     }
... ...
@@ -102,7 +102,7 @@ densityHeatmap = function(data,
102 102
 	density_param$na.rm = TRUE
103 103
 
104 104
 	if(!is.matrix(data) && !is.data.frame(data) && !is.list(data)) {
105
-		stop("only matrix and list are allowed.")
105
+		stop_wrap("only matrix and list are allowed.")
106 106
 	}
107 107
 	if(is.matrix(data)) {
108 108
 		data2 = as.list(as.data.frame(data))
... ...
@@ -214,13 +214,22 @@ densityHeatmap = function(data,
214 214
 
215 215
 		decorate_heatmap_body(paste0("density_", random_str), {
216 216
 			n = length(column_order[[n_slice]])
217
-			pushViewport(viewport(xscale = c(0.5, n + 0.5), yscale = c(min_x, max_x), clip = FALSE))
217
+			
218
+			lq = !apply(quantile_list, 1, function(x) all(x > max_x) || all(x < min_x))
219
+			lq = c(lq, !(all(mean_value > max_x) || all(mean_value < min_x)))
220
+			if(sum(lq) == 0) {
221
+				return(NULL)
222
+			}
218 223
 
219 224
 			labels = c(rownames(quantile_list), "mean")
220 225
 			y = c(quantile_list[, column_order[[n_slice]][n] ], mean_value[ column_order[[n_slice]][n] ])
226
+			labels = labels[lq]
227
+			y = y[lq]
221 228
 			od = order(y)
222 229
 			y = y[od]
223 230
 			labels = labels[od]
231
+			
232
+			pushViewport(viewport(xscale = c(0.5, n + 0.5), yscale = c(min_x, max_x), clip = FALSE))
224 233
 			text_height = convertHeight(grobHeight(textGrob(labels[1])) * (1 + 0.2), "native", valueOnly = TRUE)
225 234
 	        h1 = y - text_height*0.5
226 235
 	        h2 = y + text_height*0.5
... ...
@@ -230,10 +239,12 @@ densityHeatmap = function(data,
230 239
 	        n2 = length(labels)
231 240
 	        grid.text(labels, unit(1, "npc") + rep(link_width, n2), h, default.units = "native", just = "left", gp = quantile_gp)
232 241
 	        link_width = link_width - unit(1, "mm")
233
-	        grid.segments(unit(rep(1, n2), "npc"), y, unit(1, "npc") + rep(link_width * (1/3), n2), y, default.units = "native")
234
-	        grid.segments(unit(1, "npc") + rep(link_width * (1/3), n2), y, unit(1, "npc") + rep(link_width * (2/3), n2), h, default.units = "native")
235
-	        grid.segments(unit(1, "npc") + rep(link_width * (2/3), n2), h, unit(1, "npc") + rep(link_width, n2), h, default.units = "native")
236
-
242
+	        ly = y <= max_x & y >= min_x
243
+	        if(sum(ly)) {
244
+		        grid.segments(unit(rep(1, n2), "npc")[ly], y[ly], unit(1, "npc") + rep(link_width * (1/3), n2)[ly], y[ly], default.units = "native")
245
+		        grid.segments(unit(1, "npc") + rep(link_width * (1/3), n2)[ly], y[ly], unit(1, "npc") + rep(link_width * (2/3), n2)[ly], h[ly], default.units = "native")
246
+		        grid.segments(unit(1, "npc") + rep(link_width * (2/3), n2)[ly], h[ly], unit(1, "npc") + rep(link_width, n2)[ly], h[ly], default.units = "native")
247
+		    }
237 248
 			upViewport()
238 249
 		}, column_slice = n_slice)
239 250
 	}
... ...
@@ -133,7 +133,7 @@ Legend = function(at, labels = at, col_fun, nrow = NULL, ncol = 1, by_row = FALS
133 133
 		if(!missing(col_fun) && missing(at)) {
134 134
 			breaks = attr(col_fun, "breaks")
135 135
 			if(is.null(breaks)) {
136
-				stop("You should provide `at` for color mapping function\n")
136
+				stop_wrap("You should provide `at` for color mapping function\n")
137 137
 			}
138 138
 		
139 139
 			le1 = grid.pretty(range(breaks))
... ...
@@ -191,12 +191,12 @@ Legend = function(at, labels = at, col_fun, nrow = NULL, ncol = 1, by_row = FALS
191 191
 	if(!missing(col_fun)) {
192 192
 		if(direction == "vertical") {
193 193
 			if(title_position %in% c("leftcenter", "lefttop")) {
194
-				stop("'topleft', 'topcenter', 'leftcenter-rot' and 'lefttop-rot' are only allowd for vertical continuous legend")
194
+				stop_wrap("'topleft', 'topcenter', 'leftcenter-rot' and 'lefttop-rot' are only allowd for vertical continuous legend")
195 195
 			}
196 196
 		}
197 197
 		if(direction == "horizontal") {
198 198
 			if(title_position %in% c('leftcenter-rot', 'lefttop-rot')) {
199
-				stop("'topleft', 'topcenter', 'lefttop' and 'leftcenter' are only allowd for horizontal continuous legend")
199
+				stop_wrap("'topleft', 'topcenter', 'lefttop' and 'leftcenter' are only allowd for horizontal continuous legend")
200 200
 			}
201 201
 		}
202 202
 	}
... ...
@@ -451,7 +451,7 @@ vertical_continuous_legend_body = function(at, labels = at, col_fun,
451 451
 	min_legend_height = length(at)*(grid_height)
452 452
 	if(is.null(legend_height)) legend_height = min_legend_height
453 453
 	if(convertHeight(legend_height, "mm", valueOnly = TRUE) < convertHeight(min_legend_height, "mm", valueOnly = TRUE)) {
454
-		warning("`legend_height` you specified is too small, use the default minimal height.")
454
+		warning_wrap("`legend_height` you specified is too small, use the default minimal height.")
455 455
 		legend_height = min_legend_height
456 456
 	}
457 457
 
... ...
@@ -797,10 +797,10 @@ packLegend = function(...,gap = unit(2, "mm"), row_gap = unit(2, "mm"), column_g
797 797
 		}
798 798
 	}
799 799
 	if(length(row_gap) != 1) {
800
-		stop("Length of `row_gap` must be one.")
800
+		stop_wrap("Length of `row_gap` must be one.")
801 801
 	}
802 802
 	if(length(column_gap) != 1) {
803
-		stop("Length of `column_gap` must be one.")
803
+		stop_wrap("Length of `column_gap` must be one.")
804 804
 	}
805 805
     n_lgd = length(legend_list)
806 806
     if(direction == "vertical") {
... ...
@@ -997,13 +997,13 @@ valid_just = function(just) {
997 997
 			c("center", "center"))
998 998
 	}
999 999
 	if(length(just) != 2) {
1000
-		stop("`just` should be a single character or a vector of length 2.")
1000
+		stop_wrap("`just` should be a single character or a vector of length 2.")
1001 1001
 	}
1002 1002
 	j = c("center" = 0.5, "left" = 0, "right" = 1, "top" = 1, "bottom" = 0)
1003 1003
 	if(is.character(just)) {
1004 1004
 		just = j[just]
1005 1005
 	} else if(!is.numeric(just)) {
1006
-		stop("`just` can only be character or numeric.")
1006
+		stop_wrap("`just` can only be character or numeric.")
1007 1007
 	}
1008 1008
 	return(unname(just))
1009 1009
 }
... ...
@@ -35,7 +35,7 @@ adjust_dend_by_x = function(dend, leaf_pos = 1:nobs(dend)-0.5) {
35 35
     n = nobs(dend)
36 36
 
37 37
     if(length(leaf_pos) != n) {
38
-        stop("`leaf_pos` should be a vector with same length as `dend`.")
38
+        stop_wrap("`leaf_pos` should be a vector with same length as `dend`.")
39 39
     }
40 40
 
41 41
     dend_order = order.dendrogram(dend)
... ...
@@ -341,7 +341,7 @@ merge_dendrogram = function(x, y, only_parent = FALSE, ...) {
341 341
 
342 342
     n = nobs(parent)
343 343
     if(n != length(children)) {
344
-        stop("Number of children dendrograms should be same as leaves in parent.")
344
+        stop_wrap("Number of children dendrograms should be same as leaves in parent.")
345 345
     }
346 346
 
347 347
     # adjust height of parent dendrogram
... ...
@@ -101,7 +101,7 @@ oncoPrint = function(mat,
101 101
 		all_type = names(mat_list)
102 102
 		mat_list = lapply(mat_list, function(x) {
103 103
 				if(!is.matrix(x)) {
104
-					stop("Expect a list of matrix (not data frames).")
104
+					stop_wrap("Expect a list of matrix (not data frames).")
105 105
 				}
106 106
 				oattr = attributes(x)
107 107
 				x = as.logical(x)
... ...
@@ -110,14 +110,14 @@ oncoPrint = function(mat,
110 110
 			})
111 111
 
112 112
 		if(length(unique(sapply(mat_list, nrow))) > 1) {
113
-			stop("All matrix in 'mat_list' should have same number of rows.")
113
+			stop_wrap("All matrix in 'mat_list' should have same number of rows.")
114 114
 		}
115 115
 
116 116
 		if(length(unique(sapply(mat_list, ncol))) > 1) {
117
-			stop("All matrix in 'mat_list' should have same number of columns.")
117
+			stop_wrap("All matrix in 'mat_list' should have same number of columns.")
118 118
 		}
119 119
 	} else {
120
-		stop("Incorrect type of 'mat'")
120
+		stop_wrap("Incorrect type of 'mat'")
121 121
 	}
122 122
 
123 123
 	cat("All mutation types:", paste(all_type, collapse = ", "), "\n")
... ...
@@ -176,10 +176,10 @@ oncoPrint = function(mat,
176 176
 			names(af) = c("background", names(mat_list))
177 177
 			col = c("red", "blue")
178 178
 		} else {
179
-			stop("`alter_fun` should be specified.")
179
+			stop_wrap("`alter_fun` should be specified.")
180 180
 		}
181 181
 		names(col) = names(mat_list)
182
-		warning("Using default `alter_fun` graphics and reset `col`.")
182
+		warning_wrap("Using default `alter_fun` graphics and reset `col`.")
183 183
 	}
184 184
 
185 185
 	if(is.list(alter_fun)) {
... ...
@@ -188,7 +188,7 @@ oncoPrint = function(mat,
188 188
 		if(is.null(alter_fun$background)) alter_fun$background = function(x, y, w, h) grid.rect(x, y, w, h, gp = gpar(fill = "#CCCCCC", col = NA))
189 189
 		sdf = setdiff(all_type, names(alter_fun))
190 190
 		if(length(sdf) > 0) {
191
-			stop(paste0("You should define graphic function for: ", paste(sdf, collapse = ", ")))
191
+			stop_wrap(paste0("You should define graphic function for: ", paste(sdf, collapse = ", ")))
192 192
 		}
193 193
 
194 194
 		alter_fun = alter_fun[unique(c("background", intersect(names(alter_fun), all_type)))]
... ...
@@ -246,7 +246,7 @@ oncoPrint = function(mat,
246 246
 			}
247 247
 		}
248 248
 	} else {
249
-		stop("You need to set `alter_fun`.")
249
+		stop_wrap("You need to set `alter_fun`.")
250 250
 	}
251 251
 
252 252
 	col = col[intersect(names(col), all_type)]
... ...
@@ -281,7 +281,7 @@ oncoPrint = function(mat,
281 281
 	# validate col
282 282
 	sdf = setdiff(all_type, names(col))
283 283
 	if(length(sdf) > 0) {
284
-		stop(paste0("You should define colors for:", paste(sdf, collapse = ", ")))
284
+		stop_wrap(paste0("You should define colors for:", paste(sdf, collapse = ", ")))
285 285
 	}
286 286
 
287 287
 	# for each gene, percent of samples that have alterations
... ...
@@ -296,7 +296,7 @@ oncoPrint = function(mat,
296 296
 	right_annotation = eval(substitute(right_annotation))
297 297
 
298 298
 	if("left_annotation" %in% arg_names) {
299
-		stop("'left_annotation' are not allowed to specify, you can add...")
299
+		stop_wrap("'left_annotation' are not allowed to specify, you can add...")
300 300
 	}
301 301
 	left_annotation = NULL
302 302
 	if(show_pct) {
... ...
@@ -317,7 +317,7 @@ oncoPrint = function(mat,
317 317
 	
318 318
 	if(length(arg_list)) {
319 319
 		if(any(arg_names %in% c("rect_gp", "cluster_rows", "cluster_columns", "cell_fun"))) {
320
-			stop("'rect_gp', 'cluster_rows', 'cluster_columns', 'cell_fun' are not allowed to use in `oncoPrint()`.")
320
+			stop_wrap("'rect_gp', 'cluster_rows', 'cluster_columns', 'cell_fun' are not allowed to use in `oncoPrint()`.")
321 321
 		}
322 322
 	}
323 323
 
... ...
@@ -163,7 +163,7 @@ get_dist = function(matrix, method) {
163 163
         } else if(nargs == 3) {
164 164
             dst = dist2(matrix, method)
165 165
         } else {
166
-            stop("Since your distance method is a funciton, it can only accept one or two arguments.")
166
+            stop_wrap("Since your distance method is a funciton, it can only accept one or two arguments.")
167 167
         }
168 168
     } else if(method %in% c("euclidean", "maximum", "manhattan", "canberra", "binary", "minkowski")) {
169 169
         # if(any(is.na(matrix))) {
... ...
@@ -185,7 +185,7 @@ get_dist = function(matrix, method) {
185 185
                     y = y[!l]
186 186
                     1 - cor(x, y, method = method)
187 187
                 })
188
-            warning("NA exists in the matrix, calculating distance by removing NA values.")
188
+            warning_wrap("NA exists in the matrix, calculating distance by removing NA values.")
189 189
         } else {
190 190
             dst = switch(method,
191 191
                          pearson = as.dist(1 - cor(t(matrix), method = "pearson")),
... ...
@@ -212,7 +212,7 @@ recycle_gp = function(gp, n = 1) {
212 212
 
213 213
 check_gp = function(gp) {
214 214
     if(!inherits(gp, "gpar")) {
215
-        stop("Graphic parameters should be specified by `gpar()`.")
215
+        stop_wrap("Graphic parameters should be specified by `gpar()`.")
216 216
     }
217 217
     return(gp)
218 218
 }
... ...
@@ -244,7 +244,7 @@ subset_gp = function(gp, i) {
244 244
 get_text_just = function(rot, side) {
245 245
     rot = rot %% 360
246 246
     if(! rot %in% c(0, 90, 270)) {
247
-        stop("Only support horizontal or vertical rotations for text.\n")
247
+        stop_wrap("Only support horizontal or vertical rotations for text.\n")
248 248
     }
249 249
     if(side == "left") {
250 250
         if(rot == 0) {
... ...
@@ -416,7 +416,7 @@ message_wrap = function (...) {
416 416
 
417 417
 generate_param_list_fun = function(default) {
418 418
     if(!is.list(default)) {
419
-        stop("`default` needs to be a list.")
419
+        stop_wrap("`default` needs to be a list.")
420 420
     }
421 421
     lt = default
422 422
     function(..., list = NULL) {
... ...
@@ -475,20 +475,20 @@ unit.c = function(...) {
475 475
 
476 476
 ">.unit" = function(x, y) {
477 477
     if(!identical(attr(x, "unit"), "mm")) {
478
-        stop("x should be in mm unit")
478
+        stop_wrap("x should be in mm unit")
479 479
     }
480 480
     if(!identical(attr(y, "unit"), "mm")) {
481
-        stop("y should be in mm unit")
481
+        stop_wrap("y should be in mm unit")
482 482
     }
483 483
     x[[1]] > y[[1]]
484 484
 }
485 485
 
486 486
 "<.unit" = function(x, y) {
487 487
     if(!identical(attr(x, "unit"), "mm")) {
488
-        stop("x should be in mm unit")
488
+        stop_wrap("x should be in mm unit")
489 489
     }
490 490
     if(!identical(attr(y, "unit"), "mm")) {
491
-        stop("y should be in mm unit")
491
+        stop_wrap("y should be in mm unit")
492 492
     }
493 493
     x[[1]] < y[[1]]
494 494
 }
... ...
@@ -96,3 +96,8 @@ fun = function(index) {
96 96
 	grid.rect()
97 97
 }
98 98
 ha = HeatmapAnnotation(fun = fun, height = unit(4, "cm"))
99
+draw(ha, 1:10, test = TRUE)
100
+
101
+ha = rowAnnotation(fun = fun, width = unit(4, "cm"))
102
+draw(ha, 1:10, test = TRUE)
103
+