| 0 | 1 lo = function(rown, coln, nrow, ncol, cellheight = NA, cellwidth = NA, treeheight_col, treeheight_row, legend, annotation, annotation_colors, annotation_legend, main, fontsize, fontsize_row, fontsize_col, ...){ | 
|  | 2 	# Get height of colnames and length of rownames | 
|  | 3 	if(!is.null(coln[1])){ | 
|  | 4 		longest_coln = which.max(strwidth(coln, units = 'in')) | 
|  | 5 		gp = list(fontsize = fontsize_col, ...) | 
|  | 6 		coln_height = unit(1, "grobheight", textGrob(coln[longest_coln], rot = 90, gp = do.call(gpar, gp))) + unit(5, "bigpts") | 
|  | 7 	} | 
|  | 8 	else{ | 
|  | 9 		coln_height = unit(5, "bigpts") | 
|  | 10 	} | 
|  | 11 | 
|  | 12 	if(!is.null(rown[1])){ | 
|  | 13 		longest_rown = which.max(strwidth(rown, units = 'in')) | 
|  | 14 		gp = list(fontsize = fontsize_row, ...) | 
|  | 15 		rown_width = unit(1, "grobwidth", textGrob(rown[longest_rown], gp = do.call(gpar, gp))) + unit(10, "bigpts") | 
|  | 16 	} | 
|  | 17 	else{ | 
|  | 18 		rown_width = unit(5, "bigpts") | 
|  | 19 	} | 
|  | 20 | 
|  | 21 	gp = list(fontsize = fontsize, ...) | 
|  | 22 	# Legend position | 
|  | 23 	if(!is.na(legend[1])){ | 
|  | 24 		longest_break = which.max(nchar(names(legend))) | 
|  | 25 		longest_break = unit(1.1, "grobwidth", textGrob(as.character(names(legend))[longest_break], gp = do.call(gpar, gp))) | 
|  | 26 		title_length = unit(1.1, "grobwidth", textGrob("Scale", gp = gpar(fontface = "bold", ...))) | 
|  | 27 		legend_width = unit(12, "bigpts") + longest_break * 1.2 | 
|  | 28 		legend_width = max(title_length, legend_width) | 
|  | 29 	} | 
|  | 30 	else{ | 
|  | 31 		legend_width = unit(0, "bigpts") | 
|  | 32 	} | 
|  | 33 | 
|  | 34 	# Set main title height | 
|  | 35 	if(is.na(main)){ | 
|  | 36 		main_height = unit(0, "npc") | 
|  | 37 	} | 
|  | 38 	else{ | 
|  | 39 		main_height = unit(1.5, "grobheight", textGrob(main, gp = gpar(fontsize = 1.3 * fontsize, ...))) | 
|  | 40 	} | 
|  | 41 | 
|  | 42 	# Column annotations | 
|  | 43 	if(!is.na(annotation[[1]][1])){ | 
|  | 44 		# Column annotation height | 
|  | 45 		annot_height = unit(ncol(annotation) * (8 + 2) + 2, "bigpts") | 
|  | 46 		# Width of the correponding legend | 
|  | 47 		longest_ann = which.max(nchar(as.matrix(annotation))) | 
|  | 48 		annot_legend_width = unit(1.2, "grobwidth", textGrob(as.matrix(annotation)[longest_ann], gp = gpar(...))) + unit(12, "bigpts") | 
|  | 49 		if(!annotation_legend){ | 
|  | 50 			annot_legend_width = unit(0, "npc") | 
|  | 51 		} | 
|  | 52 	} | 
|  | 53 	else{ | 
|  | 54 		annot_height = unit(0, "bigpts") | 
|  | 55 		annot_legend_width = unit(0, "bigpts") | 
|  | 56 	} | 
|  | 57 | 
|  | 58 	# Tree height | 
|  | 59 	treeheight_col = unit(treeheight_col, "bigpts") + unit(5, "bigpts") | 
|  | 60 	treeheight_row = unit(treeheight_row, "bigpts") + unit(5, "bigpts") | 
|  | 61 | 
|  | 62 	# Set cell sizes | 
|  | 63 	if(is.na(cellwidth)){ | 
|  | 64 		matwidth = unit(1, "npc") - rown_width - legend_width - treeheight_row - annot_legend_width | 
|  | 65 	} | 
|  | 66 	else{ | 
|  | 67 		matwidth = unit(cellwidth * ncol, "bigpts") | 
|  | 68 	} | 
|  | 69 | 
|  | 70 	if(is.na(cellheight)){ | 
|  | 71 		matheight = unit(1, "npc") - main_height - coln_height - treeheight_col - annot_height | 
|  | 72 	} | 
|  | 73 	else{ | 
|  | 74 		matheight = unit(cellheight * nrow, "bigpts") | 
|  | 75 	} | 
|  | 76 | 
|  | 77 | 
|  | 78 	# Produce layout() | 
|  | 79 	pushViewport(viewport(layout = grid.layout(nrow = 5, ncol = 5, widths = unit.c(treeheight_row, matwidth, rown_width, legend_width, annot_legend_width), heights = unit.c(main_height, treeheight_col, annot_height, matheight, coln_height)), gp = do.call(gpar, gp))) | 
|  | 80 | 
|  | 81 	# Get cell dimensions | 
|  | 82 	pushViewport(vplayout(4, 2)) | 
|  | 83 	cellwidth = convertWidth(unit(0:1, "npc"), "bigpts", valueOnly = T)[2] / ncol | 
|  | 84 	cellheight = convertHeight(unit(0:1, "npc"), "bigpts", valueOnly = T)[2] / nrow | 
|  | 85 	upViewport() | 
|  | 86 | 
|  | 87 	# Return minimal cell dimension in bigpts to decide if borders are drawn | 
|  | 88 	mindim = min(cellwidth, cellheight) | 
|  | 89 	return(mindim) | 
|  | 90 } | 
|  | 91 | 
|  | 92 draw_dendrogram = function(hc, horizontal = T){ | 
|  | 93 	h = hc$height / max(hc$height) / 1.05 | 
|  | 94 	m = hc$merge | 
|  | 95 	o = hc$order | 
|  | 96 	n = length(o) | 
|  | 97 | 
|  | 98 	m[m > 0] = n + m[m > 0] | 
|  | 99 	m[m < 0] = abs(m[m < 0]) | 
|  | 100 | 
|  | 101 	dist = matrix(0, nrow = 2 * n - 1, ncol = 2, dimnames = list(NULL, c("x", "y"))) | 
|  | 102 	dist[1:n, 1] = 1 / n / 2 + (1 / n) * (match(1:n, o) - 1) | 
|  | 103 | 
|  | 104 	for(i in 1:nrow(m)){ | 
|  | 105 		dist[n + i, 1] = (dist[m[i, 1], 1] + dist[m[i, 2], 1]) / 2 | 
|  | 106 		dist[n + i, 2] = h[i] | 
|  | 107 	} | 
|  | 108 | 
|  | 109 	draw_connection = function(x1, x2, y1, y2, y){ | 
|  | 110 		grid.lines(x = c(x1, x1), y = c(y1, y)) | 
|  | 111 		grid.lines(x = c(x2, x2), y = c(y2, y)) | 
|  | 112 		grid.lines(x = c(x1, x2), y = c(y, y)) | 
|  | 113 	} | 
|  | 114 | 
|  | 115 	if(horizontal){ | 
|  | 116 		for(i in 1:nrow(m)){ | 
|  | 117 			draw_connection(dist[m[i, 1], 1], dist[m[i, 2], 1], dist[m[i, 1], 2], dist[m[i, 2], 2], h[i]) | 
|  | 118 		} | 
|  | 119 	} | 
|  | 120 | 
|  | 121 	else{ | 
|  | 122 		gr = rectGrob() | 
|  | 123 		pushViewport(viewport(height = unit(1, "grobwidth", gr), width = unit(1, "grobheight", gr), angle = 90)) | 
|  | 124 		dist[, 1] = 1 - dist[, 1] | 
|  | 125 		for(i in 1:nrow(m)){ | 
|  | 126 			draw_connection(dist[m[i, 1], 1], dist[m[i, 2], 1], dist[m[i, 1], 2], dist[m[i, 2], 2], h[i]) | 
|  | 127 		} | 
|  | 128 		upViewport() | 
|  | 129 	} | 
|  | 130 } | 
|  | 131 | 
|  | 132 draw_matrix = function(matrix, border_color, border_width, fmat, fontsize_number){ | 
|  | 133 	n = nrow(matrix) | 
|  | 134 	m = ncol(matrix) | 
|  | 135 	x = (1:m)/m - 1/2/m | 
|  | 136 	y = 1 - ((1:n)/n - 1/2/n) | 
|  | 137 	for(i in 1:m){ | 
|  | 138 		grid.rect(x = x[i], y = y[1:n], width = 1/m, height = 1/n, gp = gpar(fill = matrix[,i], col = border_color, lwd = border_width)) | 
|  | 139 		if(attr(fmat, "draw")){ | 
|  | 140 			grid.text(x = x[i], y = y[1:n], label = fmat[, i], gp = gpar(col = "grey30", fontsize = fontsize_number)) | 
|  | 141 		} | 
|  | 142 	} | 
|  | 143 } | 
|  | 144 | 
|  | 145 draw_colnames = function(coln, ...){ | 
|  | 146 	m = length(coln) | 
|  | 147 	x = (1:m)/m - 1/2/m | 
|  | 148 	grid.text(coln, x = x, y = unit(0.96, "npc"), just="right", rot = 90, gp = gpar(...)) | 
|  | 149 } | 
|  | 150 | 
|  | 151 draw_rownames = function(rown, ...){ | 
|  | 152 	n = length(rown) | 
|  | 153 	y = 1 - ((1:n)/n - 1/2/n) | 
|  | 154 	grid.text(rown, x = unit(0.04, "npc"), y = y, vjust = 0.5, hjust = 0, gp = gpar(...)) | 
|  | 155 } | 
|  | 156 | 
|  | 157 draw_legend = function(color, breaks, legend, ...){ | 
|  | 158 	height = min(unit(1, "npc"), unit(150, "bigpts")) | 
|  | 159 	pushViewport(viewport(x = 0, y = unit(1, "npc"), just = c(0, 1), height = height)) | 
|  | 160 	legend_pos = (legend - min(breaks)) / (max(breaks) - min(breaks)) | 
|  | 161 	breaks = (breaks - min(breaks)) / (max(breaks) - min(breaks)) | 
|  | 162 	h = breaks[-1] - breaks[-length(breaks)] | 
|  | 163 	grid.rect(x = 0, y = breaks[-length(breaks)], width = unit(10, "bigpts"), height = h, hjust = 0, vjust = 0, gp = gpar(fill = color, col = "#FFFFFF00")) | 
|  | 164 	grid.text(names(legend), x = unit(12, "bigpts"), y = legend_pos, hjust = 0, gp = gpar(...)) | 
|  | 165 	upViewport() | 
|  | 166 } | 
|  | 167 | 
|  | 168 convert_annotations = function(annotation, annotation_colors){ | 
|  | 169 	new = annotation | 
|  | 170 	for(i in 1:ncol(annotation)){ | 
|  | 171 		a = annotation[, i] | 
|  | 172 		b = annotation_colors[[colnames(annotation)[i]]] | 
|  | 173 		if(is.character(a) | is.factor(a)){ | 
|  | 174 			a = as.character(a) | 
|  | 175 			if(length(setdiff(a, names(b))) > 0){ | 
|  | 176 				stop(sprintf("Factor levels on variable %s do not match with annotation_colors", colnames(annotation)[i])) | 
|  | 177 			} | 
|  | 178 			new[, i] = b[a] | 
|  | 179 		} | 
|  | 180 		else{ | 
|  | 181 			a = cut(a, breaks = 100) | 
|  | 182 			new[, i] = colorRampPalette(b)(100)[a] | 
|  | 183 		} | 
|  | 184 	} | 
|  | 185 	return(as.matrix(new)) | 
|  | 186 } | 
|  | 187 | 
|  | 188 draw_annotations = function(converted_annotations, border_color, border_width){ | 
|  | 189 	n = ncol(converted_annotations) | 
|  | 190 	m = nrow(converted_annotations) | 
|  | 191 	x = (1:m)/m - 1/2/m | 
|  | 192 	y = cumsum(rep(8, n)) - 4 + cumsum(rep(2, n)) | 
|  | 193 	for(i in 1:m){ | 
|  | 194 		grid.rect(x = x[i], unit(y[1:n], "bigpts"), width = 1/m, height = unit(8, "bigpts"), gp = gpar(fill = converted_annotations[i, ], col = border_color, lwd = border_width)) | 
|  | 195 	} | 
|  | 196 } | 
|  | 197 | 
|  | 198 draw_annotation_legend = function(annotation, annotation_colors, border_color, border_width, ...){ | 
|  | 199 	y = unit(1, "npc") | 
|  | 200 	text_height = unit(1, "grobheight", textGrob("FGH", gp = gpar(...))) | 
|  | 201 	for(i in names(annotation_colors)){ | 
|  | 202 		grid.text(i, x = 0, y = y, vjust = 1, hjust = 0, gp = gpar(fontface = "bold", ...)) | 
|  | 203 		y = y - 1.5 * text_height | 
|  | 204 		if(is.character(annotation[, i]) | is.factor(annotation[, i])){ | 
|  | 205 			for(j in 1:length(annotation_colors[[i]])){ | 
|  | 206 				grid.rect(x = unit(0, "npc"), y = y, hjust = 0, vjust = 1, height = text_height, width = text_height, gp = gpar(col = border_color, lwd = border_width, fill = annotation_colors[[i]][j])) | 
|  | 207 				grid.text(names(annotation_colors[[i]])[j], x = text_height * 1.3, y = y, hjust = 0, vjust = 1, gp = gpar(...)) | 
|  | 208 				y = y - 1.5 * text_height | 
|  | 209 			} | 
|  | 210 		} | 
|  | 211 		else{ | 
|  | 212 			yy = y - 4 * text_height + seq(0, 1, 0.02) * 4 * text_height | 
|  | 213 			h = 4 * text_height * 0.02 | 
|  | 214 			grid.rect(x = unit(0, "npc"), y = yy, hjust = 0, vjust = 1, height = h, width = text_height, gp = gpar(col = "#FFFFFF00", fill = colorRampPalette(annotation_colors[[i]])(50))) | 
|  | 215 			txt = rev(range(grid.pretty(range(annotation[, i], na.rm = TRUE)))) | 
|  | 216 			yy = y - c(0, 3) * text_height | 
|  | 217 			grid.text(txt, x = text_height * 1.3, y = yy, hjust = 0, vjust = 1, gp = gpar(...)) | 
|  | 218 			y = y - 4.5 * text_height | 
|  | 219 		} | 
|  | 220 		y = y - 1.5 * text_height | 
|  | 221 	} | 
|  | 222 } | 
|  | 223 | 
|  | 224 draw_main = function(text, ...){ | 
|  | 225 	grid.text(text, gp = gpar(fontface = "bold", ...)) | 
|  | 226 } | 
|  | 227 | 
|  | 228 vplayout = function(x, y){ | 
|  | 229 	return(viewport(layout.pos.row = x, layout.pos.col = y)) | 
|  | 230 } | 
|  | 231 | 
|  | 232 heatmap_motor = function(matrix, border_color, border_width, cellwidth, cellheight, tree_col, tree_row, treeheight_col, treeheight_row, filename, width, height, breaks, color, legend, annotation, annotation_colors, annotation_legend, main, fontsize, fontsize_row, fontsize_col, fmat, fontsize_number, ...){ | 
|  | 233 	grid.newpage() | 
|  | 234 | 
|  | 235 	# Set layout | 
|  | 236 	mindim = lo(coln = colnames(matrix), rown = rownames(matrix), nrow = nrow(matrix), ncol = ncol(matrix), cellwidth = cellwidth, cellheight = cellheight, treeheight_col = treeheight_col, treeheight_row = treeheight_row, legend = legend, annotation = annotation, annotation_colors = annotation_colors, annotation_legend = annotation_legend, main = main, fontsize = fontsize, fontsize_row = fontsize_row, fontsize_col = fontsize_col,  ...) | 
|  | 237 | 
|  | 238 	if(!is.na(filename)){ | 
|  | 239 		pushViewport(vplayout(1:5, 1:5)) | 
|  | 240 | 
|  | 241 		if(is.na(height)){ | 
|  | 242 			height = convertHeight(unit(0:1, "npc"), "inches", valueOnly = T)[2] | 
|  | 243 		} | 
|  | 244 		if(is.na(width)){ | 
|  | 245 			width = convertWidth(unit(0:1, "npc"), "inches", valueOnly = T)[2] | 
|  | 246 		} | 
|  | 247 | 
|  | 248 		# Get file type | 
|  | 249 		r = regexpr("\\.[a-zA-Z]*$", filename) | 
|  | 250 		if(r == -1) stop("Improper filename") | 
|  | 251 		ending = substr(filename, r + 1, r + attr(r, "match.length")) | 
|  | 252 | 
|  | 253 		f = switch(ending, | 
|  | 254 			pdf = function(x, ...) pdf(x, ...), | 
|  | 255 			png = function(x, ...) png(x, units = "in", res = 300, ...), | 
|  | 256 			jpeg = function(x, ...) jpeg(x, units = "in", res = 300, ...), | 
|  | 257 			jpg = function(x, ...) jpeg(x, units = "in", res = 300, ...), | 
|  | 258 			tiff = function(x, ...) tiff(x, units = "in", res = 300, compression = "lzw", ...), | 
|  | 259 			bmp = function(x, ...) bmp(x, units = "in", res = 300, ...), | 
|  | 260 			stop("File type should be: pdf, png, bmp, jpg, tiff") | 
|  | 261 		) | 
|  | 262 | 
|  | 263 		# print(sprintf("height:%f width:%f", height, width)) | 
|  | 264 		f(filename, height = height, width = width) | 
|  | 265 		heatmap_motor(matrix, cellwidth = cellwidth, cellheight = cellheight, border_color = border_color, border_width = border_width, tree_col = tree_col, tree_row = tree_row, treeheight_col = treeheight_col, treeheight_row = treeheight_row, breaks = breaks, color = color, legend = legend, annotation = annotation, annotation_colors = annotation_colors, annotation_legend = annotation_legend, filename = NA, main = main, fontsize = fontsize, fontsize_row = fontsize_row, fontsize_col = fontsize_col, fmat = fmat, fontsize_number =  fontsize_number, ...) | 
|  | 266 		dev.off() | 
|  | 267 		upViewport() | 
|  | 268 		return() | 
|  | 269 	} | 
|  | 270 | 
|  | 271 	# Omit border color if cell size is too small | 
|  | 272 	if(mindim < 3) border_color = NA | 
|  | 273 | 
|  | 274 	# Draw title | 
|  | 275 	if(!is.na(main)){ | 
|  | 276 		pushViewport(vplayout(1, 2)) | 
|  | 277 		draw_main(main, fontsize = 1.3 * fontsize, ...) | 
|  | 278 		upViewport() | 
|  | 279 	} | 
|  | 280 | 
|  | 281 	# Draw tree for the columns | 
|  | 282 	if(!is.na(tree_col[[1]][1]) & treeheight_col != 0){ | 
|  | 283 		pushViewport(vplayout(2, 2)) | 
|  | 284 		draw_dendrogram(tree_col, horizontal = T) | 
|  | 285 		upViewport() | 
|  | 286 	} | 
|  | 287 | 
|  | 288 	# Draw tree for the rows | 
|  | 289 	if(!is.na(tree_row[[1]][1]) & treeheight_row != 0){ | 
|  | 290 		pushViewport(vplayout(4, 1)) | 
|  | 291 		draw_dendrogram(tree_row, horizontal = F) | 
|  | 292 		upViewport() | 
|  | 293 	} | 
|  | 294 | 
|  | 295 	# Draw matrix | 
|  | 296 	pushViewport(vplayout(4, 2)) | 
|  | 297 	draw_matrix(matrix, border_color, border_width, fmat, fontsize_number) | 
|  | 298 	upViewport() | 
|  | 299 | 
|  | 300 	# Draw colnames | 
|  | 301 	if(length(colnames(matrix)) != 0){ | 
|  | 302 		pushViewport(vplayout(5, 2)) | 
|  | 303 		pars = list(colnames(matrix), fontsize = fontsize_col, ...) | 
|  | 304 		do.call(draw_colnames, pars) | 
|  | 305 		upViewport() | 
|  | 306 	} | 
|  | 307 | 
|  | 308 	# Draw rownames | 
|  | 309 	if(length(rownames(matrix)) != 0){ | 
|  | 310 		pushViewport(vplayout(4, 3)) | 
|  | 311 		pars = list(rownames(matrix), fontsize = fontsize_row, ...) | 
|  | 312 		do.call(draw_rownames, pars) | 
|  | 313 		upViewport() | 
|  | 314 	} | 
|  | 315 | 
|  | 316 	# Draw annotation tracks | 
|  | 317 	if(!is.na(annotation[[1]][1])){ | 
|  | 318 		pushViewport(vplayout(3, 2)) | 
|  | 319 		converted_annotation = convert_annotations(annotation, annotation_colors) | 
|  | 320 		draw_annotations(converted_annotation, border_color, border_width) | 
|  | 321 		upViewport() | 
|  | 322 	} | 
|  | 323 | 
|  | 324 	# Draw annotation legend | 
|  | 325 	if(!is.na(annotation[[1]][1]) & annotation_legend){ | 
|  | 326 		if(length(rownames(matrix)) != 0){ | 
|  | 327 			pushViewport(vplayout(4:5, 5)) | 
|  | 328 		} | 
|  | 329 		else{ | 
|  | 330 			pushViewport(vplayout(3:5, 5)) | 
|  | 331 		} | 
|  | 332 		draw_annotation_legend(annotation, annotation_colors, border_color, border_width, fontsize = fontsize, ...) | 
|  | 333 		upViewport() | 
|  | 334 	} | 
|  | 335 | 
|  | 336 	# Draw legend | 
|  | 337 	if(!is.na(legend[1])){ | 
|  | 338 		length(colnames(matrix)) | 
|  | 339 		if(length(rownames(matrix)) != 0){ | 
|  | 340 			pushViewport(vplayout(4:5, 4)) | 
|  | 341 		} | 
|  | 342 		else{ | 
|  | 343 			pushViewport(vplayout(3:5, 4)) | 
|  | 344 		} | 
|  | 345 		draw_legend(color, breaks, legend, fontsize = fontsize, ...) | 
|  | 346 		upViewport() | 
|  | 347 	} | 
|  | 348 | 
|  | 349 | 
|  | 350 } | 
|  | 351 | 
|  | 352 generate_breaks = function(x, n, center = F){ | 
|  | 353 	if(center){ | 
|  | 354 		m = max(abs(c(min(x, na.rm = T), max(x, na.rm = T)))) | 
|  | 355 		res = seq(-m, m, length.out = n + 1) | 
|  | 356 	} | 
|  | 357 	else{ | 
|  | 358 		res = seq(min(x, na.rm = T), max(x, na.rm = T), length.out = n + 1) | 
|  | 359 	} | 
|  | 360 | 
|  | 361 	return(res) | 
|  | 362 } | 
|  | 363 | 
|  | 364 scale_vec_colours = function(x, col = rainbow(10), breaks = NA){ | 
|  | 365 	return(col[as.numeric(cut(x, breaks = breaks, include.lowest = T))]) | 
|  | 366 } | 
|  | 367 | 
|  | 368 scale_colours = function(mat, col = rainbow(10), breaks = NA){ | 
|  | 369 	mat = as.matrix(mat) | 
|  | 370 	return(matrix(scale_vec_colours(as.vector(mat), col = col, breaks = breaks), nrow(mat), ncol(mat), dimnames = list(rownames(mat), colnames(mat)))) | 
|  | 371 } | 
|  | 372 | 
|  | 373 cluster_mat = function(mat, distance, method){ | 
|  | 374 	if(!(method %in% c("ward", "single", "complete", "average", "mcquitty", "median", "centroid"))){ | 
|  | 375 		stop("clustering method has to one form the list: 'ward', 'single', 'complete', 'average', 'mcquitty', 'median' or 'centroid'.") | 
|  | 376 	} | 
|  | 377 	if(!(distance[1] %in% c("correlation", "euclidean", "maximum", "manhattan", "canberra", "binary", "minkowski")) & class(distance) != "dist"){ | 
|  | 378 		print(!(distance[1] %in% c("correlation", "euclidean", "maximum", "manhattan", "canberra", "binary", "minkowski")) | class(distance) != "dist") | 
|  | 379 		stop("distance has to be a dissimilarity structure as produced by dist or one measure  form the list: 'correlation', 'euclidean', 'maximum', 'manhattan', 'canberra', 'binary', 'minkowski'") | 
|  | 380 	} | 
|  | 381 	if(distance[1] == "correlation"){ | 
|  | 382 		d = as.dist(1 - cor(t(mat))) | 
|  | 383 	} | 
|  | 384 	else{ | 
|  | 385 		if(class(distance) == "dist"){ | 
|  | 386 			d = distance | 
|  | 387 		} | 
|  | 388 		else{ | 
|  | 389 			d = dist(mat, method = distance) | 
|  | 390 		} | 
|  | 391 	} | 
|  | 392 | 
|  | 393 	return(hclust(d, method = method)) | 
|  | 394 } | 
|  | 395 | 
|  | 396 scale_rows = function(x){ | 
|  | 397 	m = apply(x, 1, mean, na.rm = T) | 
|  | 398 	s = apply(x, 1, sd, na.rm = T) | 
|  | 399 	return((x - m) / s) | 
|  | 400 } | 
|  | 401 | 
|  | 402 scale_mat = function(mat, scale){ | 
|  | 403 	if(!(scale %in% c("none", "row", "column"))){ | 
|  | 404 		stop("scale argument shoud take values: 'none', 'row' or 'column'") | 
|  | 405 	} | 
|  | 406 	mat = switch(scale, none = mat, row = scale_rows(mat), column = t(scale_rows(t(mat)))) | 
|  | 407 	return(mat) | 
|  | 408 } | 
|  | 409 | 
|  | 410 generate_annotation_colours = function(annotation, annotation_colors, drop){ | 
|  | 411 	if(is.na(annotation_colors)[[1]][1]){ | 
|  | 412 		annotation_colors = list() | 
|  | 413 	} | 
|  | 414 	count = 0 | 
|  | 415 	for(i in 1:ncol(annotation)){ | 
|  | 416 		if(is.character(annotation[, i]) | is.factor(annotation[, i])){ | 
|  | 417 			if (is.factor(annotation[, i]) & !drop){ | 
|  | 418 				count = count + length(levels(annotation[, i])) | 
|  | 419 			} | 
|  | 420 			else{ | 
|  | 421 				count = count + length(unique(annotation[, i])) | 
|  | 422 			} | 
|  | 423 		} | 
|  | 424 	} | 
|  | 425 | 
|  | 426 	factor_colors = hsv((seq(0, 1, length.out = count + 1)[-1] + | 
|  | 427       0.2)%%1, 0.7, 0.95) | 
|  | 428 | 
|  | 429 	set.seed(3453) | 
|  | 430 | 
|  | 431 	for(i in 1:ncol(annotation)){ | 
|  | 432 		if(!(colnames(annotation)[i] %in% names(annotation_colors))){ | 
|  | 433 			if(is.character(annotation[, i]) | is.factor(annotation[, i])){ | 
|  | 434 				n = length(unique(annotation[, i])) | 
|  | 435 				if (is.factor(annotation[, i]) & !drop){ | 
|  | 436 					n = length(levels(annotation[, i])) | 
|  | 437 				} | 
|  | 438 				ind = sample(1:length(factor_colors), n) | 
|  | 439 				annotation_colors[[colnames(annotation)[i]]] = factor_colors[ind] | 
|  | 440 				l = levels(as.factor(annotation[, i])) | 
|  | 441 				l = l[l %in% unique(annotation[, i])] | 
|  | 442 				if (is.factor(annotation[, i]) & !drop){ | 
|  | 443 					l = levels(annotation[, i]) | 
|  | 444 				} | 
|  | 445 				names(annotation_colors[[colnames(annotation)[i]]]) = l | 
|  | 446 				factor_colors = factor_colors[-ind] | 
|  | 447 			} | 
|  | 448 			else{ | 
|  | 449 				r = runif(1) | 
|  | 450 				annotation_colors[[colnames(annotation)[i]]] = hsv(r, c(0.1, 1), 1) | 
|  | 451 			} | 
|  | 452 		} | 
|  | 453 	} | 
|  | 454 	return(annotation_colors) | 
|  | 455 } | 
|  | 456 | 
|  | 457 kmeans_pheatmap = function(mat, k = min(nrow(mat), 150), sd_limit = NA, ...){ | 
|  | 458 	# Filter data | 
|  | 459 	if(!is.na(sd_limit)){ | 
|  | 460 		s = apply(mat, 1, sd) | 
|  | 461 		mat = mat[s > sd_limit, ] | 
|  | 462 	} | 
|  | 463 | 
|  | 464 	# Cluster data | 
|  | 465 	set.seed(1245678) | 
|  | 466 	km = kmeans(mat, k, iter.max = 100) | 
|  | 467 	mat2 = km$centers | 
|  | 468 | 
|  | 469 	# Compose rownames | 
|  | 470 	t = table(km$cluster) | 
|  | 471 	rownames(mat2) = sprintf("cl%s_size_%d", names(t), t) | 
|  | 472 | 
|  | 473 	# Draw heatmap | 
|  | 474 	pheatmap(mat2, ...) | 
|  | 475 } | 
|  | 476 | 
|  | 477 #' A function to draw clustered heatmaps. | 
|  | 478 #' | 
|  | 479 #' A function to draw clustered heatmaps where one has better control over some graphical | 
|  | 480 #' parameters such as cell size, etc. | 
|  | 481 #' | 
|  | 482 #' The function also allows to aggregate the rows using kmeans clustering. This is | 
|  | 483 #' advisable if number of rows is so big that R cannot handle their hierarchical | 
|  | 484 #' clustering anymore, roughly more than 1000. Instead of showing all the rows | 
|  | 485 #' separately one can cluster the rows in advance and show only the cluster centers. | 
|  | 486 #' The number of clusters can be tuned with parameter kmeans_k. | 
|  | 487 #' | 
|  | 488 #' @param mat numeric matrix of the values to be plotted. | 
|  | 489 #' @param color vector of colors used in heatmap. | 
|  | 490 #' @param kmeans_k the number of kmeans clusters to make, if we want to agggregate the | 
|  | 491 #' rows before drawing heatmap. If NA then the rows are not aggregated. | 
|  | 492 #' @param breaks a sequence of numbers that covers the range of values in mat and is one | 
|  | 493 #' element longer than color vector. Used for mapping values to colors. Useful, if needed | 
|  | 494 #' to map certain values to certain colors, to certain values. If value is NA then the | 
|  | 495 #' breaks are calculated automatically. | 
|  | 496 #' @param border_color color of cell borders on heatmap, use NA if no border should be | 
|  | 497 #' drawn. | 
|  | 498 #' @param cellwidth individual cell width in points. If left as NA, then the values | 
|  | 499 #' depend on the size of plotting window. | 
|  | 500 #' @param cellheight individual cell height in points. If left as NA, | 
|  | 501 #' then the values depend on the size of plotting window. | 
|  | 502 #' @param scale character indicating if the values should be centered and scaled in | 
|  | 503 #' either the row direction or the column direction, or none. Corresponding values are | 
|  | 504 #' \code{"row"}, \code{"column"} and \code{"none"} | 
|  | 505 #' @param cluster_rows boolean values determining if rows should be clustered, | 
|  | 506 #' @param cluster_cols boolean values determining if columns should be clustered. | 
|  | 507 #' @param clustering_distance_rows distance measure used in clustering rows. Possible | 
|  | 508 #' values are \code{"correlation"} for Pearson correlation and all the distances | 
|  | 509 #' supported by \code{\link{dist}}, such as \code{"euclidean"}, etc. If the value is none | 
|  | 510 #' of the above it is assumed that a distance matrix is provided. | 
|  | 511 #' @param clustering_distance_cols distance measure used in clustering columns. Possible | 
|  | 512 #' values the same as for clustering_distance_rows. | 
|  | 513 #' @param clustering_method clustering method used. Accepts the same values as | 
|  | 514 #' \code{\link{hclust}}. | 
|  | 515 #' @param treeheight_row the height of a tree for rows, if these are clustered. | 
|  | 516 #' Default value 50 points. | 
|  | 517 #' @param treeheight_col the height of a tree for columns, if these are clustered. | 
|  | 518 #' Default value 50 points. | 
|  | 519 #' @param legend logical to determine if legend should be drawn or not. | 
|  | 520 #' @param legend_breaks vector of breakpoints for the legend. | 
|  | 521 #' @param legend_labels vector of labels for the \code{legend_breaks}. | 
|  | 522 #' @param annotation data frame that specifies the annotations shown on top of the | 
|  | 523 #' columns. Each row defines the features for a specific column. The columns in the data | 
|  | 524 #' and rows in the annotation are matched using corresponding row and column names. Note | 
|  | 525 #' that color schemes takes into account if variable is continuous or discrete. | 
|  | 526 #' @param annotation_colors list for specifying annotation track colors manually. It is | 
|  | 527 #' possible to define the colors for only some of the features. Check examples for | 
|  | 528 #' details. | 
|  | 529 #' @param annotation_legend boolean value showing if the legend for annotation tracks | 
|  | 530 #' should be drawn. | 
|  | 531 #' @param drop_levels logical to determine if unused levels are also shown in the legend | 
|  | 532 #' @param show_rownames boolean specifying if column names are be shown. | 
|  | 533 #' @param show_colnames boolean specifying if column names are be shown. | 
|  | 534 #' @param main the title of the plot | 
|  | 535 #' @param fontsize base fontsize for the plot | 
|  | 536 #' @param fontsize_row fontsize for rownames (Default: fontsize) | 
|  | 537 #' @param fontsize_col fontsize for colnames (Default: fontsize) | 
|  | 538 #' @param display_numbers logical determining if the numeric values are also printed to | 
|  | 539 #' the cells. | 
|  | 540 #' @param number_format format strings (C printf style) of the numbers shown in cells. | 
|  | 541 #' For example "\code{\%.2f}" shows 2 decimal places and "\code{\%.1e}" shows exponential | 
|  | 542 #' notation (see more in \code{\link{sprintf}}). | 
|  | 543 #' @param fontsize_number fontsize of the numbers displayed in cells | 
|  | 544 #' @param filename file path where to save the picture. Filetype is decided by | 
|  | 545 #' the extension in the path. Currently following formats are supported: png, pdf, tiff, | 
|  | 546 #'  bmp, jpeg. Even if the plot does not fit into the plotting window, the file size is | 
|  | 547 #' calculated so that the plot would fit there, unless specified otherwise. | 
|  | 548 #' @param width manual option for determining the output file width in inches. | 
|  | 549 #' @param height manual option for determining the output file height in inches. | 
|  | 550 #' @param \dots graphical parameters for the text used in plot. Parameters passed to | 
|  | 551 #' \code{\link{grid.text}}, see \code{\link{gpar}}. | 
|  | 552 #' | 
|  | 553 #' @return | 
|  | 554 #' Invisibly a list of components | 
|  | 555 #' \itemize{ | 
|  | 556 #' 	\item \code{tree_row} the clustering of rows as \code{\link{hclust}} object | 
|  | 557 #' 	\item \code{tree_col} the clustering of columns as \code{\link{hclust}} object | 
|  | 558 #' 	\item \code{kmeans} the kmeans clustering of rows if parameter \code{kmeans_k} was | 
|  | 559 #' specified | 
|  | 560 #' } | 
|  | 561 #' | 
|  | 562 #' @author  Raivo Kolde <rkolde@@gmail.com> | 
|  | 563 #' @examples | 
|  | 564 #'  # Generate some data | 
|  | 565 #' test = matrix(rnorm(200), 20, 10) | 
|  | 566 #' test[1:10, seq(1, 10, 2)] = test[1:10, seq(1, 10, 2)] + 3 | 
|  | 567 #' test[11:20, seq(2, 10, 2)] = test[11:20, seq(2, 10, 2)] + 2 | 
|  | 568 #' test[15:20, seq(2, 10, 2)] = test[15:20, seq(2, 10, 2)] + 4 | 
|  | 569 #' colnames(test) = paste("Test", 1:10, sep = "") | 
|  | 570 #' rownames(test) = paste("Gene", 1:20, sep = "") | 
|  | 571 #' | 
|  | 572 #' # Draw heatmaps | 
|  | 573 #' pheatmap(test) | 
|  | 574 #' pheatmap(test, kmeans_k = 2) | 
|  | 575 #' pheatmap(test, scale = "row", clustering_distance_rows = "correlation") | 
|  | 576 #' pheatmap(test, color = colorRampPalette(c("navy", "white", "firebrick3"))(50)) | 
|  | 577 #' pheatmap(test, cluster_row = FALSE) | 
|  | 578 #' pheatmap(test, legend = FALSE) | 
|  | 579 #' pheatmap(test, display_numbers = TRUE) | 
|  | 580 #' pheatmap(test, display_numbers = TRUE, number_format = "%.1e") | 
|  | 581 #' pheatmap(test, cluster_row = FALSE, legend_breaks = -1:4, legend_labels = c("0", | 
|  | 582 #' "1e-4", "1e-3", "1e-2", "1e-1", "1")) | 
|  | 583 #' pheatmap(test, cellwidth = 15, cellheight = 12, main = "Example heatmap") | 
|  | 584 #' pheatmap(test, cellwidth = 15, cellheight = 12, fontsize = 8, filename = "test.pdf") | 
|  | 585 #' | 
|  | 586 #' | 
|  | 587 #' # Generate column annotations | 
|  | 588 #' annotation = data.frame(Var1 = factor(1:10 %% 2 == 0, | 
|  | 589 #' 				labels = c("Class1", "Class2")), Var2 = 1:10) | 
|  | 590 #' annotation$Var1 = factor(annotation$Var1, levels = c("Class1", "Class2", "Class3")) | 
|  | 591 #' rownames(annotation) = paste("Test", 1:10, sep = "") | 
|  | 592 #' | 
|  | 593 #' pheatmap(test, annotation = annotation) | 
|  | 594 #' pheatmap(test, annotation = annotation, annotation_legend = FALSE) | 
|  | 595 #' pheatmap(test, annotation = annotation, annotation_legend = FALSE, drop_levels = FALSE) | 
|  | 596 #' | 
|  | 597 #' # Specify colors | 
|  | 598 #' Var1 = c("navy", "darkgreen") | 
|  | 599 #' names(Var1) = c("Class1", "Class2") | 
|  | 600 #' Var2 = c("lightgreen", "navy") | 
|  | 601 #' | 
|  | 602 #' ann_colors = list(Var1 = Var1, Var2 = Var2) | 
|  | 603 #' | 
|  | 604 #' pheatmap(test, annotation = annotation, annotation_colors = ann_colors, main = "Example") | 
|  | 605 #' | 
|  | 606 #' # Specifying clustering from distance matrix | 
|  | 607 #' drows = dist(test, method = "minkowski") | 
|  | 608 #' dcols = dist(t(test), method = "minkowski") | 
|  | 609 #' pheatmap(test, clustering_distance_rows = drows, clustering_distance_cols = dcols) | 
|  | 610 #' | 
|  | 611 #' @export | 
|  | 612 pheatmap_j = function(mat, color = colorRampPalette(rev(brewer.pal(n = 7, name = "RdYlBu")))(100), kmeans_k = NA, breaks = NA, border_color = "grey60", border_width = 1, cellwidth = NA, cellheight = NA, scale = "none", cluster_rows = TRUE, cluster_cols = TRUE, clustering_distance_rows = "euclidean", clustering_distance_cols = "euclidean", clustering_method = "complete",  treeheight_row = ifelse(cluster_rows, 50, 0), treeheight_col = ifelse(cluster_cols, 50, 0), legend = TRUE, legend_breaks = NA, legend_labels = NA, annotation = NA, annotation_colors = NA, annotation_legend = TRUE, drop_levels = TRUE, show_rownames = T, show_colnames = T, main = NA, fontsize = 10, fontsize_row = fontsize, fontsize_col = fontsize, display_numbers = F, number_format = "%.2f", fontsize_number = 0.8 * fontsize, filename = NA, width = NA, height = NA, ...){ | 
|  | 613 | 
|  | 614 	# Preprocess matrix | 
|  | 615 	mat = as.matrix(mat) | 
|  | 616 	if(scale != "none"){ | 
|  | 617 		mat = scale_mat(mat, scale) | 
|  | 618 		if(is.na(breaks)){ | 
|  | 619 			breaks = generate_breaks(mat, length(color), center = T) | 
|  | 620 		} | 
|  | 621 	} | 
|  | 622 | 
|  | 623 | 
|  | 624 	# Kmeans | 
|  | 625 	if(!is.na(kmeans_k)){ | 
|  | 626 		# Cluster data | 
|  | 627 		km = kmeans(mat, kmeans_k, iter.max = 100) | 
|  | 628 		mat = km$centers | 
|  | 629 | 
|  | 630 		# Compose rownames | 
|  | 631 		t = table(km$cluster) | 
|  | 632 		rownames(mat) = sprintf("cl%s_size_%d", names(t), t) | 
|  | 633 	} | 
|  | 634 	else{ | 
|  | 635 		km = NA | 
|  | 636 	} | 
|  | 637 | 
|  | 638 	# Do clustering | 
|  | 639 	if(cluster_rows){ | 
|  | 640 		tree_row = cluster_mat(mat, distance = clustering_distance_rows, method = clustering_method) | 
|  | 641 		mat = mat[tree_row$order, , drop = FALSE] | 
|  | 642 	} | 
|  | 643 	else{ | 
|  | 644 		tree_row = NA | 
|  | 645 		treeheight_row = 0 | 
|  | 646 	} | 
|  | 647 | 
|  | 648 	if(cluster_cols){ | 
|  | 649 		tree_col = cluster_mat(t(mat), distance = clustering_distance_cols, method = clustering_method) | 
|  | 650 		mat = mat[, tree_col$order, drop = FALSE] | 
|  | 651 	} | 
|  | 652 	else{ | 
|  | 653 		tree_col = NA | 
|  | 654 		treeheight_col = 0 | 
|  | 655 	} | 
|  | 656 | 
|  | 657 	# Format numbers to be displayed in cells | 
|  | 658 	if(display_numbers){ | 
|  | 659 		fmat = matrix(sprintf(number_format, mat), nrow = nrow(mat), ncol = ncol(mat)) | 
|  | 660 		attr(fmat, "draw") = TRUE | 
|  | 661 	} | 
|  | 662 	else{ | 
|  | 663 		fmat = matrix(NA, nrow = nrow(mat), ncol = ncol(mat)) | 
|  | 664 		attr(fmat, "draw") = FALSE | 
|  | 665 	} | 
|  | 666 | 
|  | 667 | 
|  | 668 	# Colors and scales | 
|  | 669 	if(!is.na(legend_breaks[1]) & !is.na(legend_labels[1])){ | 
|  | 670 		if(length(legend_breaks) != length(legend_labels)){ | 
|  | 671 			stop("Lengths of legend_breaks and legend_labels must be the same") | 
|  | 672 		} | 
|  | 673 	} | 
|  | 674 | 
|  | 675 | 
|  | 676 	if(is.na(breaks[1])){ | 
|  | 677       breaks = generate_breaks(as.vector(mat), length(color)) | 
|  | 678   } | 
|  | 679   if (legend & is.na(legend_breaks[1])) { | 
|  | 680       legend = grid.pretty(range(as.vector(breaks))) | 
|  | 681 			names(legend) = legend | 
|  | 682   } | 
|  | 683 	else if(legend & !is.na(legend_breaks[1])){ | 
|  | 684 		legend = legend_breaks[legend_breaks >= min(breaks) & legend_breaks <= max(breaks)] | 
|  | 685 | 
|  | 686 		if(!is.na(legend_labels[1])){ | 
|  | 687 			legend_labels = legend_labels[legend_breaks >= min(breaks) & legend_breaks <= max(breaks)] | 
|  | 688 			names(legend) = legend_labels | 
|  | 689 		} | 
|  | 690 		else{ | 
|  | 691 			names(legend) = legend | 
|  | 692 		} | 
|  | 693 	} | 
|  | 694   else { | 
|  | 695       legend = NA | 
|  | 696   } | 
|  | 697 	mat = scale_colours(mat, col = color, breaks = breaks) | 
|  | 698 | 
|  | 699 	# Preparing annotation colors | 
|  | 700 	if(!is.na(annotation[[1]][1])){ | 
|  | 701 		annotation = annotation[colnames(mat), , drop = F] | 
|  | 702 		annotation_colors = generate_annotation_colours(annotation, annotation_colors, drop = drop_levels) | 
|  | 703 	} | 
|  | 704 | 
|  | 705 	if(!show_rownames){ | 
|  | 706 		rownames(mat) = NULL | 
|  | 707 	} | 
|  | 708 | 
|  | 709 	if(!show_colnames){ | 
|  | 710 		colnames(mat) = NULL | 
|  | 711 	} | 
|  | 712 | 
|  | 713 	# Draw heatmap | 
|  | 714 	heatmap_motor(mat, border_color = border_color, border_width = border_width, cellwidth = cellwidth, cellheight = cellheight, treeheight_col = treeheight_col, treeheight_row = treeheight_row, tree_col = tree_col, tree_row = tree_row, filename = filename, width = width, height = height, breaks = breaks, color = color, legend = legend, annotation = annotation, annotation_colors = annotation_colors, annotation_legend = annotation_legend, main = main, fontsize = fontsize, fontsize_row = fontsize_row, fontsize_col = fontsize_col, fmat = fmat, fontsize_number = fontsize_number, ...) | 
|  | 715 | 
|  | 716 	invisible(list(tree_row = tree_row, tree_col = tree_col, kmeans = km)) | 
|  | 717 } | 
|  | 718 | 
|  | 719 |