b8dacfcc |
# -anno_simple_size size of the simple annotation.# -anno_simple_size size of the simple annotation.# -anno_simple_size size of the simple annotation.
|
402ff791 |
|
10fbf31c |
# == title
# Empty Annotation
#
# == param
# -which Whether it is a column annotation or a row annotation?
|
1a56796e |
# -border Whether draw borders of the annotation region?
# -width Width of the annotation. The value should be an absolute unit. Width is not allowed to be set for column annotation.
# -height Height of the annotation. The value should be an absolute unit. Height is not allowed to be set for row annotation.
|
10fbf31c |
#
# == details
# It creates an empty annotation and holds space, later users can add graphics
# by `decorate_annotation`. This function is useful when users have difficulty to
# implement `AnnotationFunction` object.
#
# In following example, an empty annotation is first created and later points are added:
#
# m = matrix(rnorm(100), 10)
# ht = Heatmap(m, top_annotation = HeatmapAnnotation(pt = anno_empty()))
# ht = draw(ht)
# co = column_order(ht)[[1]]
# pt_value = 1:10
# decorate_annotation("pt", {
# pushViewport(viewport(xscale = c(0.5, ncol(mat)+0.5), yscale = range(pt_value)))
# grid.points(seq_len(ncol(mat)), pt_value[co], pch = 16, default.units = "native")
# grid.yaxis()
# popViewport()
# })
#
# And it is similar as using `anno_points`:
#
# Heatmap(m, top_annotation = HeatmapAnnotation(pt = anno_points(pt_value)))
#
# == value
# An annotation function which can be used in `HeatmapAnnotation`.
#
# == examples
# anno = anno_empty()
# draw(anno, test = "anno_empty")
# anno = anno_empty(border = FALSE)
# draw(anno, test = "anno_empty without border")
|
402ff791 |
anno_empty = function(which = c("column", "row"), border = TRUE, width = NULL, height = NULL) {
if(is.null(.ENV$current_annotation_which)) {
which = match.arg(which)[1]
} else {
which = .ENV$current_annotation_which
}
anno_size = anno_width_and_height(which, width, height, unit(1, "cm"))
fun = function(index) {
if(border) grid.rect()
}
anno = AnnotationFunction(
fun = fun,
|
c4a66bf9 |
n = NA,
|
402ff791 |
fun_name = "anno_empty",
which = which,
var_import = list(border),
subset_rule = list(),
subsetable = TRUE,
height = anno_size$height,
|
933e808c |
width = anno_size$width,
show_name = FALSE
|
402ff791 |
)
return(anno)
}
|
ad35494a |
# == title
# Subset the Matrix by Rows
#
# == param
# -x A matrix
# -i The row indices.
#
|
402ff791 |
subset_matrix_by_row = function(x, i) x[i, , drop = FALSE]
|
ad35494a |
# == title
# Subset the vector
#
# == param
# -x A vector
# -i The indices
#
|
402ff791 |
subset_vector = function(x, i) x[i]
|
10fbf31c |
# == title
# Simple Annotation
#
# == param
# -x The value vector. The value can be a vector or a matrix. The length of the vector
|
1a56796e |
# or the nrow of the matrix is taken as the number of the observations of the annotation.
|
10fbf31c |
# The value can be numeric or character and NA value is allowed.
# -col Color that maps to ``x``. If ``x`` is numeric and needs a continuous mapping, ``col``
# should be a color mapping function which accepts a vector of values and returns a
# vector of colors. Normally it is generated by `circlize::colorRamp2`. If ``x`` is discrete
# (numeric or character) and needs a discrete color mapping, ``col`` should be a vector of
# colors with levels in ``x`` as vector names. If ``col`` is not specified, the color mapping
|
ad35494a |
# is randomly generated by ``ComplexHeatmap:::default_col``.
|
10fbf31c |
# -na_col Color for NA value.
# -which Whether it is a column annotation or a row annotation?
# -border Wether draw borders of the annotation region?
# -gp Graphic parameters for grid borders. The ``fill`` parameter is disabled.
# -pch Points/symbols that are added on top of the annotation grids. The value can be numeric
# or single letters. It can be a vector if ``x`` is a vector and a matrix if ``x`` is a matrix.
# No points are drawn if the corresponding values are NA.
# -pt_size Size of the points/symbols. It should be a `grid::unit` object. If ``x`` is a vector,
# the value of ``pt_size`` can be a vector, while if ``x`` is a matrix, ``pt_size`` can
# only be a single value.
# -pt_gp Graphic parameters for points/symbols. The length setting is same as ``pt_size``.
|
b8dacfcc |
# -anno_simple_size size of the simple annotation.
|
1a56796e |
# -width Width of the annotation. The value should be an absolute unit. Width is not allowed to be set for column annotation.
# -height Height of the annotation. The value should be an absolute unit. Height is not allowed to be set for row annotation.
|
10fbf31c |
#
# == details
# The "simple annotation" is the most widely used annotation type which is heatmap-like, where
# the grid colors correspond to the values. `anno_simple` also supports to add points/symbols
|
1a56796e |
# on top of the grids where the it can be normal point (when ``pch`` is set as numbers) or letters (when
# ``pch`` is set as single letters).
|
10fbf31c |
#
# == value
# An annotation function which can be used in `HeatmapAnnotation`.
#
# == example
# anno = anno_simple(1:10)
# draw(anno, test = "a numeric vector")
#
# anno = anno_simple(cbind(1:10, 10:1))
# draw(anno, test = "a matrix")
#
# anno = anno_simple(1:10, pch = c(1:4, NA, 6:8, NA, 10))
# draw(anno, test = "pch has NA values")
#
|
ad35494a |
# anno = anno_simple(1:10, pch = c(rep("A", 5), rep(NA, 5)))
|
10fbf31c |
# draw(anno, test = "pch has NA values")
#
# pch = matrix(1:20, nc = 2)
# pch[sample(length(pch), 10)] = NA
# anno = anno_simple(cbind(1:10, 10:1), pch = pch)
# draw(anno, test = "matrix, pch is a matrix with NA values")
|
402ff791 |
anno_simple = function(x, col, na_col = "grey",
which = c("column", "row"), border = FALSE, gp = gpar(col = NA),
pch = NULL, pt_size = unit(1, "snpc")*0.8, pt_gp = gpar(),
|
6320aa68 |
anno_simple_size = ht_opt$anno_simple_size,
|
402ff791 |
width = NULL, height = NULL) {
if(is.null(.ENV$current_annotation_which)) {
which = match.arg(which)[1]
} else {
which = .ENV$current_annotation_which
}
if(is.data.frame(x)) x = as.matrix(x)
if(is.matrix(x)) {
if(ncol(x) == 1) {
x = x[, 1]
}
}
input_is_matrix = is.matrix(x)
anno_size = anno_width_and_height(which, width, height,
|
6320aa68 |
anno_simple_size*ifelse(input_is_matrix, ncol(x), 1))
|
402ff791 |
if(missing(col)) {
col = default_col(x)
}
if(is.atomic(col)) {
color_mapping = ColorMapping(name = "foo", colors = col, na_col = na_col)
} else if(is.function(col)) {
color_mapping = ColorMapping(name = "foo", col_fun = col, na_col = na_col)
} else if(inherits(col, "ColorMapping")) {
color_mapping = col
} else {
stop_wrap("`col` should be a named vector/a color mapping function/a ColorMapping object.")
}
value = x
gp = subset_gp(gp, 1) # gp controls border
if(is.matrix(value)) {
n = nrow(value)
nr = n
nc = ncol(value)
} else {
n = length(value)
nr = n
nc = 1
}
if(!is.null(pch)) {
if(input_is_matrix) {
pch = normalize_graphic_param_to_mat(pch, ifelse(is.matrix(x), ncol(x), 1), n, "pch")
pt_size = pt_size[1]*(1/nc)
pt_gp = subset_gp(pt_gp, 1)
} else {
if(length(pch) == 1) pch = rep(pch, n)
if(length(pt_size) == 1) pt_size = rep(pt_size, n)
pt_gp = recycle_gp(pt_gp, n)
}
}
row_fun = function(index) {
n = length(index)
y = (n - seq_len(n) + 0.5) / n
if(is.matrix(value)) {
nc = ncol(value)
for(i in seq_len(nc)) {
fill = map_to_colors(color_mapping, value[index, i])
grid.rect(x = (i-0.5)/nc, y, height = 1/n, width = 1/nc,
gp = do.call("gpar", c(list(fill = fill), gp)))
if(!is.null(pch)) {
l = !is.na(pch[, i])
grid.points(x = rep((i-0.5)/nc, sum(l)), y = y[l], pch = pch[l, i],
size = pt_size, gp = pt_gp)
}
}
} else {
fill = map_to_colors(color_mapping, value[index])
grid.rect(x = 0.5, y, height = 1/n, width = 1, gp = do.call("gpar", c(list(fill = fill), gp)))
if(!is.null(pch)) {
l = !is.na(pch)
grid.points(x = rep(0.5, sum(l)), y = y[l], pch = pch[l], size = pt_size[l],
gp = subset_gp(pt_gp, which(l)))
}
}
if(border) grid.rect(gp = gpar(fill = "transparent"))
}
column_fun = function(index) {
n = length(index)
x = (seq_len(n) - 0.5) / n
if(is.matrix(value)) {
nc = ncol(value)
for(i in seq_len(nc)) {
fill = map_to_colors(color_mapping, value[index, i])
grid.rect(x, y = (nc-i +0.5)/nc, width = 1/n, height = 1/nc, gp = do.call("gpar", c(list(fill = fill), gp)))
if(!is.null(pch)) {
|
c4a66bf9 |
pch = pch[index, , drop = FALSE]
|
402ff791 |
l = !is.na(pch[, i])
grid.points(x[l], y = rep((nc-i +0.5)/nc, sum(l)), pch = pch[l, i], size = pt_size, gp = pt_gp)
}
}
} else {
fill = map_to_colors(color_mapping, value[index])
grid.rect(x, y = 0.5, width = 1/n, height = 1, gp = do.call("gpar", c(list(fill = fill), gp)))
if(!is.null(pch)) {
|
c4a66bf9 |
pch = pch[index]
|
402ff791 |
l = !is.na(pch)
grid.points(x[l], y = rep(0.5, sum(l)), pch = pch[l], size = pt_size[l], gp = subset_gp(pt_gp, which(l)))
}
}
if(border) grid.rect(gp = gpar(fill = "transparent"))
}
if(which == "row") {
fun = row_fun
} else if(which == "column") {
fun = column_fun
}
anno = AnnotationFunction(
fun = fun,
fun_name = "anno_simple",
which = which,
width = anno_size$width,
height = anno_size$height,
n = n,
data_scale = c(0.5, nc + 0.5),
var_import = list(value, gp, border, color_mapping, pt_gp, pt_size, pch)
)
anno@subset_rule = list()
if(input_is_matrix) {
anno@subset_rule$value = subset_matrix_by_row
if(!is.null(pch)) {
anno@subset_rule$pch = subset_matrix_by_row
}
} else {
anno@subset_rule$value = subset_vector
if(!is.null(pch)) {
anno@subset_rule$pch = subset_vector
anno@subset_rule$pt_size = subset_vector
anno@subset_rule$pt_gp = subset_gp
}
}
anno@subsetable = TRUE
return(anno)
}
|
10fbf31c |
# == title
# Image Annotation
#
# == param
# -image A vector of file paths of images. The format of the image is inferred from the suffix name of the image file.
# NA values or empty strings in the vector means no image to drawn.
# -which Whether it is a column annotation or a row annotation?
# -border Wether draw borders of the annotation region?
# -gp Graphic parameters for annotation grids. If the image has transparent background, the ``fill`` parameter
# can be used to control the background color in the annotation grids.
# -space The space around the image to the annotation grid borders. The value should be a `grid::unit` object.
|
1a56796e |
# -width Width of the annotation. The value should be an absolute unit. Width is not allowed to be set for column annotation.
# -height Height of the annotation. The value should be an absolute unit. Height is not allowed to be set for row annotation.
|
10fbf31c |
#
# == details
# This function supports image formats in ``png``, ``svg``, ``pdf``, ``eps``, ``jpeg/jpg``, ``tiff``.
# ``png``, ``jpeg/jpg`` and ``tiff`` images are imported by `png::readPNG`, `jpeg::readJPEG` and
|
ad35494a |
# `tiff::readTIFF`, and drawn by `grid::grid.raster`. ``svg`` images are firstly reformatted by `rsvg::rsvg_svg`
|
10fbf31c |
# and then imported by `grImport2::readPicture` and drawn by `grImport2::grid.picture`. ``pdf`` and ``eps``
# images are imported by `grImport::PostScriptTrace` and `grImport::readPicture`, later drawn by `grImport::grid.picture`.
#
# Different image formats can be mixed in the ``image`` vector.
#
# == value
# An annotation function which can be used in `HeatmapAnnotation`.
#
# == example
# # download the free icons from https://github.com/Keyamoon/IcoMoon-Free
# \dontrun{
# image = sample(dir("~/Downloads/IcoMoon-Free-master/PNG/64px", full.names = TRUE), 10)
# anno = anno_image(image)
# draw(anno, test = "png")
# image[1:5] = ""
# anno = anno_image(image)
# draw(anno, test = "some of png")
# }
|
402ff791 |
anno_image = function(image, which = c("column", "row"), border = TRUE,
|
10fbf31c |
gp = gpar(fill = NA, col = NA), space = unit(1, "mm"),
width = NULL, height = NULL) {
|
402ff791 |
|
10fbf31c |
image[is.na(image)] = ""
l = grepl("^\\s*$", image)
image[l] = ""
|
402ff791 |
allowed_image_type = c("png", "svg", "pdf", "eps", "jpeg", "jpg", "tiff")
if(inherits(image, "character")) { ## they are file path
image_type = tolower(gsub("^.*\\.(\\w+)$", "\\1", image))
|
10fbf31c |
if(! all(image_type[image_type != ""] %in% allowed_image_type)) {
|
c4a66bf9 |
stop_wrap("image file should be of png/svg/pdf/eps/jpeg/jpg/tiff.")
|
402ff791 |
}
} else {
|
c4a66bf9 |
stop_wrap("`image` should be a vector of path.")
|
402ff791 |
}
n_image = length(image)
image_list = vector("list", n_image)
image_class = vector("character", n_image)
for(i in seq_along(image)) {
|
10fbf31c |
if(image[i] == "") {
image_list[[i]] = NA
image_class[i] = NA
} else if(image_type[i] == "png") {
|
402ff791 |
if(!requireNamespace("png")) {
|
c4a66bf9 |
stop_wrap("Need png package to read png images.")
|
402ff791 |
}
image_list[[i]] = png::readPNG(image[i])
image_class[i] = "raster"
} else if(image_type[i] %in% c("jpeg", "jpg")) {
if(!requireNamespace("jpeg")) {
|
c4a66bf9 |
stop_wrap("Need jpeg package to read jpeg/jpg images.")
|
402ff791 |
}
image_list[[i]] = jpeg::readJPEG(image[i])
image_class[i] = "raster"
} else if(image_type[i] == "tiff") {
if(!requireNamespace("tiff")) {
|
c4a66bf9 |
stop_wrap("Need tiff package to read tiff images.")
|
402ff791 |
}
image_list[[i]] = tiff::readTIFF(image[i])
image_class[i] = "raster"
} else if(image_type[i] %in% c("pdf", "eps")) {
if(!requireNamespace("grImport")) {
|
c4a66bf9 |
stop_wrap("Need grImport package to read pdf/eps images.")
|
402ff791 |
}
temp_file = tempfile()
getFromNamespace("PostScriptTrace", ns = "grImport")(image[[i]], temp_file)
image_list[[i]] = grImport::readPicture(temp_file)
file.remove(temp_file)
image_class[i] = "grImport::Picture"
} else if(image_type[i] == "svg") {
if(!requireNamespace("grImport2")) {
|
c4a66bf9 |
stop_wrap("Need grImport2 package to read svg images.")
|
402ff791 |
}
if(!requireNamespace("rsvg")) {
|
c4a66bf9 |
stop_wrap("Need rsvg package to convert svg images.")
|
402ff791 |
}
temp_file = tempfile()
rsvg::rsvg_svg(image[i], temp_file)
image_list[[i]] = grImport2::readPicture(temp_file)
file.remove(temp_file)
image_class[i] = "grImport2::Picture"
}
}
yx_asp = sapply(image_list, function(x) {
if(inherits(x, "array")) {
nrow(x)/ncol(x)
} else if(inherits(x, "Picture")) {
max(x@summary@yscale)/max(x@summary@xscale)
|
10fbf31c |
} else {
1
|
402ff791 |
}
})
if(is.null(.ENV$current_annotation_which)) {
which = match.arg(which)[1]
} else {
which = .ENV$current_annotation_which
}
space = space[1]
anno_size = anno_width_and_height(which, width, height, unit(1, "cm"))
gp = recycle_gp(gp, n_image)
column_fun = function(index) {
n = length(index)
pushViewport(viewport())
|
ad35494a |
asp = convertHeight(unit(1, "npc") - space*2, "mm", valueOnly = TRUE)/convertWidth(unit(1/n, "npc") - space*2, "mm", valueOnly = TRUE)
|
402ff791 |
grid.rect(x = (1:n - 0.5)/n, width = 1/n, gp = subset_gp(gp, index))
for(i in seq_len(n)) {
|
10fbf31c |
if(identical(image_list[[i]], NA)) next
|
402ff791 |
if(yx_asp[ index[i] ] > asp) {
height = unit(1, "npc") - space*2
width = convertHeight(height, "mm")*yx_asp[ index[i] ]
} else {
width = unit(1/n, "npc") - space*2
height = yx_asp[ index[i] ]*convertWidth(width, "mm")
}
if(image_class[ index[i] ] == "raster") {
grid.raster(image_list[[i]], x = (i-0.5)/n, width = width, height = height)
} else if(image_class[ index[i] ] == "grImport::Picture") {
grid.picture = getFromNamespace("grid.picture", ns = "grImport")
grid.picture(image_list[[i]], x = (i-0.5)/n, width = width, height = height)
} else if(image_class[ index[i] ] == "grImport2::Picture") {
grid.picture = getFromNamespace("grid.picture", ns = "grImport2")
grid.picture(image_list[[i]], x = (i-0.5)/n, width = width, height = height)
}
}
if(border) grid.rect(gp = gpar(fill = "transparent"))
popViewport()
}
row_fun = function(index) {
n = length(index)
pushViewport(viewport())
|
ad35494a |
asp = convertHeight(unit(1/n, "npc") - space*2, "mm", valueOnly = TRUE)/convertWidth(unit(1, "npc") - space*2, "mm", valueOnly = TRUE)
|
402ff791 |
grid.rect(y = (n - 1:n + 0.5)/n, height = 1/n, gp = subset_gp(gp, index))
for(i in seq_len(n)) {
|
10fbf31c |
if(identical(image_list[[i]], NA)) next
|
402ff791 |
if(yx_asp[ index[i] ] > asp) {
height = unit(1/n, "npc") - space*2
width = convertHeight(height, "mm")*(1/yx_asp[ index[i] ])
} else {
width = unit(1, "npc") - space*2
height = yx_asp[ index[i] ]*convertWidth(width, "mm")
}
if(image_class[ index[i] ] == "raster") {
grid.raster(image_list[[i]], y = (n - i + 0.5)/n, width = width, height = height)
} else if(image_class[ index[i] ] == "grImport::Picture") {
grid.picture = getFromNamespace("grid.picture", ns = "grImport")
grid.picture(image_list[[i]], y = (n - i + 0.5)/n, width = width, height = height)
} else if(image_class[ index[i] ] == "grImport2::Picture") {
grid.picture = getFromNamespace("grid.picture", ns = "grImport2")
grid.picture(image_list[[i]], y = (n - i + 0.5)/n, width = width, height = height)
}
}
if(border) grid.rect(gp = gpar(fill = "transparent"))
popViewport()
}
if(which == "row") {
fun = row_fun
} else if(which == "column") {
fun = column_fun
}
anno = AnnotationFunction(
fun = fun,
fun_name = "anno_image",
which = which,
width = anno_size$width,
height = anno_size$height,
n = n_image,
data_scale = c(0.5, 1.5),
var_import = list(gp, border, space, yx_asp, image_list, image_class)
)
anno@subset_rule$gp = subset_vector
anno@subset_rule$image_list = subset_vector
anno@subset_rule$image_class = subset_vector
anno@subsetable = TRUE
return(anno)
}
|
10fbf31c |
# == title
# The Default Parameters for Annotation Axis
#
# == param
# -which Whether it is for column annotation or row annotation?
#
# == details
# There are following parameters for the annotation axis:
#
# -at The breaks of axis. By default it is automatically inferred.
# -labels The corresponding axis labels.
# -labels_rot The rotation of the axis labels.
# -gp Graphc parameters of axis labels. The value should be a `grid::unit` object.
# -side If it is for column annotation, the value should only be one of ``left`` and ``right``. If
# it is for row annotation, the value should only be one of ``top`` and ``bottom``.
# -facing Whether the axis faces to the outside of the annotation region or inside. Sometimes when
# appending more than one heatmaps, the axes of column annotations of one heatmap might
# overlap to the neighbouring heatmap, setting ``facing`` to ``inside`` may invoild it.
#
# == example
# default_axis_param("column")
# default_axis_param("row")
|
402ff791 |
default_axis_param = function(which) {
list(
at = NULL,
labels = NULL,
labels_rot = ifelse(which == "column", 0, 90),
gp = gpar(fontsize = 8),
side = ifelse(which == "column", "left", "bottom"),
facing = "outside"
)
}
validate_axis_param = function(axis_param, which) {
dft = default_axis_param(which)
for(nm in names(axis_param)) {
dft[[nm]] = axis_param[[nm]]
}
return(dft)
}
construct_axis_grob = function(axis_param, which, data_scale) {
axis_param_default = default_axis_param(which)
for(nm in setdiff(names(axis_param_default), names(axis_param))) {
axis_param[[nm]] = axis_param_default[[nm]]
}
if(is.null(axis_param$at)) {
at = pretty_breaks(data_scale)
axis_param$at = at
axis_param$labels = at
}
if(is.null(axis_param$labels)) {
axis_param$labels = axis_param$at
}
axis_grob = do.call(annotation_axis_grob, axis_param)
return(axis_grob)
}
# == title
|
10fbf31c |
# Points Annotation
|
402ff791 |
#
# == param
|
10fbf31c |
# -x The value vector. The value can be a vector or a matrix. The length of the vector
# or the number of rows of the matrix is taken as the number of the observations of the annotation.
# -which Whether it is a column annotation or a row annotation?
# -border Wether draw borders of the annotation region?
# -gp Graphic parameters for points. The length of each graphic parameter can be 1, length of ``x`` if ``x``
# is a vector, or number of columns of ``x`` is ``x`` is a matrix.
# -pch Point type. The length setting is the same as ``gp``.
# -size Point size, the value should be a `grid::unit` object. The length setting is the same as ``gp``.
# -ylim Data ranges. By default it is ``range(x)``.
# -extend The extension to both side of ``ylim``. The value is a percent value corresponding to ``ylim[2] - ylim[1]``.
# -axis Whether to add axis?
# -axis_param parameters for controlling axis. See `default_axis_param` for all possible settings and default parameters.
|
1a56796e |
# -width Width of the annotation. The value should be an absolute unit. Width is not allowed to be set for column annotation.
# -height Height of the annotation. The value should be an absolute unit. Height is not allowed to be set for row annotation.
|
402ff791 |
#
# == value
|
10fbf31c |
# An annotation function which can be used in `HeatmapAnnotation`.
|
402ff791 |
#
|
10fbf31c |
# == example
# anno = anno_points(runif(10))
# draw(anno, test = "anno_points")
# anno = anno_points(matrix(runif(20), nc = 2), pch = 1:2)
# draw(anno, test = "matrix")
|
402ff791 |
anno_points = function(x, which = c("column", "row"), border = TRUE, gp = gpar(), pch = 16,
size = unit(2, "mm"), ylim = NULL, extend = 0.05, axis = TRUE,
|
10fbf31c |
axis_param = default_axis_param(which), width = NULL, height = NULL) {
|
402ff791 |
if(is.null(.ENV$current_annotation_which)) {
which = match.arg(which)[1]
} else {
which = .ENV$current_annotation_which
}
if(is.data.frame(x)) x = as.matrix(x)
if(is.matrix(x)) {
if(ncol(x) == 1) {
x = x[, 1]
}
}
input_is_matrix = is.matrix(x)
anno_size = anno_width_and_height(which, width, height, unit(1, "cm"))
if(is.matrix(x)) {
n = nrow(x)
nr = n
nc = ncol(x)
} else {
n = length(x)
nr = n
nc = 1
}
|
10fbf31c |
if(input_is_matrix) {
|
402ff791 |
gp = recycle_gp(gp, nc)
if(length(pch) == 1) pch = rep(pch, nc)
if(length(size) == 1) size = rep(size, nc)
|
10fbf31c |
} else if(is.atomic(x)) {
gp = recycle_gp(gp, n)
if(length(pch) == 1) pch = rep(pch, n)
if(length(size) == 1) size = rep(size, n)
|
402ff791 |
}
|
10fbf31c |
|
402ff791 |
if(is.null(ylim)) {
data_scale = range(x, na.rm = TRUE)
} else {
data_scale = ylim
}
data_scale = data_scale + c(-extend, extend)*(data_scale[2] - data_scale[1])
value = x
axis_param = validate_axis_param(axis_param, which)
axis_grob = if(axis) construct_axis_grob(axis_param, which, data_scale) else NULL
|
ad35494a |
row_fun = function(index, k = 1, N = 1) {
|
402ff791 |
n = length(index)
pushViewport(viewport(xscale = data_scale, yscale = c(0.5, n+0.5)))
if(is.matrix(value)) {
for(i in seq_len(ncol(value))) {
grid.points(value[index, i], n - seq_along(index) + 1, gp = subset_gp(gp, i),
default.units = "native", pch = pch[i], size = size[i])
}
} else {
grid.points(value[index], n - seq_along(index) + 1, gp = gp, default.units = "native",
pch = pch[index], size = size[index])
}
|
ad35494a |
if(axis_param$side == "top") {
if(k > 1) axis = FALSE
} else if(axis_param$side == "bottom") {
if(k < N) axis = FALSE
}
|
402ff791 |
if(axis) grid.draw(axis_grob)
if(border) grid.rect(gp = gpar(fill = "transparent"))
popViewport()
}
|
ad35494a |
column_fun = function(index, k = 1, N = 1) {
|
402ff791 |
n = length(index)
pushViewport(viewport(yscale = data_scale, xscale = c(0.5, n+0.5)))
if(is.matrix(value)) {
for(i in seq_len(ncol(value))) {
grid.points(seq_along(index), value[index, i], gp = subset_gp(gp, i), default.units = "native", pch = pch[i], size = size[i])
}
} else {
grid.points(seq_along(index), value[index], gp = gp, default.units = "native", pch = pch[index], size = size[index])
}
|
ad35494a |
if(axis_param$side == "left") {
if(k > 1) axis = FALSE
} else if(axis_param$side == "right") {
if(k < N) axis = FALSE
}
|
402ff791 |
if(axis) grid.draw(axis_grob)
if(border) grid.rect(gp = gpar(fill = "transparent"))
popViewport()
}
if(which == "row") {
fun = row_fun
} else if(which == "column") {
fun = column_fun
}
anno = AnnotationFunction(
fun = fun,
fun_name = "anno_points",
which = which,
width = anno_size$width,
height = anno_size$height,
n = n,
data_scale = data_scale,
var_import = list(value, gp, border, pch, size, axis, axis_param, axis_grob, data_scale)
)
anno@subset_rule$gp = subset_vector
if(input_is_matrix) {
anno@subset_rule$value = subset_matrix_by_row
} else {
anno@subset_rule$value = subset_vector
anno@subset_rule$gp = subset_gp
anno@subset_rule$size = subset_vector
anno@subset_rule$pch = subset_vector
}
anno@subsetable = TRUE
anno@extended = update_anno_extend(anno, axis_grob, axis_param)
return(anno)
}
update_anno_extend = function(anno, axis_grob, axis_param) {
extended = anno@extended
if(axis_param$facing == "outside") {
if(axis_param$side == "left") {
extended[[2]] = convertWidth(grobWidth(axis_grob), "mm", valueOnly = TRUE)
} else if(axis_param$side == "right") {
extended[[4]] = convertWidth(grobWidth(axis_grob), "mm", valueOnly = TRUE)
} else if(axis_param$side == "top") {
extended[[3]] = convertHeight(grobHeight(axis_grob), "mm", valueOnly = TRUE)
} else if(axis_param$side == "bottom") {
extended[[1]] = convertHeight(grobHeight(axis_grob), "mm", valueOnly = TRUE)
}
}
return(extended)
}
|
10fbf31c |
# == title
# Lines Annotation
#
# == param
# -x The value vector. The value can be a vector or a matrix. The length of the vector
# or the number of rows of the matrix is taken as the number of the observations of the annotation.
# -which Whether it is a column annotation or a row annotation?
# -border Wether draw borders of the annotation region?
# -gp Graphic parameters for lines. The length of each graphic parameter can be 1, or number of columns of ``x`` is ``x`` is a matrix.
# -add_points Whether to add points on the lines?
|
1a56796e |
# -smooth If it is ``TRUE``, smoothing by `stats::loess` is performed. If it is ``TRUE``, ``add_points`` is set to ``TRUE`` by default.
|
10fbf31c |
# -pch Point type. The length setting is the same as ``gp``.
# -size Point size, the value should be a `grid::unit` object. The length setting is the same as ``gp``.
|
ad35494a |
# -pt_gp Graphic parameters for points. The length setting is the same as ``gp``.
|
10fbf31c |
# -ylim Data ranges. By default it is ``range(x)``.
# -extend The extension to both side of ``ylim``. The value is a percent value corresponding to ``ylim[2] - ylim[1]``.
# -axis Whether to add axis?
# -axis_param parameters for controlling axis. See `default_axis_param` for all possible settings and default parameters.
|
1a56796e |
# -width Width of the annotation. The value should be an absolute unit. Width is not allowed to be set for column annotation.
# -height Height of the annotation. The value should be an absolute unit. Height is not allowed to be set for row annotation.
|
10fbf31c |
#
# == value
# An annotation function which can be used in `HeatmapAnnotation`.
#
# == example
# anno = anno_lines(runif(10))
# draw(anno, test = "anno_lines")
# anno = anno_lines(cbind(c(1:5, 1:5), c(5:1, 5:1)), gp = gpar(col = 2:3))
# draw(anno, test = "matrix")
# anno = anno_lines(cbind(c(1:5, 1:5), c(5:1, 5:1)), gp = gpar(col = 2:3),
# add_points = TRUE, pt_gp = gpar(col = 5:6), pch = c(1, 16))
# draw(anno, test = "matrix")
|
402ff791 |
anno_lines = function(x, which = c("column", "row"), border = TRUE, gp = gpar(),
|
1a56796e |
add_points = smooth, smooth = FALSE, pch = 16, size = unit(2, "mm"), pt_gp = gpar(), ylim = NULL,
|
402ff791 |
extend = 0.05, axis = TRUE, axis_param = default_axis_param(which),
width = NULL, height = NULL) {
if(is.null(.ENV$current_annotation_which)) {
which = match.arg(which)[1]
} else {
which = .ENV$current_annotation_which
}
if(is.data.frame(x)) x = as.matrix(x)
if(is.matrix(x)) {
if(ncol(x) == 1) {
x = x[, 1]
}
}
input_is_matrix = is.matrix(x)
anno_size = anno_width_and_height(which, width, height, unit(1, "cm"))
if(is.matrix(x)) {
n = nrow(x)
nr = n
nc = ncol(x)
} else {
n = length(x)
nr = n
nc = 1
}
|
10fbf31c |
if(input_is_matrix) {
|
402ff791 |
gp = recycle_gp(gp, nc)
pt_gp = recycle_gp(pt_gp, nc)
if(length(pch) == 1) pch = rep(pch, nc)
if(length(size) == 1) size = rep(size, nc)
|
10fbf31c |
} else if(is.atomic(x)) {
gp = recycle_gp(gp, 1)
pt_gp = recycle_gp(pt_gp, n)
if(length(pch) == 1) pch = rep(pch, n)
if(length(size) == 1) size = rep(size, n)
|
402ff791 |
}
|
10fbf31c |
|
402ff791 |
if(is.null(ylim)) {
data_scale = range(x, na.rm = TRUE)
} else {
data_scale = ylim
}
data_scale = data_scale + c(-extend, extend)*(data_scale[2] - data_scale[1])
value = x
axis_param = validate_axis_param(axis_param, which)
axis_grob = if(axis) construct_axis_grob(axis_param, which, data_scale) else NULL
|
ad35494a |
row_fun = function(index, k = 1, N = 1) {
|
402ff791 |
n = length(index)
pushViewport(viewport(xscale = data_scale, yscale = c(0.5, n+0.5)))
if(is.matrix(value)) {
for(i in seq_len(ncol(value))) {
|
933e808c |
x = n - seq_along(index) + 1
y = value[index, i]
if(smooth) {
fit = loess(y ~ x)
x2 = seq(x[1], x[length(x)], length = 100)
y2 = predict(fit, x2)
grid.lines(y2, x2, gp = subset_gp(gp, i), default.units = "native")
} else {
grid.lines(y, x, gp = subset_gp(gp, i), default.units = "native")
}
|
402ff791 |
if(add_points) {
|
933e808c |
grid.points(y, x, gp = subset_gp(pt_gp, i),
|
402ff791 |
default.units = "native", pch = pch[i], size = size[i])
}
}
} else {
|
933e808c |
x = n - seq_along(index) + 1
y = value[index]
if(smooth) {
fit = loess(y ~ x)
x2 = seq(x[1], x[length(x)], length = 100)
y2 = predict(fit, x2)
grid.lines(y2, x2, gp = gp, default.units = "native")
} else {
grid.lines(y, x, gp = gp, default.units = "native")
}
|
402ff791 |
if(add_points) {
|
933e808c |
grid.points(y, x, gp = gp, default.units = "native",
|
402ff791 |
pch = pch[index], size = size[index])
}
}
|
ad35494a |
if(axis_param$side == "top") {
if(k > 1) axis = FALSE
} else if(axis_param$side == "bottom") {
if(k < N) axis = FALSE
}
|
402ff791 |
if(axis) grid.draw(axis_grob)
if(border) grid.rect(gp = gpar(fill = "transparent"))
popViewport()
}
|
ad35494a |
column_fun = function(index, k = 1, N = 1) {
|
402ff791 |
n = length(index)
|
10fbf31c |
|
402ff791 |
pushViewport(viewport(yscale = data_scale, xscale = c(0.5, n+0.5)))
if(is.matrix(value)) {
for(i in seq_len(ncol(value))) {
|
933e808c |
x = seq_along(index)
y = value[index, i]
if(smooth) {
fit = loess(y ~ x)
x2 = seq(x[1], x[length(x)], length = 100)
y2 = predict(fit, x2)
grid.lines(x2, y2, gp = subset_gp(gp, i), default.units = "native")
} else {
grid.lines(x, y, gp = subset_gp(gp, i), default.units = "native")
}
|
402ff791 |
if(add_points) {
|
933e808c |
grid.points(x, y, gp = subset_gp(pt_gp, i),
|
402ff791 |
default.units = "native", pch = pch[i], size = size[i])
}
}
} else {
|
933e808c |
x = seq_along(index)
y = value[index]
if(smooth) {
fit = loess(y ~ x)
x2 = seq(x[1], x[length(x)], length = 100)
y2 = predict(fit, x2)
grid.lines(x2, y2, gp = gp, default.units = "native")
} else {
grid.lines(x, y, gp = gp, default.units = "native")
}
|
402ff791 |
if(add_points) {
grid.points(seq_along(index), value[index], gp = pt_gp, default.units = "native",
pch = pch[index], size = size[index])
}
}
|
ad35494a |
if(axis_param$side == "left") {
if(k > 1) axis = FALSE
} else if(axis_param$side == "right") {
if(k < N) axis = FALSE
}
|
402ff791 |
if(axis) grid.draw(axis_grob)
if(border) grid.rect(gp = gpar(fill = "transparent"))
popViewport()
}
if(which == "row") {
fun = row_fun
} else if(which == "column") {
fun = column_fun
}
anno = AnnotationFunction(
fun = fun,
fun_name = "anno_points",
which = which,
width = anno_size$width,
height = anno_size$height,
n = n,
data_scale = data_scale,
|
933e808c |
var_import = list(value, gp, border, pch, size, pt_gp, axis, axis_param,
axis_grob, data_scale, add_points, smooth)
|
402ff791 |
)
anno@subset_rule$gp = subset_vector
if(input_is_matrix) {
anno@subset_rule$value = subset_matrix_by_row
} else {
anno@subset_rule$value = subset_vector
anno@subset_rule$gp = subset_gp
anno@subset_rule$pt_gp = subset_gp
anno@subset_rule$size = subset_vector
anno@subset_rule$pch = subset_vector
}
anno@subsetable = TRUE
anno@extended = update_anno_extend(anno, axis_grob, axis_param)
return(anno)
}
# == title
|
10fbf31c |
# Barplot Annotation
|
402ff791 |
#
# == param
|
10fbf31c |
# -x The value vector. The value can be a vector or a matrix. The length of the vector
# or the number of rows of the matrix is taken as the number of the observations of the annotation.
# If ``x`` is a vector, the barplots will be represented as stacked barplots.
# -baseline baseline of bars. The value should be "min" or "max", or a numeric value. It is enforced to be zero
|
402ff791 |
# for stacked barplots.
|
10fbf31c |
# -which Whether it is a column annotation or a row annotation?
# -border Wether draw borders of the annotation region?
# -bar_width Relative width of the bars. The value should be smaller than one.
# -gp Graphic parameters for points. The length of each graphic parameter can be 1, length of ``x`` if ``x``
# is a vector, or number of columns of ``x`` is ``x`` is a matrix.
# -ylim Data ranges. By default it is ``range(x)`` if ``x`` is a vector, or ``range(rowSums(x))`` if ``x`` is a matrix.
# -extend The extension to both side of ``ylim``. The value is a percent value corresponding to ``ylim[2] - ylim[1]``.
# -axis Whether to add axis?
# -axis_param parameters for controlling axis. See `default_axis_param` for all possible settings and default parameters.
|
1a56796e |
# -width Width of the annotation. The value should be an absolute unit. Width is not allowed to be set for column annotation.
# -height Height of the annotation. The value should be an absolute unit. Height is not allowed to be set for row annotation.
|
402ff791 |
#
# == value
|
10fbf31c |
# An annotation function which can be used in `HeatmapAnnotation`.
|
402ff791 |
#
|
10fbf31c |
# == example
# anno = anno_barplot(1:10)
# draw(anno, test = "a vector")
|
402ff791 |
#
|
10fbf31c |
# m = matrix(runif(4*10), nc = 4)
# m = t(apply(m, 1, function(x) x/sum(x)))
# anno = anno_barplot(m, gp = gpar(fill = 2:5), bar_width = 1, height = unit(6, "cm"))
# draw(anno, test = "proportion matrix")
|
402ff791 |
anno_barplot = function(x, baseline = 0, which = c("column", "row"), border = TRUE, bar_width = 0.6,
gp = gpar(fill = "#CCCCCC"), ylim = NULL, extend = 0.05, axis = TRUE,
axis_param = default_axis_param(which),
width = NULL, height = NULL) {
if(inherits(x, "list")) x = do.call("cbind", x)
if(inherits(x, "data.frame")) x = as.matrix(x)
if(inherits(x, "matrix")) {
sg = apply(x, 1, function(xx) all(sign(xx) %in% c(1, 0)) || all(sign(xx) %in% c(-1, 0)))
if(!all(sg)) {
stop_wrap("Since `x` is a matrix, the sign of each row should be either all positive or all negative.")
}
}
# convert everything to matrix
if(is.null(dim(x))) x = matrix(x, ncol = 1)
nc = ncol(x)
if(missing(gp)) {
gp = gpar(fill = grey(seq(0, 1, length = nc+2))[-c(1, nc+2)])
}
data_scale = range(rowSums(x, na.rm = TRUE), na.rm = TRUE)
if(!is.null(ylim)) data_scale = ylim
if(baseline == "min") {
data_scale = data_scale + c(0, extend)*(data_scale[2] - data_scale[1])
|
933e808c |
baseline = min(x)
|
402ff791 |
} else if(baseline == "max") {
data_scale = data_scale + c(-extend, 0)*(data_scale[2] - data_scale[1])
|
933e808c |
baseline = max(x)
|
402ff791 |
} else {
if(is.numeric(baseline)) {
|
7db3856b |
if(baseline == 0 && all(abs(rowSums(x) - 1) < 1e-6)) {
|
402ff791 |
data_scale = c(0, 1)
} else if(baseline <= min(x)) {
data_scale = c(baseline, extend*(data_scale[2] - baseline) + data_scale[2])
|
933e808c |
} else if(baseline >= max(x)) {
|
402ff791 |
data_scale = c(-extend*(baseline - data_scale[1]) + data_scale[1], baseline)
} else {
data_scale = data_scale + c(-extend, extend)*(data_scale[2] - data_scale[1])
}
}
}
if(is.null(.ENV$current_annotation_which)) {
which = match.arg(which)[1]
} else {
which = .ENV$current_annotation_which
}
anno_size = anno_width_and_height(which, width, height, unit(1, "cm"))
if(nc == 1) {
gp = recycle_gp(gp, nrow(x))
} else {
gp = recycle_gp(gp, nc)
}
value = x
axis_param = validate_axis_param(axis_param, which)
axis_grob = if(axis) construct_axis_grob(axis_param, which, data_scale) else NULL
|
ad35494a |
row_fun = function(index, k = 1, N = 1) {
|
402ff791 |
n = length(index)
pushViewport(viewport(xscale = data_scale, yscale = c(0.5, n+0.5)))
if(ncol(value) == 1) {
width = value[index] - baseline
x_coor = width/2+baseline
grid.rect(x = x_coor, y = n - seq_along(index) + 1, width = abs(width), height = 1*bar_width, default.units = "native", gp = subset_gp(gp, index))
} else {
for(i in seq_len(ncol(value))) {
width = value[index, i]
x_coor = rowSums(value[index, seq_len(i-1), drop = FALSE]) + width/2
grid.rect(x = x_coor, y = n - seq_along(index) + 1, width = abs(width), height = 1*bar_width, default.units = "native", gp = subset_gp(gp, i))
}
}
|
ad35494a |
if(axis_param$side == "top") {
if(k > 1) axis = FALSE
} else if(axis_param$side == "bottom") {
if(k < N) axis = FALSE
}
|
402ff791 |
if(axis) grid.draw(axis_grob)
if(border) grid.rect(gp = gpar(fill = "transparent"))
popViewport()
}
|
ad35494a |
column_fun = function(index, k = 1, N = 1) {
|
402ff791 |
n = length(index)
pushViewport(viewport(yscale = data_scale, xscale = c(0.5, n+0.5)))
if(ncol(value) == 1) {
height = value[index] - baseline
y_coor = height/2+baseline
grid.rect(y = y_coor, x = seq_along(index), height = abs(height), width = 1*bar_width, default.units = "native", gp = subset_gp(gp, index))
} else {
for(i in seq_len(ncol(value))) {
height = value[index, i]
y_coor = rowSums(value[index, seq_len(i-1), drop = FALSE]) + height/2
grid.rect(y = y_coor, x = seq_along(index), height = abs(height), width = 1*bar_width, default.units = "native", gp = subset_gp(gp, i))
}
}
|
ad35494a |
if(axis_param$side == "left") {
if(k > 1) axis = FALSE
} else if(axis_param$side == "right") {
if(k < N) axis = FALSE
}
|
402ff791 |
if(axis) grid.draw(axis_grob)
if(border) grid.rect(gp = gpar(fill = "transparent"))
popViewport()
}
if(which == "row") {
fun = row_fun
} else if(which == "column") {
fun = column_fun
}
n = nrow(value)
anno = AnnotationFunction(
fun = fun,
fun_name = "anno_barplot",
which = which,
width = anno_size$width,
height = anno_size$height,
n = n,
data_scale = data_scale,
var_import = list(value, gp, border, bar_width, baseline, axis, axis_param, axis_grob, data_scale)
)
anno@subset_rule$value = subset_matrix_by_row
if(ncol(value) == 1) {
anno@subset_rule$gp = subset_gp
}
anno@subsetable = TRUE
anno@extended = update_anno_extend(anno, axis_grob, axis_param)
return(anno)
}
# == title
|
10fbf31c |
# Boxplot Annotation
|
402ff791 |
#
# == param
|
10fbf31c |
# -x A matrix or a list. If ``x`` is a matrix and if ``which`` is ``column``, statistics for boxplots
# are calculated by columns, if ``which`` is ``row``, the calculation is done by rows.
# -which Whether it is a column annotation or a row annotation?
# -border Wether draw borders of the annotation region?
# -gp Graphic parameters for the boxes. The length of the graphic parameters should be one or the number of observations.
# -ylim Data ranges.
# -extend The extension to both side of ``ylim``. The value is a percent value corresponding to ``ylim[2] - ylim[1]``.
# -outline Whether draw outline of boxplots?
# -box_width Relative width of boxes. The value should be smaller than one.
# -pch Point style.
# -size Point size.
# -axis Whether to add axis?
# -axis_param parameters for controlling axis. See `default_axis_param` for all possible settings and default parameters.
|
1a56796e |
# -width Width of the annotation. The value should be an absolute unit. Width is not allowed to be set for column annotation.
# -height Height of the annotation. The value should be an absolute unit. Height is not allowed to be set for row annotation.
|
402ff791 |
#
# == value
|
10fbf31c |
# An annotation function which can be used in `HeatmapAnnotation`.
#
# == example
# set.seed(123)
# m = matrix(rnorm(100), 10)
# anno = anno_boxplot(m, height = unit(4, "cm"))
# draw(anno, test = "anno_boxplot")
# anno = anno_boxplot(m, height = unit(4, "cm"), gp = gpar(fill = 1:10))
# draw(anno, test = "anno_boxplot with gp")
|
402ff791 |
anno_boxplot = function(x, which = c("column", "row"), border = TRUE,
gp = gpar(fill = "#CCCCCC"), ylim = NULL, extend = 0.05, outline = TRUE, box_width = 0.6,
pch = 1, size = unit(2, "mm"), axis = TRUE, axis_param = default_axis_param(which),
width = NULL, height = NULL) {
if(is.null(.ENV$current_annotation_which)) {
which = match.arg(which)[1]
} else {
which = .ENV$current_annotation_which
}
anno_size = anno_width_and_height(which, width, height, unit(2, "cm"))
## convert matrix all to list (or data frame)
if(is.matrix(x)) {
if(which == "column") {
value = as.data.frame(x)
} else if(which == "row") {
value = as.data.frame(t(x))
}
} else {
value = x
}
if(is.null(ylim)) {
if(!outline) {
boxplot_stats = boxplot(value, plot = FALSE)$stats
data_scale = range(boxplot_stats)
} else {
data_scale = range(value, na.rm = TRUE)
}
} else {
data_scale = ylim
}
data_scale = data_scale + c(-extend, extend)*(data_scale[2] - data_scale[1])
n = length(value)
gp = recycle_gp(gp, n)
if(length(pch) == 1) pch = rep(pch, n)
if(length(size) == 1) size = rep(size, n)
axis_param = validate_axis_param(axis_param, which)
axis_grob = if(axis) construct_axis_grob(axis_param, which, data_scale) else NULL
|
ad35494a |
row_fun = function(index, k = 1, N = 1) {
|
402ff791 |
n_all = length(value)
value = value[index]
boxplot_stats = boxplot(value, plot = FALSE)$stats
n = length(index)
gp = subset_gp(gp, index)
pushViewport(viewport(xscale = data_scale, yscale = c(0.5, n+0.5)))
grid.rect(x = boxplot_stats[2, ], y = n - seq_along(index) + 1,
height = 1*box_width, width = boxplot_stats[4, ] - boxplot_stats[2, ], just = "left",
default.units = "native", gp = gp)
grid.segments(boxplot_stats[5, ], n - seq_along(index) + 1 - 0.5*box_width,
boxplot_stats[5, ], n - seq_along(index) + 1 + 0.5*box_width,
default.units = "native", gp = gp)
grid.segments(boxplot_stats[5, ], n - seq_along(index) + 1,
boxplot_stats[4, ], n - seq_along(index) + 1,
default.units = "native", gp = gp)
grid.segments(boxplot_stats[1, ], n - seq_along(index) + 1,
boxplot_stats[2, ], n - seq_along(index) + 1,
default.units = "native", gp = gp)
grid.segments(boxplot_stats[1, ], n - seq_along(index) + 1 - 0.5*box_width,
boxplot_stats[1, ], n - seq_along(index) + 1 + 0.5*box_width,
default.units = "native", gp = gp)
grid.segments(boxplot_stats[3, ], n - seq_along(index) + 1 - 0.5*box_width,
boxplot_stats[3, ], n - seq_along(index) + 1 + 0.5*box_width,
default.units = "native", gp = gp)
if(outline) {
for(i in seq_along(value)) {
l1 = value[[i]] > boxplot_stats[5,i]
if(sum(l1)) grid.points(y = rep(n - i + 1, sum(l1)), x = value[[i]][l1],
default.units = "native", gp = subset_gp(gp, i), pch = pch[i], size = size[i])
l2 = value[[i]] < boxplot_stats[1,i]
if(sum(l2)) grid.points(y = rep(n - i + 1, sum(l2)), x = value[[i]][l2],
default.units = "native", gp = subset_gp(gp, i), pch = pch[i], size = size[i])
}
}
|
ad35494a |
if(axis_param$side == "top") {
if(k > 1) axis = FALSE
} else if(axis_param$side == "bottom") {
if(k < N) axis = FALSE
}
|
402ff791 |
if(axis) grid.draw(axis_grob)
if(border) grid.rect(gp = gpar(fill = "transparent"))
popViewport()
}
|
ad35494a |
column_fun = function(index, k = 1, N = 1) {
|
402ff791 |
value = value[index]
boxplot_stats = boxplot(value, plot = FALSE)$stats
n = length(index)
gp = subset_gp(gp, index)
pushViewport(viewport(xscale = c(0.5, n+0.5), yscale = data_scale))
grid.rect(x = seq_along(index), y = boxplot_stats[2, ],
height = boxplot_stats[4, ] - boxplot_stats[2, ], width = 1*box_width, just = "bottom",
default.units = "native", gp = gp)
grid.segments(seq_along(index) - 0.5*box_width, boxplot_stats[5, ],
seq_along(index) + 0.5*box_width, boxplot_stats[5, ],
default.units = "native", gp = gp)
grid.segments(seq_along(index), boxplot_stats[5, ],
seq_along(index), boxplot_stats[4, ],
default.units = "native", gp = gp)
grid.segments(seq_along(index), boxplot_stats[1, ],
seq_along(index), boxplot_stats[2, ],
default.units = "native", gp = gp)
grid.segments(seq_along(index) - 0.5*box_width, boxplot_stats[1, ],
seq_along(index) + 0.5*box_width, boxplot_stats[1, ],
default.units = "native", gp = gp)
grid.segments(seq_along(index) - 0.5*box_width, boxplot_stats[3, ],
seq_along(index) + 0.5*box_width, boxplot_stats[3, ],
default.units = "native", gp = gp)
if(outline) {
for(i in seq_along(value)) {
l1 = value[[i]] > boxplot_stats[5,i]
if(sum(l1)) grid.points(x = rep(i, sum(l1)), y = value[[i]][l1],
default.units = "native", gp = subset_gp(gp, i), pch = pch[i], size = size[i])
l2 = value[[i]] < boxplot_stats[1,i]
if(sum(l2)) grid.points(x = rep(i, sum(l2)), y = value[[i]][l2],
default.units = "native", gp = subset_gp(gp, i), pch = pch[i], size = size[i])
}
}
|
ad35494a |
if(axis_param$side == "left") {
if(k > 1) axis = FALSE
} else if(axis_param$side == "right") {
if(k < N) axis = FALSE
}
|
402ff791 |
if(axis) grid.draw(axis_grob)
if(border) grid.rect(gp = gpar(fill = "transparent"))
popViewport()
}
if(which == "row") {
fun = row_fun
} else if(which == "column") {
fun = column_fun
}
anno = AnnotationFunction(
fun = fun,
fun_name = "anno_boxplot",
which = which,
n = n,
width = anno_size$width,
height = anno_size$height,
data_scale = data_scale,
var_import = list(value, gp, border, box_width, axis, axis_param, axis_grob, data_scale, pch, size, outline)
)
anno@subset_rule$value = subset_vector
anno@subset_rule$gp = subset_gp
anno@subset_rule$pch = subset_vector
anno@subset_rule$size = subset_vector
anno@subsetable = TRUE
anno@extended = update_anno_extend(anno, axis_grob, axis_param)
return(anno)
}
# == title
|
10fbf31c |
# Histogram Annotation
|
402ff791 |
#
# == param
|
10fbf31c |
# -x A matrix or a list. If ``x`` is a matrix and if ``which`` is ``column``, statistics for boxplots
# are calculated by columns, if ``which`` is ``row``, the calculation is done by rows.
# -which Whether it is a column annotation or a row annotation?
# -n_breaks Number of breaks for calculating histogram.
# -border Wether draw borders of the annotation region?
# -gp Graphic parameters for the boxes. The length of the graphic parameters should be one or the number of observations.
# -axis Whether to add axis?
# -axis_param parameters for controlling axis. See `default_axis_param` for all possible settings and default parameters.
|
1a56796e |
# -width Width of the annotation. The value should be an absolute unit. Width is not allowed to be set for column annotation.
# -height Height of the annotation. The value should be an absolute unit. Height is not allowed to be set for row annotation.
|
402ff791 |
#
# == value
|
10fbf31c |
# An annotation function which can be used in `HeatmapAnnotation`.
#
# == example
# m = matrix(rnorm(1000), nc = 10)
# anno = anno_histogram(t(m), which = "row")
# draw(anno, test = "row histogram")
# anno = anno_histogram(t(m), which = "row", gp = gpar(fill = 1:10))
# draw(anno, test = "row histogram with color")
# anno = anno_histogram(t(m), which = "row", n_breaks = 20)
# draw(anno, test = "row histogram with color")
|
402ff791 |
anno_histogram = function(x, which = c("column", "row"), n_breaks = 11,
border = FALSE, gp = gpar(fill = "#CCCCCC"),
axis = TRUE, axis_param = default_axis_param(which),
width = NULL, height = NULL) {
if(is.null(.ENV$current_annotation_which)) {
which = match.arg(which)[1]
} else {
which = .ENV$current_annotation_which
}
anno_size = anno_width_and_height(which, width, height, unit(4, "cm"))
## convert matrix all to list (or data frame)
if(is.matrix(x)) {
if(which == "column") {
value = as.data.frame(x)
} else if(which == "row") {
value = as.data.frame(t(x))
}
} else {
value = x
}
n = length(value)
x_range =range(unlist(value), na.rm = TRUE)
histogram_stats = lapply(value, hist, plot = FALSE, breaks = seq(x_range[1], x_range[2], length = n_breaks))
histogram_breaks = lapply(histogram_stats, function(x) x$breaks)
histogram_counts = lapply(histogram_stats, function(x) x$counts)
xscale = range(unlist(histogram_breaks), na.rm = TRUE)
xscale = xscale + c(0, 0.05)*(xscale[2] - xscale[1])
yscale = c(0, max(unlist(histogram_counts)))
yscale[2] = yscale[2]*1.05
gp = recycle_gp(gp, n)
axis_param = validate_axis_param(axis_param, which)
axis_grob = if(axis) construct_axis_grob(axis_param, which, xscale) else NULL
|
ad35494a |
row_fun = function(index, k = 1, N = 1) {
|
402ff791 |
n_all = length(value)
value = value[index]
n = length(index)
histogram_breaks = histogram_breaks[index]
histogram_counts = histogram_counts[index]
gp = subset_gp(gp, index)
for(i in seq_len(n)) {
n_breaks = length(histogram_breaks[[i]])
pushViewport(viewport(x = unit(0, "npc"), y = unit((n-i)/n, "npc"), height = unit(1/n, "npc"), just = c("left", "bottom"), xscale = xscale, yscale = yscale))
grid.rect(x = histogram_breaks[[i]][-1], y = 0, width = histogram_breaks[[i]][-1] - histogram_breaks[[i]][-n_breaks], height = histogram_counts[[i]], just = c("right", "bottom"), default.units = "native", gp = subset_gp(gp, i))
popViewport()
}
pushViewport(viewport(xscale = xscale))
|
ad35494a |
if(axis_param$side == "top") {
if(k > 1) axis = FALSE
} else if(axis_param$side == "bottom") {
if(k < N) axis = FALSE
}
|
402ff791 |
if(axis) grid.draw(axis_grob)
if(border) grid.rect(gp = gpar(fill = "transparent"))
popViewport()
}
|
ad35494a |
column_fun = function(index, k = 1, N = 1) {
|
402ff791 |
n_all = length(value)
value = value[index]
foo = yscale
yscale = xscale
xscale = foo
histogram_breaks = histogram_breaks[index]
histogram_counts = histogram_counts[index]
n = length(index)
gp = subset_gp(gp, index)
for(i in seq_len(n)) {
n_breaks = length(histogram_breaks[[i]])
pushViewport(viewport(y = unit(0, "npc"), x = unit(i/n, "npc"), width = unit(1/n, "npc"),
just = c("right", "bottom"), xscale = xscale, yscale = yscale))
grid.rect(y = histogram_breaks[[i]][-1], x = 0, height = histogram_breaks[[i]][-1] - histogram_breaks[[i]][-n_breaks],
width = histogram_counts[[i]], just = c("left", "top"), default.units = "native", gp = subset_gp(gp, index[i]))
popViewport()
}
pushViewport(viewport(yscale = yscale))
|
ad35494a |
if(axis_param$side == "left") {
if(k > 1) axis = FALSE
} else if(axis_param$side == "right") {
if(k < N) axis = FALSE
}
|
402ff791 |
if(axis) grid.draw(axis_grob)
if(border) grid.rect(gp = gpar(fill = "transparent"))
popViewport()
}
if(which == "row") {
fun = row_fun
} else if(which == "column") {
fun = column_fun
}
anno = AnnotationFunction(
fun = fun,
fun_name = "anno_histogram",
which = which,
width = anno_size$width,
height = anno_size$height,
n = n,
data_scale = xscale,
var_import = list(value, gp, border, axis, axis_param, axis_grob, xscale, yscale,
histogram_breaks, histogram_counts)
)
anno@subset_rule$value = subset_vector
anno@subset_rule$gp = subset_gp
anno@subset_rule$histogram_breaks = subset_vector
anno@subset_rule$histogram_counts = subset_vector
anno@subsetable = TRUE
anno@extended = update_anno_extend(anno, axis_grob, axis_param)
return(anno)
}
# == title
|
10fbf31c |
# Density Annotation
|
402ff791 |
#
# == param
|
10fbf31c |
# -x A matrix or a list. If ``x`` is a matrix and if ``which`` is ``column``, statistics for boxplots
# are calculated by columns, if ``which`` is ``row``, the calculation is done by rows.
# -which Whether it is a column annotation or a row annotation?
# -type Type of graphics to represent density distribution. "lines" for normal density plot; "violine" for violin plot
# and "heatmap" for heatmap visualization of density distribution.
# -heatmap_colors A vector of colors for interpolating density values.
# -joyplot_scale Relative height of density distribution. A value higher than 1 increases the height of the density
# distribution and the plot will represented as so-called "joyplot".
# -border Wether draw borders of the annotation region?
# -gp Graphic parameters for the boxes. The length of the graphic parameters should be one or the number of observations.
# -axis Whether to add axis?
# -axis_param parameters for controlling axis. See `default_axis_param` for all possible settings and default parameters.
|
1a56796e |
# -width Width of the annotation. The value should be an absolute unit. Width is not allowed to be set for column annotation.
# -height Height of the annotation. The value should be an absolute unit. Height is not allowed to be set for row annotation.
|
402ff791 |
#
# == value
|
10fbf31c |
# An annotation function which can be used in `HeatmapAnnotation`.
#
# == example
|
ad35494a |
# m = matrix(rnorm(100), 10)
# anno = anno_density(m, which = "row")
|
10fbf31c |
# draw(anno, test = "normal density")
|
ad35494a |
# anno = anno_density(m, which = "row", type = "violin")
|
10fbf31c |
# draw(anno, test = "violin")
|
ad35494a |
# anno = anno_density(m, which = "row", type = "heatmap")
|
10fbf31c |
# draw(anno, test = "heatmap")
|
ad35494a |
# anno = anno_density(m, which = "row", type = "heatmap",
|
10fbf31c |
# heatmap_colors = c("white", "orange"))
# draw(anno, test = "heatmap, colors")
anno_density = function(x, which = c("column", "row"),
|
402ff791 |
type = c("lines", "violin", "heatmap"),
heatmap_colors = rev(brewer.pal(name = "RdYlBu", n = 11)),
|
10fbf31c |
joyplot_scale = 1, border = TRUE, gp = gpar(fill = "#CCCCCC"),
|
402ff791 |
axis = TRUE, axis_param = default_axis_param(which),
width = NULL, height = NULL) {
if(is.null(.ENV$current_annotation_which)) {
which = match.arg(which)[1]
} else {
which = .ENV$current_annotation_which
}
anno_size = anno_width_and_height(which, width, height, unit(4, "cm"))
## convert matrix all to list (or data frame)
if(is.matrix(x)) {
if(which == "column") {
value = as.data.frame(x)
} else if(which == "row") {
value = as.data.frame(t(x))
}
} else {
value = x
}
n = length(value)
gp = recycle_gp(gp, n)
type = match.arg(type)[1]
n_all = length(value)
density_stats = lapply(value, density)
density_x = lapply(density_stats, function(x) x$x)
density_y = lapply(density_stats, function(x) x$y)
min_density_x = min(unlist(density_x))
max_density_x = max(unlist(density_x))
xscale = range(unlist(density_x), na.rm = TRUE)
xscale = xscale + c(0, 0.05)*(xscale[2] - xscale[1])
if(type == "lines") {
yscale = c(0, max(unlist(density_y)))
yscale[2] = yscale[2]*1.05
} else if(type == "violin") {
yscale = max(unlist(density_y))
yscale = c(-yscale*1.05, yscale*1.05)
} else if(type == "heatmap") {
xscale = range(unlist(density_x), na.rm = TRUE)
yscale = c(0, 1)
min_y = min(unlist(density_y))
max_y = max(unlist(density_y))
col_fun = colorRamp2(seq(min_y, max_y,
length = length(heatmap_colors)), heatmap_colors)
}
axis_param = validate_axis_param(axis_param, which)
axis_grob = if(axis) construct_axis_grob(axis_param, which, xscale) else NULL
|
ad35494a |
row_fun = function(index, k = 1, N = 1) {
|
402ff791 |
n = length(index)
value = value[index]
gp = subset_gp(gp, index)
density_x = density_x[index]
density_y = density_y[index]
for(i in seq_len(n)) {
pushViewport(viewport(x = unit(0, "npc"), y = unit((n-i)/n, "npc"),
just = c("left", "bottom"), height = unit(1/n, "npc"), xscale = xscale,
yscale = yscale))
if(type == "lines") {
grid.polygon(x = density_x[[i]], y = density_y[[i]]*joyplot_scale,
default.units = "native", gp = subset_gp(gp, i))
} else if(type == "violin") {
grid.polygon(x = c(density_x[[i]], rev(density_x[[i]])),
y = c(density_y[[i]], -rev(density_y[[i]])), default.units = "native",
gp = subset_gp(gp, i))
box_stat = boxplot(value[[i]], plot = FALSE)$stat
grid.lines(box_stat[1:2, 1], c(0, 0), default.units = "native",
gp = subset_gp(gp, i))
grid.lines(box_stat[4:5, 1], c(0, 0), default.units = "native",
gp = subset_gp(gp, i))
grid.points(box_stat[3, 1], 0, default.units = "native", pch = 3,
size = unit(1, "mm"), gp = subset_gp(gp, i))
} else if(type == "heatmap") {
n_breaks = length(density_x[[i]])
grid.rect(x = density_x[[i]][-1], y = 0,
width = density_x[[i]][-1] - density_x[[i]][-n_breaks], height = 1,
just = c("right", "bottom"), default.units = "native",
gp = gpar(fill = col_fun((density_y[[i]][-1] + density_y[[i]][-n_breaks])/2),
col = NA))
grid.rect(x = density_x[[i]][1], y = 0, width = density_x[[i]][1] - min_density_x,
height = 1, just = c("right", "bottom"), default.units = "native",
gp = gpar(fill = col_fun(0), col = NA))
grid.rect(x = density_x[[i]][n_breaks], y = 0,
width = max_density_x - density_x[[i]][n_breaks], height = 1,
just = c("left", "bottom"), default.units = "native",
gp = gpar(fill = col_fun(0), col = NA))
}
popViewport()
}
pushViewport(viewport(xscale = xscale))
|
ad35494a |
if(axis_param$side == "top") {
if(k > 1) axis = FALSE
} else if(axis_param$side == "bottom") {
if(k < N) axis = FALSE
}
|
402ff791 |
if(axis) grid.draw(axis_grob)
if(border) grid.rect(gp = gpar(fill = "transparent"))
popViewport()
}
|
ad35494a |
column_fun = function(index, k = 1, N = 1) {
|
402ff791 |
n_all = length(value)
value = value[index]
foo = yscale
yscale = xscale
xscale = foo
density_x = density_x[index]
density_y = density_y[index]
yscale = range(unlist(density_x), na.rm = TRUE)
yscale = yscale + c(0, 0.05)*(yscale[2] - yscale[1])
if(type == "lines") {
xscale = c(0, max(unlist(density_y)))
xscale[2] = xscale[2]*1.05
} else if(type == "violin") {
xscale = max(unlist(density_y))
xscale = c(-xscale*1.05, xscale*1.05)
} else if(type == "heatmap") {
yscale = range(unlist(density_x), na.rm = TRUE)
xscale = c(0, 1)
min_y = min(unlist(density_y))
max_y = max(unlist(density_y))
col_fun = colorRamp2(seq(min_y, max_y,
length = length(heatmap_colors)), heatmap_colors)
}
n = length(index)
gp = subset_gp(gp, index)
for(i in rev(seq_len(n))) {
pushViewport(viewport(y = unit(0, "npc"), x = unit(i/n, "npc"), width = unit(1/n, "npc"),
just = c("right", "bottom"), xscale = xscale, yscale = yscale))
if(type == "lines") {
grid.polygon(y = density_x[[i]], x = density_y[[i]]*joyplot_scale,
default.units = "native", gp = subset_gp(gp, index[i]))
} else if(type == "violin") {
grid.polygon(y = c(density_x[[i]], rev(density_x[[i]])),
x = c(density_y[[i]], -rev(density_y[[i]])), default.units = "native",
gp = subset_gp(gp, index[i]))
box_stat = boxplot(value[[i]], plot = FALSE)$stat
grid.lines(y = box_stat[1:2, 1], x = c(0, 0), default.units = "native",
gp = subset_gp(gp, i))
grid.lines(y = box_stat[4:5, 1], x = c(0, 0), default.units = "native",
gp = subset_gp(gp, i))
grid.points(y = box_stat[3, 1], x = 0, default.units = "native", pch = 3,
size = unit(1, "mm"), gp = subset_gp(gp, i))
} else if(type == "heatmap") {
n_breaks = length(density_x[[i]])
grid.rect(y = density_x[[i]][-1], x = 0,
height = density_x[[i]][-1] - density_x[[i]][-n_breaks], width = 1,
just = c("left", "top"), default.units = "native",
gp = gpar(fill = col_fun((density_y[[i]][-1] + density_y[[i]][-n_breaks])/2),
col = NA))
grid.rect(y = density_x[[i]][1], x = 0, height = density_x[[i]][1] - min_density_x,
width = 1, just = c("left", "top"), default.units = "native",
gp = gpar(fill = col_fun(0), col = NA))
grid.rect(y = density_x[[i]][n_breaks], x = 0,
height = max_density_x - density_x[[i]][n_breaks], width = 1,
just = c("left", "bottom"), default.units = "native",
gp = gpar(fill = col_fun(0), col = NA))
}
popViewport()
}
pushViewport(viewport(yscale = yscale))
|
ad35494a |
if(axis_param$side == "left") {
if(k > 1) axis = FALSE
} else if(axis_param$side == "right") {
if(k < N) axis = FALSE
}
|
402ff791 |
if(axis) grid.draw(axis_grob)
if(border) grid.rect(gp = gpar(fill = "transparent"))
popViewport()
}
if(which == "row") {
fun = row_fun
} else if(which == "column") {
fun = column_fun
}
anno = AnnotationFunction(
fun = fun,
fun_name = "anno_density",
which = which,
width = anno_size$width,
height = anno_size$height,
n = n,
data_scale = xscale,
var_import = list(value, gp, border, type, axis, axis_param, axis_grob, xscale, yscale, density_x,
|
ad35494a |
density_y, min_density_x, max_density_x, joyplot_scale, heatmap_colors)
|
402ff791 |
)
if(type == "heatmap") {
anno@var_env$col_fun = col_fun
}
anno@subset_rule$value = subset_vector
anno@subset_rule$gp = subset_gp
anno@subset_rule$density_x = subset_vector
anno@subset_rule$density_y = subset_vector
anno@subsetable = TRUE
anno@extended = update_anno_extend(anno, axis_grob, axis_param)
return(anno)
}
# == title
|
10fbf31c |
# Text Annotation
|
402ff791 |
#
# == param
|
10fbf31c |
# -x A vector of text.
# -which Whether it is a column annotation or a row annotation?
# -gp Graphic parameters.
# -rot Rotation of the text, pass to `grid::grid.text`.
# -just Justification of text, pass to `grid::grid.text`.
# -offset Depracated, use ``location`` instead.
# -location Position of the text. By default ``rot``, ``just`` and ``location`` are automatically
# inferred according to whether it is a row annotation or column annotation. The value
# of ``location`` should be a `grid::unit` object, normally in ``npc`` unit. E.g. ``unit(0, 'npc')``
# means the most left of the annotation region and ``unit(1, 'npc')`` means the most right of
# the annotation region.
|
1a56796e |
# -width Width of the annotation. The value should be an absolute unit. Width is not allowed to be set for column annotation.
# -height Height of the annotation. The value should be an absolute unit. Height is not allowed to be set for row annotation.
|
402ff791 |
#
# == value
|
10fbf31c |
# An annotation function which can be used in `HeatmapAnnotation`.
#
# == example
# anno = anno_text(month.name)
# draw(anno, test = "month names")
# anno = anno_text(month.name, gp = gpar(fontsize = 16))
# draw(anno, test = "month names with fontsize")
# anno = anno_text(month.name, gp = gpar(fontsize = 1:12+4))
# draw(anno, test = "month names with changing fontsize")
# anno = anno_text(month.name, which = "row")
# draw(anno, test = "month names on rows")
# anno = anno_text(month.name, location = 0, rot = 45,
# just = "left", gp = gpar(col = 1:12))
# draw(anno, test = "with rotations")
# anno = anno_text(month.name, location = 1,
# rot = 45, just = "right", gp = gpar(fontsize = 1:12+4))
# draw(anno, test = "with rotations")
|
402ff791 |
anno_text = function(x, which = c("column", "row"), gp = gpar(),
rot = guess_rot(), just = guess_just(),
offset = guess_location(), location = guess_location(),
width = NULL, height = NULL) {
|
ad35494a |
if(is.null(.ENV$current_annotation_which)) {
|
402ff791 |
which = match.arg(which)[1]
|
ad35494a |
} else {
which = .ENV$current_annotation_which
|
402ff791 |
}
n = length(x)
gp = recycle_gp(gp, n)
guess_rot = function() {
ifelse(which == "column", 90, 0)
}
guess_just = function() {
ifelse(which == "column", "right", "left")
}
guess_location = function() {
unit(ifelse(which == "column", 1, 0), "npc")
}
rot = rot[1] %% 360
just = just[1]
if(!missing(offset)) {
warning("`offset` is deprecated, use `location` instead.")
if(missing(location)) {
location = offset
}
}
location = location[1]
if(!inherits(location, "unit")) {
location = unit(location, "npc")
}
if(which == "column") {
if("right" %in% just) {
if(rot < 180) {
location = location - 0.5*grobHeight(textGrob("A", gp = gp))*abs(cos(rot/180*pi))
} else {
location = location + 0.5*grobHeight(textGrob("A", gp = gp))*abs(cos(rot/180*pi))
}
} else if("left" %in% just) {
if(rot < 180) {
location = location + 0.5*grobHeight(textGrob("A", gp = gp))*abs(cos(rot/180*pi))
} else {
location = location - 0.5*grobHeight(textGrob("A", gp = gp))*abs(cos(rot/180*pi))
}
}
}
if(which == "column") {
if(missing(height)) {
height = max_text_width(x, gp = gp)*abs(sin(rot/180*pi)) + grobHeight(textGrob("A", gp = gp))*abs(cos(rot/180*pi))
height = convertHeight(height, "mm")
}
if(missing(width)) {
width = unit(1, "npc")
}
}
if(which == "row") {
if(missing(width)) {
width = max_text_width(x, gp = gp)*abs(cos(rot/180*pi)) + grobHeight(textGrob("A", gp = gp))*abs(sin(rot/180*pi))
width = convertWidth(width, "mm")
}
if(missing(height)) {
height = unit(1, "npc")
}
}
anno_size = list(width = width, height = height)
value = x
row_fun = function(index) {
n = length(index)
grid.text(value[index], location, (n - seq_along(index) + 0.5)/n, gp = subset_gp(gp, index), just = just, rot = rot)
}
column_fun = function(index, k = NULL, N = NULL, vp_name = NULL) {
n = length(index)
grid.text(value[index], (seq_along(index) - 0.5)/n, location, gp = subset_gp(gp, index), just = just, rot = rot)
}
if(which == "row") {
fun = row_fun
} else if(which == "column") {
fun = column_fun
}
anno = AnnotationFunction(
fun = fun,
fun_name = "anno_text",
which = which,
width = width,
height = height,
n = n,
|
933e808c |
var_import = list(value, gp, just, rot, location),
show_name = FALSE
|
402ff791 |
)
anno@subset_rule$value = subset_vector
anno@subset_rule$gp = subset_gp
anno@subsetable = TRUE
return(anno)
}
|
10fbf31c |
# == title
# Joyplot Annotation
#
# == param
# -x A matrix or a list. If ``x`` is a matrix or a data frame, columns correspond to observations.
# -which Whether it is a column annotation or a row annotation?
# -gp Graphic parameters for the boxes. The length of the graphic parameters should be one or the number of observations.
# -scale Relative height of the curve. A value higher than 1 increases the height of the curve.
# -transparency Transparency of the filled colors. Value should be between 0 and 1.
# -axis Whether to add axis?
# -axis_param parameters for controlling axis. See `default_axis_param` for all possible settings and default parameters.
|
1a56796e |
# -width Width of the annotation. The value should be an absolute unit. Width is not allowed to be set for column annotation.
# -height Height of the annotation. The value should be an absolute unit. Height is not allowed to be set for row annotation.
|
10fbf31c |
#
# == value
# An annotation function which can be used in `HeatmapAnnotation`.
#
# == example
# m = matrix(rnorm(1000), nc = 10)
# lt = apply(m, 2, function(x) data.frame(density(x)[c("x", "y")]))
# anno = anno_joyplot(lt, width = unit(4, "cm"), which = "row")
# draw(anno, test = "joyplot")
# anno = anno_joyplot(lt, width = unit(4, "cm"), which = "row", gp = gpar(fill = 1:10))
# draw(anno, test = "joyplot + col")
# anno = anno_joyplot(lt, width = unit(4, "cm"), which = "row", scale = 1)
# draw(anno, test = "joyplot + scale")
#
# m = matrix(rnorm(5000), nc = 50)
# lt = apply(m, 2, function(x) data.frame(density(x)[c("x", "y")]))
# anno = anno_joyplot(lt, width = unit(4, "cm"), which = "row", gp = gpar(fill = NA), scale = 4)
# draw(anno, test = "joyplot")
|
402ff791 |
anno_joyplot = function(x, which = c("column", "row"), gp = gpar(fill = "#000000"),
scale = 2, transparency = 0.6,
axis = TRUE, axis_param = default_axis_param(which),
width = NULL, height = NULL) {
if(is.null(.ENV$current_annotation_which)) {
which = match.arg(which)[1]
} else {
which = .ENV$current_annotation_which
}
anno_size = anno_width_and_height(which, width, height, unit(4, "cm"))
## convert matrix all to list (or data frame)
if(is.matrix(x) || is.data.frame(x)) {
value = vector("list", ncol(x))
for(i in seq_len(ncol(x))) {
|
ad35494a |
value[[i]] = cbind(seq_len(nrow(x)), x[, i])
|
402ff791 |
}
} else if(inherits(x, "list")){
if(all(sapply(x, is.atomic))) {
if(length(unique(sapply(x, length))) == 1) {
value = vector("list", length(x))
for(i in seq_len(length(x))) {
value[[i]] = cbind(seq_along(x[[i]]), x[[i]])
}
} else {
|
c4a66bf9 |
stop_wrap("Since x is a list, x need to be a list of two-column matrices.")
|
402ff791 |
}
} else {
value = x
}
} else {
|
c4a66bf9 |
stop_wrap("The input should be a list of two-column matrices or a matrix/data frame.")
|
402ff791 |
}
xscale = range(lapply(value, function(x) x[, 1]), na.rm = TRUE)
xscale = xscale + c(-0.05, 0.05)*(xscale[2] - xscale[1])
yscale = range(lapply(value, function(x) x[, 2]), na.rm = TRUE)
yscale[1] = 0
yscale[2] = yscale[2]*1.05
n = length(value)
if(!"fill" %in% names(gp)) {
gp$fill = "#000000"
}
gp = recycle_gp(gp, n)
gp$fill = add_transparency(gp$fill, transparency)
axis_param = validate_axis_param(axis_param, which)
axis_grob = if(axis) construct_axis_grob(axis_param, which, xscale) else NULL
|
ad35494a |
row_fun = function(index, k = 1, N = 1) {
|
402ff791 |
n_all = length(value)
value = value[index]
n = length(index)
gp = subset_gp(gp, index)
for(i in seq_len(n)) {
pushViewport(viewport(x = unit(0, "npc"), y = unit((n-i)/n, "npc"),
just = c("left", "bottom"), height = unit(1/n, "npc"), xscale = xscale,
yscale = yscale))
x0 = value[[i]][, 1]
y0 = value[[i]][, 2]*scale
x0 = c(x0[1], x0, x0[length(x0)])
y0 = c(0, y0, 0)
gppp = subset_gp(gp, i); gppp$col = NA
grid.polygon(x = x0, y = y0, default.units = "native", gp = gppp)
grid.lines(x = x0, y = y0, default.units = "native",
gp = subset_gp(gp, i))
popViewport()
}
pushViewport(viewport(xscale = xscale))
|
ad35494a |
if(axis_param$side == "top") {
if(k > 1) axis = FALSE
} else if(axis_param$side == "bottom") {
if(k < N) axis = FALSE
}
|
402ff791 |
if(axis) grid.draw(axis_grob)
popViewport()
}
|
ad35494a |
column_fun = function(index, k = 1, N = 1) {
|
402ff791 |
n_all = length(value)
value = value[index]
foo = yscale
yscale = xscale
xscale = foo
n = length(index)
gp = subset(gp, index)
for(i in seq_len(n)) {
pushViewport(viewport(y = unit(0, "npc"), x = unit(i/n, "npc"),
width = unit(1/n, "npc"), just = c("right", "bottom"), xscale = xscale,
yscale = yscale))
x0 = value[[i]][, 2]*scale
y0 = value[[i]][ ,1]
x0 = c(0, x0, 0)
y0 = c(y0[1], y0, y0[length(y0)])
gppp = subset_gp(gp, i); gppp$col = NA
grid.polygon(y = y0, x = x0, default.units = "native", gp = gppp)
grid.lines(y = y0, x = x0, default.units = "native",
gp = subset_gp(gp, i))
popViewport()
}
pushViewport(viewport(yscale = yscale))
|
ad35494a |
if(axis_param$side == "left") {
if(k > 1) axis = FALSE
} else if(axis_param$side == "right") {
if(k < N) axis = FALSE
}
|
402ff791 |
if(axis) grid.draw(axis_grob)
popViewport()
}
if(which == "row") {
fun = row_fun
} else if(which == "column") {
fun = column_fun
}
anno = AnnotationFunction(
fun = fun,
fun_name = "anno_joyplot",
which = which,
width = anno_size$width,
height = anno_size$height,
n = n,
data_scale = xscale,
var_import = list(value, gp, axis, axis_param, axis_grob, scale, yscale, xscale)
)
anno@subset_rule$value = subset_vector
anno@subset_rule$gp = subset_gp
anno@subsetable = TRUE
anno@extended = update_anno_extend(anno, axis_grob, axis_param)
return(anno)
}
|
10fbf31c |
# == title
# Horizon chart Annotation
#
# == param
# -x A matrix or a list. If ``x`` is a matrix or a data frame, columns correspond to observations.
# -which Whether it is a column annotation or a row annotation?
# -gp Graphic parameters for the boxes. The length of the graphic parameters should be one or the number of observations.
|
ad35494a |
# There are two unstandard parameters specificly for horizon chart: ``pos_fill`` and ``neg_fill`` controls the filled
|
10fbf31c |
# color for positive values and negative values.
# -n_slice Number of slices on y-axis.
# -slice_size Height of the slice. If the value is not ``NULL``, ``n_slice`` will be recalculated.
# -negative_from_top Whether the areas for negative values start from the top or the bottom of the plotting region?
|
7db3856b |
# -normalize Whether normalize ``x`` by max(abs(x)).
|
10fbf31c |
# -gap Gap size of neighbouring horizon chart.
# -axis Whether to add axis?
# -axis_param parameters for controlling axis. See `default_axis_param` for all possible settings and default parameters.
|
1a56796e |
# -width Width of the annotation. The value should be an absolute unit. Width is not allowed to be set for column annotation.
# -height Height of the annotation. The value should be an absolute unit. Height is not allowed to be set for row annotation.
|
10fbf31c |
#
# == detail
# Horizon chart as row annotation is only supported.
#
# == value
# An annotation function which can be used in `HeatmapAnnotation`.
#
|
ad35494a |
# == example
|
10fbf31c |
# lt = lapply(1:20, function(x) cumprod(1 + runif(1000, -x/100, x/100)) - 1)
# anno = anno_horizon(lt, which = "row")
# draw(anno, test = "horizon chart")
# anno = anno_horizon(lt, which = "row",
# gp = gpar(pos_fill = "orange", neg_fill = "darkgreen"))
# draw(anno, test = "horizon chart, col")
# anno = anno_horizon(lt, which = "row", negative_from_top = TRUE)
# draw(anno, test = "horizon chart + negative_from_top")
# anno = anno_horizon(lt, which = "row", gap = unit(1, "mm"))
# draw(anno, test = "horizon chart + gap")
# anno = anno_horizon(lt, which = "row",
# gp = gpar(pos_fill = rep(c("orange", "red"), each = 10),
# neg_fill = rep(c("darkgreen", "blue"), each = 10)))
# draw(anno, test = "horizon chart, col")
|
402ff791 |
anno_horizon = function(x, which = c("column", "row"),
gp = gpar(pos_fill = "#D73027", neg_fill = "#313695"),
n_slice = 4, slice_size = NULL, negative_from_top = FALSE,
|
10fbf31c |
normalize = TRUE, gap = unit(0, "mm"),
|
402ff791 |
axis = TRUE, axis_param = default_axis_param(which),
width = NULL, height = NULL) {
if(is.null(.ENV$current_annotation_which)) {
which = match.arg(which)[1]
} else {
which = .ENV$current_annotation_which
}
anno_size = anno_width_and_height(which, width, height, unit(4, "cm"))
## convert matrix all to list (or data frame)
if(is.matrix(x) || is.data.frame(x)) {
value = vector("list", ncol(x))
for(i in seq_len(ncol(x))) {
|
ad35494a |
value[[i]] = cbind(seq_len(nrow(x)), x[, i])
|
402ff791 |
}
} else if(inherits(x, "list")){
if(all(sapply(x, is.atomic))) {
if(length(unique(sapply(x, length))) == 1) {
value = vector("list", length(x))
for(i in seq_len(length(x))) {
value[[i]] = cbind(seq_along(x[[i]]), x[[i]])
}
} else {
|
c4a66bf9 |
stop_wrap("Since x is a list, x need to be a list of two-column matrices.")
|
402ff791 |
}
} else {
value = x
}
} else {
|
c4a66bf9 |
stop_wrap("The input should be a list of two-column matrices or a matrix/data frame.")
|
402ff791 |
}
if(is.null(gp$pos_fill)) gp$pos_fill = "#D73027"
if(is.null(gp$neg_fill)) gp$neg_fill = "#313695"
if("fill" %in% names(gp)) {
foo = unlist(lapply(value, function(x) x[, 2]))
if(all(foo >= 0)) {
gp$pos_fill = gp$fill
} else if(all(foo <= 0)) {
gp$neg_fill = gp$fill
} else {
gp = gpar(pos_fill = "#D73027", neg_fill = "#313695")
}
}
if(which == "column") {
|
c4a66bf9 |
stop_wrap("anno_horizon() does not support column annotation. If you want, please email me.")
|
402ff791 |
}
if(normalize) {
value = lapply(value, function(m) {
m[, 2] = m[, 2]/max(abs(m[, 2]))
m
})
}
n = length(value)
xscale = range(lapply(value, function(x) x[, 1]), na.rm = TRUE)
yscale = range(lapply(value, function(x) abs(x[, 2])), na.rm = TRUE)
axis_param = validate_axis_param(axis_param, which)
axis_grob = if(axis) construct_axis_grob(axis_param, which, xscale) else NULL
|
ad35494a |
row_fun = function(index, k = 1, N = 1) {
|
402ff791 |
n_all = length(value)
value = value[index]
if(is.null(slice_size)) {
slice_size = yscale[2]/n_slice
}
n_slice = ceiling(yscale[2]/slice_size)
n = length(index)
gp = subset_gp(gp, index)
for(i in seq_len(n)) {
pushViewport(viewport(x = unit(0, "npc"), y = unit((n-i)/n, "npc"), just = c("left", "bottom"),
height = unit(1/n, "npc") - gap))
sgp = subset_gp(gp, i)
horizon_chart(value[[i]][, 1], value[[i]][, 2], n_slice = n_slice, slice_size = slice_size,
negative_from_top = negative_from_top, pos_fill = sgp$pos_fill, neg_fill = sgp$neg_fill)
grid.rect(gp = gpar(fill = "transparent"))
popViewport()
}
pushViewport(viewport(xscale = xscale))
|
ad35494a |
if(axis_param$side == "top") {
if(k > 1) axis = FALSE
} else if(axis_param$side == "bottom") {
if(k < N) axis = FALSE
}
|
402ff791 |
if(axis) grid.draw(axis_grob)
popViewport()
}
column_fun = function(index) {
}
if(which == "row") {
fun = row_fun
} else if(which == "column") {
fun = column_fun
}
anno = AnnotationFunction(
fun = fun,
fun_name = "anno_horizon",
which = which,
width = anno_size$width,
height = anno_size$height,
n = n,
data_scale = xscale,
|
10fbf31c |
var_import = list(value, gp, axis, axis_param, axis_grob, n_slice, slice_size,
|
402ff791 |
negative_from_top, xscale, yscale, gap)
)
anno@subset_rule$value = subset_vector
anno@subset_rule$gp = subset_gp
anno@subsetable = TRUE
anno@extended = update_anno_extend(anno, axis_grob, axis_param)
return(anno)
}
horizon_chart = function(x, y, n_slice = 4, slice_size, pos_fill = "#D73027", neg_fill = "#313695",
negative_from_top = FALSE) {
if(missing(slice_size)) {
slice_size = max(abs(y))/n_slice
}
n_slice = ceiling(max(abs(y))/slice_size)
if(n_slice == 0) {
return(invisible(NULL))
}
pos_col_fun = colorRamp2(c(0, n_slice), c("white", pos_fill))
neg_col_fun = colorRamp2(c(0, n_slice), c("white", neg_fill))
pushViewport(viewport(xscale = range(x), yscale = c(0, slice_size)))
for(i in seq_len(n_slice)) {
l1 = y >= (i-1)*slice_size & y < i*slice_size
l2 = y < (i-1)*slice_size
l3 = y >= i*slice_size
if(any(l1)) {
x2 = x
y2 = y
y2[l1] = y2[l1] - slice_size*(i-1)
y2[l3] = slice_size
x2[l2] = NA
y2[l2] = NA
add_horizon_polygon(x2, y2, gp = gpar(fill = pos_col_fun(i), col = NA),
default.units = "native")
}
}
y = -y
for(i in seq_len(n_slice)) {
l1 = y >= (i-1)*slice_size & y < i*slice_size
l2 = y < (i-1)*slice_size
l3 = y >= i*slice_size
if(any(l1)) {
x2 = x
y2 = y
y2[l1] = y2[l1] - slice_size*(i-1)
y2[l3] = slice_size
x2[l2] = NA
y2[l2] = NA
add_horizon_polygon(x2, y2, slice_size = slice_size, from_top = negative_from_top,
gp = gpar(fill = neg_col_fun(i), col = NA), default.units = "native")
}
}
popViewport()
}
# x and y may contain NA, split x and y by NA gaps, align the bottom to y = 0
add_horizon_polygon = function(x, y, slice_size = NULL, from_top = FALSE, ...) {
ltx = split_vec_by_NA(x)
lty = split_vec_by_NA(y)
for(i in seq_along(ltx)) {
x0 = ltx[[i]]
y0 = lty[[i]]
if(from_top) {
x0 = c(x0[1], x0, x0[length(x0)])
y0 = c(slice_size, slice_size - y0, slice_size)
} else {
x0 = c(x0[1], x0, x0[length(x0)])
y0 = c(0, y0, 0)
}
grid.polygon(x0, y0, ...)
}
}
# https://stat.ethz.ch/pipermail/r-help/2010-April/237031.html
split_vec_by_NA = function(x) {
idx = 1 + cumsum(is.na(x))
not.na = !is.na(x)
split(x[not.na], idx[not.na])
}
# == title
|
10fbf31c |
# Points as Row Annotation
|
402ff791 |
#
# == param
# -... pass to `anno_points`
#
# == details
# A wrapper of `anno_points` with pre-defined ``which`` to ``row``.
#
|
10fbf31c |
# You can directly use `anno_points` for row annotation if you call it in `rowAnnotation`.
#
|
402ff791 |
# == value
# See help page of `anno_points`
#
row_anno_points = function(...) {
if(exists(".__under_SingleAnnotation__", envir = parent.frame())) {
|
c4a66bf9 |
message_wrap("From this version of ComplexHeatmap, you can directly use `anno_points()` for row annotation if you call it in `rowAnnotation()`.")
|
402ff791 |
}
anno_points(..., which = "row")
}
# == title
|
10fbf31c |
# Barplots as Row Annotation
|
402ff791 |
#
# == param
# -... pass to `anno_barplot`
#
# == details
# A wrapper of `anno_barplot` with pre-defined ``which`` to ``row``.
#
|
10fbf31c |
# You can directly use `anno_barplot` for row annotation if you call it in `rowAnnotation`.
#
|
402ff791 |
# == value
# See help page of `anno_barplot`
#
row_anno_barplot = function(...) {
|
ad35494a |
if(exists(".__under_SingleAnnotation__", envir = parent.frame())) {
|
c4a66bf9 |
message_wrap("From this version of ComplexHeatmap, you can directly use `anno_barplot()` for row annotation if you call it in `rowAnnotation()`.")
|
ad35494a |
}
|
402ff791 |
anno_barplot(..., which = "row")
}
# == title
|
10fbf31c |
# Boxplots as Row Annotation
|
402ff791 |
#
# == param
# -... pass to `anno_boxplot`
#
# == details
# A wrapper of `anno_boxplot` with pre-defined ``which`` to ``row``.
#
|
10fbf31c |
# You can directly use `anno_boxplot` for row annotation if you call it in `rowAnnotation`.
#
|
402ff791 |
# == value
# See help page of `anno_boxplot`
#
row_anno_boxplot = function(...) {
|
ad35494a |
if(exists(".__under_SingleAnnotation__", envir = parent.frame())) {
|
c4a66bf9 |
message_wrap("From this version of ComplexHeatmap, you can directly use `anno_boxplot()` for row annotation if you call it in `rowAnnotation()`.")
|
ad35494a |
}
|
402ff791 |
anno_boxplot(..., which = "row")
}
# == title
|
10fbf31c |
# Histograms as Row Annotation
|
402ff791 |
#
# == param
# -... pass to `anno_histogram`
#
# == details
# A wrapper of `anno_histogram` with pre-defined ``which`` to ``row``.
#
|
10fbf31c |
# You can directly use `anno_histogram` for row annotation if you call it in `rowAnnotation`.
#
|
402ff791 |
# == value
# See help page of `anno_histogram`
#
row_anno_histogram = function(...) {
|
ad35494a |
if(exists(".__under_SingleAnnotation__", envir = parent.frame())) {
|
c4a66bf9 |
message_wrap("From this version of ComplexHeatmap, you can directly use `anno_histogram()` for row annotation if you call it in `rowAnnotation()`.")
|
ad35494a |
}
|
402ff791 |
anno_histogram(..., which = "row")
}
# == title
|
10fbf31c |
# Density as Row Annotation
|
402ff791 |
#
# == param
# -... pass to `anno_density`
#
# == details
# A wrapper of `anno_density` with pre-defined ``which`` to ``row``.
#
|
10fbf31c |
# You can directly use `anno_density` for row annotation if you call it in `rowAnnotation`.
#
|
402ff791 |
# == value
# See help page of `anno_density`
#
row_anno_density = function(...) {
|
ad35494a |
if(exists(".__under_SingleAnnotation__", envir = parent.frame())) {
|
c4a66bf9 |
message_wrap("From this version of ComplexHeatmap, you can directly use `anno_density()` for row annotation if you call it in `rowAnnotation()`.")
|
ad35494a |
}
|
402ff791 |
anno_density(..., which = "row")
}
# == title
|
10fbf31c |
# Text as Row Annotation
|
402ff791 |
#
# == param
# -... pass to `anno_text`
#
# == details
# A wrapper of `anno_text` with pre-defined ``which`` to ``row``.
#
|
10fbf31c |
# You can directly use `anno_text` for row annotation if you call it in `rowAnnotation`.
#
|
402ff791 |
# == value
# See help page of `anno_text`
#
row_anno_text = function(...) {
|
ad35494a |
if(exists(".__under_SingleAnnotation__", envir = parent.frame())) {
|
c4a66bf9 |
message_wrap("From this version of ComplexHeatmap, you can directly use `anno_text()` for row annotation if you call it in `rowAnnotation()`.")
|
ad35494a |
}
|
402ff791 |
anno_text(..., which = "row")
}
# == title
# Link annotation with labels
#
# == param
|
10fbf31c |
# -at Numeric index from the original matrix.
# -labels Corresponding labels.
# -which Whether it is a column annotation or a row annotation?
# -side Side of the labels. If it is a column annotation, valid values are "top" and "bottom";
# If it is a row annotation, valid values are "left" and "right".
# -lines_gp Please use ``link_gp`` instead.
# -link_gp Graphic settings for the segments.
# -labels_gp Graphic settings for the labels.
# -padding Padding between neighbouring labels in the plot.
# -link_width Width of the segments.
# -extend By default, the region for the labels has the same width (if it is a column annotation) or
|
402ff791 |
# same height (if it is a row annotation) as the heatmap. The size can be extended by this options.
# The value can be a proportion number or a `grid::unit` object. The length can be either one or two.
#
# == details
# Sometimes there are many rows or columns in the heatmap and we want to mark some of the rows.
# This annotation function is used to mark these rows and connect labels and corresponding rows
# with links.
#
# == value
|
10fbf31c |
# An annotation function which can be used in `HeatmapAnnotation`.
#
# == example
# anno = anno_mark(at = c(1:4, 20, 60, 97:100), labels = month.name[1:10], which = "row")
# draw(anno, index = 1:100, test = "anno_mark")
#
# m = matrix(1:1000, byrow = TRUE, nr = 100)
# anno = anno_mark(at = c(1:4, 20, 60, 97:100), labels = month.name[1:10], which = "row")
|
ad35494a |
# Heatmap(m, cluster_rows = FALSE, cluster_columns = FALSE) + rowAnnotation(mark = anno)
|
10fbf31c |
# Heatmap(m) + rowAnnotation(mark = anno)
anno_mark = function(at, labels, which = c("column", "row"),
side = ifelse(which == "column", "top", "right"),
lines_gp = gpar(), labels_gp = gpar(), padding = 0.5,
link_width = unit(5, "mm"), link_gp = lines_gp,
extend = unit(0, "mm")) {
|
402ff791 |
if(is.null(.ENV$current_annotation_which)) {
which = match.arg(which)[1]
} else {
which = .ENV$current_annotation_which
}
if(!is.numeric(at)) {
|
c4a66bf9 |
stop_wrap(paste0("`at` should be numeric ", which, " index corresponding to the matrix."))
|
402ff791 |
}
n = length(at)
link_gp = recycle_gp(link_gp, n)
labels_gp = recycle_gp(labels_gp, n)
labels2index = structure(seq_along(at), names = labels)
at2labels = structure(labels, names = at)
if(length(extend) == 1) extend = rep(extend, 2)
if(length(extend) > 2) extend = extend[1:2]
if(!inherits(extend, "unit")) extend = unit(extend, "npc")
if(which == "row") {
height = unit(1, "npc")
width = link_width + max_text_width(labels, gp = labels_gp)
} else {
height = link_width + max_text_width(labels, gp = labels_gp)
width = unit(1, "npc")
}
|
933e808c |
# a map between row index and positions
# pos_map =
|
402ff791 |
row_fun = function(index) {
n = length(index)
# adjust at and labels
at = intersect(index, at)
if(length(at) == 0) {
return(NULL)
}
labels = rev(at2labels[as.character(at)])
labels_gp = subset_gp(labels_gp, labels2index[labels])
link_gp = subset_gp(link_gp, labels2index[labels])
pushViewport(viewport(xscale = c(0, 1), yscale = c(0.5, n+0.5)))
# go to the parent viewport
text_height = convertHeight(grobHeight(textGrob(labels, gp = labels_gp))*(1+padding), "native", valueOnly = TRUE)
i2 = rev(which(index %in% at))
h1 = n-i2+1 - text_height*0.5
h2 = n-i2+1 + text_height*0.5
pos = rev(smartAlign(h1, h2, c(0.5, n+0.5)))
h = (pos[, 1] + pos[, 2])/2
n2 = length(labels)
if(side == "right") {
grid.text(labels, rep(link_width, n2), h, default.units = "native", gp = labels_gp, just = "left")
link_width = link_width - unit(1, "mm")
grid.segments(unit(rep(0, n2), "npc"), n-i2+1, rep(link_width*(1/3), n2), n-i2+1, default.units = "native", gp = link_gp)
grid.segments(rep(link_width*(1/3), n2), n-i2+1, rep(link_width*(2/3), n2), h, default.units = "native", gp = link_gp)
grid.segments(rep(link_width*(2/3), n2), h, rep(link_width, n2), h, default.units = "native", gp = link_gp)
} else {
grid.text(labels, unit(1, "npc")-rep(link_width, n2), h, default.units = "native", gp = labels_gp, just = "right")
link_width = link_width - unit(1, "mm")
grid.segments(unit(rep(1, n2), "npc"), n-i2+1, unit(1, "npc")-rep(link_width*(1/3), n2), n-i2+1, default.units = "native", gp = link_gp)
grid.segments(unit(1, "npc")-rep(link_width*(1/3), n2), n-i2+1, unit(1, "npc")-rep(link_width*(2/3), n2), h, default.units = "native", gp = link_gp)
grid.segments(unit(1, "npc")-rep(link_width*(2/3), n2), h, unit(1, "npc")-rep(link_width, n2), h, default.units = "native", gp = link_gp)
}
upViewport()
}
column_fun = function(index) {
n = length(index)
# adjust at and labels
at = intersect(index, at)
labels = at2labels[as.character(at)]
labels_gp = subset_gp(labels_gp, labels2index[labels])
lines_gp = subset_gp(lines_gp, labels2index[labels])
pushViewport(viewport(yscale = c(0, 1), xscale = c(0.5, n+0.5)))
if(inherits(extend, "unit")) extend = convertWidth(extend, "native", valueOnly = TRUE)
text_height = convertWidth(grobHeight(textGrob(labels, gp = labels_gp))*(1+padding), "native", valueOnly = TRUE)
i2 = which(index %in% at)
h1 = i2 - text_height*0.5
h2 = i2 + text_height*0.5
pos = smartAlign(h1, h2, c(0.5 - extend[1], n+0.5 + extend[2]))
h = (pos[, 1] + pos[, 2])/2
if(is.null(link_width)) {
if(convertHeight(unit(1, "npc") - max_text_width(labels, gp = labels_gp), "mm", valueOnly = TRUE) < 0) {
link_width = unit(0.5, "npc")
} else {
link_width = unit(1, "npc") - max_text_width(labels, gp = labels_gp)
}
}
n2 = length(labels)
if(side == "top") {
grid.text(labels, h, rep(link_width, n2), default.units = "native", gp = labels_gp, rot = 90, just = "left")
link_width = link_width - unit(1, "mm")
grid.segments(i2, unit(rep(0, n2), "npc"), i2, rep(link_width*(1/3), n2), default.units = "native", gp = link_gp)
grid.segments(i2, rep(link_width*(1/3), n2), h, rep(link_width*(2/3), n2), default.units = "native", gp = link_gp)
grid.segments(h, rep(link_width*(2/3), n2), h, rep(link_width, n), default.units = "native", gp = link_gp)
} else {
grid.text(labels, h, rep(max_text_width(labels, gp = labels_gp), n2), default.units = "native", gp = labels_gp, rot = 90, just = "right")
link_width = link_width - unit(1, "mm")
grid.segments(i2, unit(rep(1, n2), "npc"), i2, unit(1, "npc")-rep(link_width*(1/3), n2), default.units = "native", gp = link_gp)
grid.segments(i2, unit(1, "npc")-rep(link_width*(1/3), n2), h, unit(1, "npc")-rep(link_width*(2/3), n2), default.units = "native", gp = link_gp)
grid.segments(h, unit(1, "npc")-rep(link_width*(2/3), n2), h, unit(1, "npc")-rep(link_width, n2), default.units = "native", gp = link_gp)
}
upViewport()
}
if(which == "row") {
fun = row_fun
} else if(which == "column") {
fun = column_fun
}
anno = AnnotationFunction(
fun = fun,
fun_name = "anno_mark",
which = which,
width = width,
height = height,
n = -1,
|
933e808c |
var_import = list(at, labels2index, at2labels, link_gp, labels_gp, padding,
side, link_width, extend),
show_name = FALSE
|
402ff791 |
)
anno@subset_rule$at = subset_by_intersect
anno@subsetable = TRUE
return(anno)
}
subset_by_intersect = function(x, i) {
intersect(x, i)
}
# == title
|
10fbf31c |
# Label Markers Annotation
|
402ff791 |
#
# == param
|
10fbf31c |
# -... Pass to `anno_mark`.
|
402ff791 |
#
# == details
|
10fbf31c |
# `anno_link` is deprecated, please use `anno_mark` instead.
|
402ff791 |
#
|
10fbf31c |
anno_link = function(...) {
|
c4a66bf9 |
warning_wrap("anno_link() is deprecated, please use anno_mark() instead.")
|
10fbf31c |
anno_mark(...)
|
402ff791 |
}
|
10fbf31c |
|
402ff791 |
# == title
|
10fbf31c |
# Label Markers as Row Annotation
|
402ff791 |
#
# == param
# -... pass to `anno_link`
#
# == details
|
10fbf31c |
# A wrapper of `anno_link` with pre-defined ``which`` to ``row``.
#
# You can directly use `anno_link` for row annotation if you call it in `rowAnnotation`.
|
402ff791 |
#
# == value
# See help page of `anno_link`
#
|
10fbf31c |
row_anno_link = function(...) {
|
ad35494a |
if(exists(".__under_SingleAnnotation__", envir = parent.frame())) {
|
c4a66bf9 |
message_wrap("From this version of ComplexHeatmap, you can directly use `anno_mark()` for row annotation if you call it in `rowAnnotation()`.")
|
ad35494a |
}
|
10fbf31c |
anno_link(..., which = "row")
|
402ff791 |
}
|
1a56796e |
# == title
# Summary Annotation
#
# == param
# -which Whether it is a column annotation or a row annotation?
# -border Wether draw borders of the annotation region?
# -bar_width Relative width of the bars. The value should be smaller than one.
# -axis Whether to add axis?
# -axis_param parameters for controlling axis. See `default_axis_param` for all possible settings and default parameters.
# -ylim Data ranges. ``ylim`` for barplot is enforced to be ``c(0, 1)``.
# -extend The extension to both side of ``ylim``. The value is a percent value corresponding to ``ylim[2] - ylim[1]``. This argument is only for boxplot.
# -outline Whether draw outline of boxplots?
# -box_width Relative width of boxes. The value should be smaller than one.
# -pch Point style.
# -size Point size.
# -gp Graphic parameters.
# -width Width of the annotation. The value should be an absolute unit. Width is not allowed to be set for column annotation.
# -height Height of the annotation. The value should be an absolute unit. Height is not allowed to be set for row annotation.
#
# == detail
# ``anno_summary`` is a special annotation function that it only works for one-column or one-row heatmap.
# It shows the summary of the values in the heatmap. If the values in the heatmap is discrete,
# the proportion of each level (the sum is normalized to 1) is visualized as stacked barplot. If the heatmap
# is split into multiple slices, multiple bars are put in the annotation. If the value is continuous, boxplot is used.
#
# In the barplot, the color schema is used as the same as the heatmap, while for the boxplot, the color needs
# to be controlled by ``gp``.
#
# == example
# ha = HeatmapAnnotation(summary = anno_summary(height = unit(4, "cm")))
# v = sample(letters[1:2], 50, replace = TRUE)
# split = sample(letters[1:2], 50, replace = TRUE)
# Heatmap(v, top_annotation = ha, width = unit(1, "cm"), split = split)
#
# ha = HeatmapAnnotation(summary = anno_summary(gp = gpar(fill = 2:3), height = unit(4, "cm")))
# v = rnorm(50)
# Heatmap(v, top_annotation = ha, width = unit(1, "cm"), split = split)
#
|
cc35650a |
anno_summary = function(which = c("column", "row"), border = TRUE, bar_width = 0.8,
|
a93897a0 |
axis = TRUE, axis_param = default_axis_param(which),
ylim = NULL, extend = 0.05, outline = TRUE, box_width = 0.6,
pch = 1, size = unit(2, "mm"), gp = gpar(),
|
1a56796e |
width = NULL, height = NULL) {
|
249fdfa0 |
if(is.null(.ENV$current_annotation_which)) {
which = match.arg(which)[1]
} else {
which = .ENV$current_annotation_which
}
anno_size = anno_width_and_height(which, width, height, unit(2, "cm"))
|
cc35650a |
axis_param = validate_axis_param(axis_param, which)
|
a93897a0 |
if(is.null(ylim)) {
axis_grob = if(axis) construct_axis_grob(axis_param, which, c(0, 1)) else NULL
} else {
axis_grob = if(axis) construct_axis_grob(axis_param, which, ylim) else NULL
}
|
cc35650a |
|
bb20f132 |
row_fun = function(index) {
|
cc35650a |
ht = get("object", envir = parent.frame(7))
mat = ht@matrix
cm = ht@matrix_color_mapping
order_list = ht@column_order_list
ng = length(order_list)
|
bb20f132 |
|
cc35650a |
if(cm@type == "discrete") {
tl = lapply(order_list, function(od) table(mat[1, od]))
tl = lapply(tl, function(x) x/sum(x))
pushViewport(viewport(yscale = c(0.5, ng+0.5), xscale = c(0, 1)))
for(i in 1:ng) {
x = i
y = cumsum(tl[[i]])
grid.rect(y, x, height = bar_width, width = tl[[i]], just = "right", gp = gpar(fill = map_to_colors(cm, names(y))), default.units = "native")
}
if(axis) grid.draw(axis_grob)
if(border) grid.rect(gp = gpar(fill = "transparent"))
popViewport()
} else {
|
a93897a0 |
|
cc35650a |
}
|
bb20f132 |
}
column_fun = function(index) {
ht = get("object", envir = parent.frame(7))
mat = ht@matrix
cm = ht@matrix_color_mapping
order_list = ht@row_order_list
ng = length(order_list)
if(cm@type == "discrete") {
|
a93897a0 |
if(!is.null(ylim)) {
stop_wrap("For discrete matrix, `ylim` is not allowed to set. It is always c(0, 1).")
}
|
bb20f132 |
tl = lapply(order_list, function(od) table(mat[od, 1]))
tl = lapply(tl, function(x) x/sum(x))
|
cc35650a |
|
bb20f132 |
pushViewport(viewport(xscale = c(0.5, ng+0.5), yscale = c(0, 1)))
for(i in 1:ng) {
x = i
y = cumsum(tl[[i]])
|
cc35650a |
grid.rect(x, y, width = bar_width, height = tl[[i]], just = "top", gp = gpar(fill = map_to_colors(cm, names(y))), default.units = "native")
|
bb20f132 |
}
|
cc35650a |
if(axis) grid.draw(axis_grob)
if(border) grid.rect(gp = gpar(fill = "transparent"))
|
bb20f132 |
popViewport()
|
cc35650a |
} else {
|
a93897a0 |
vl = lapply(order_list, function(od) mat[od, 1])
nv = length(vl)
if(is.null(ylim)) {
if(!outline) {
boxplot_stats = boxplot(vl, plot = FALSE)$stats
data_scale = range(boxplot_stats)
} else {
data_scale = range(vl, na.rm = TRUE)
}
} else {
data_scale = ylim
}
data_scale = data_scale + c(-extend, extend)*(data_scale[2] - data_scale[1])
if(is.null(ylim)) {
axis_param = validate_axis_param(axis_param, which)
axis_grob = if(axis) construct_axis_grob(axis_param, which, data_scale) else NULL
}
gp = recycle_gp(gp, nv)
if(length(pch) == 1) pch = rep(pch, nv)
if(length(size) == 1) size = rep(size, nv)
pushViewport(viewport(xscale = c(0.5, ng+0.5), yscale = data_scale))
for(i in 1:ng) {
x = i
v = vl[[i]]
grid.boxplot(v, pos = x, box_width = box_width, gp = subset_gp(gp, i),
pch = pch, size = size)
}
if(axis) grid.draw(axis_grob)
if(border) grid.rect(gp = gpar(fill = "transparent"))
popViewport()
|
bb20f132 |
}
}
if(which == "row") {
fun = row_fun
} else if(which == "column") {
fun = column_fun
}
|
249fdfa0 |
|
bb20f132 |
anno = AnnotationFunction(
fun = fun,
fun_name = "anno_summary",
which = which,
width = width,
height = height,
|
a93897a0 |
var_import = list(bar_width, border, axis, axis_grob, axis_param, which, ylim, extend,
outline, box_width, pch, size, gp),
|
bb20f132 |
n = 1,
show_name = FALSE
)
anno@subsetable = FALSE
|
cc35650a |
anno@extended = update_anno_extend(anno, axis_grob, axis_param)
|
bb20f132 |
return(anno)
|
249fdfa0 |
}
|