Создание сложных теплокарт

Сложные теплокарты (heatmap) позволяют эффективно визуализировать взаимосвязи между различными наборами данных и помогают обнаруживать полезные характеристики. Пакет ComplexHeatmap обеспечивает широкие возможности для организации теплокарт и поддерживает пользовательские графические аннотации.

Общая структура

В общем случае, набор теплокарт (heatmap list) состоит из нескольких теплокарт и строчных аннотаций (row annotation).

Существует несколько классов, используемых при создании теплокарт. Вокруг набора теплокарт располагаются легенды (legend) для самих теплокарт и аннотаций. Кроме того, с любой стороны от набора теплокарт могут размещаться заголовки (title). Вокруг тела каждой теплокарты также могут располагаться различные компоненты.

В пакете ComplexHeatmap компоненты наборов теплокарт выделены в несколько классов:

  • класс Heatmap – одиночная теплокарта (single heatmap), содержащая тело теплокарты, названия строк и столбцов, заголовки, дендрограммы (dendrogram) и столбцовые аннотации (column annotation);
  • класс HeatmapList – набор теплокарт и строчных аннотаций;
  • класс HeatmapAnnotation – определяет набор строчных и столбцовых аннотаций.

Также существует несколько внутренних классов:

  • класс SingleAnnotation – определяет одиночную строчную или одиночную столбцовую аннотацию;
  • класс ColorMapping – реализует преобразование значений в соответствующие цвета.

Пакет ComplexHeatmap реализован на основе системы grid, поэтому пользователи должны знать базовую функциональность grid, чтобы полноценно использовать пакет.

Одиночная теплокарта

Одиночная теплокарта в основном используется для быстрого обзора данных. Одиночная теплокарта – это частный случай набора теплокарт, который содержит только одну теплокарту. В следующих примерах мы покажем, как задать параметры для визуализации одиночной теплокарты.

Для начала загрузим пакеты и сгенерируем случайную матрицу:

library(ComplexHeatmap)
library(circlize)
library(colorspace)
library(GetoptLong)

set.seed(123)

mat = cbind(rbind(matrix(rnorm(16, -1), 4), matrix(rnorm(32, 1), 8)),
            rbind(matrix(rnorm(24, 1), 4), matrix(rnorm(48, -1), 8)))

rownames(mat) = paste0("R", 1:12)
colnames(mat) = paste0("C", 1:10)

Создадим теплокарту с параметрами по умолчанию. Стиль по умолчанию для теплокарты аналогичен стилю теплокарт, создаваемых другими подобными функциями.

Heatmap(mat)

Цвета

В большинстве случаев теплокарта визуализирует матрицу, содержащую непрерывные значения. В этом случае пользователь должен предоставить функцию цветового отображения (color mapping function). Функция цветового отображения должна принимать вектор значений и возвращать вектор соответствующих цветов. Функция colorRamp2() из пакета circlize позволяет создавать подобные функции. Два аргумента функции colorRamp2() представляют собой вектор граничных значений (break value) и вектор соответствующих цветов.

Heatmap(mat, col = colorRamp2(c(-3, 0, 3), c("green", "white", "red")))

Если матрица содержит дискретные значения (числовые или символьные), цвета должны быть заданы в виде именованного вектора (named vector), чтобы обеспечить возможность преобразования дискретных значений в цвета.

discrete_mat = matrix(sample(1:4, 100, replace = TRUE), 10, 10)
colors = structure(rainbow_hcl(4), names = c("1", "2", "3", "4"))
Heatmap(discrete_mat, col = colors)

Также цвета можно задать в виде символьной матрицы (character matrix):

discrete_mat = matrix(sample(letters[1:4], 100, replace = TRUE), 10, 10)
colors = structure(rainbow_hcl(4), names = letters[1:4])
Heatmap(discrete_mat, col = colors)

Как видите, в случае числовой матрицы по умолчанию кластеризация отображается для обоих измерений, а в случае символьной матрицы кластеризация не отображается.

При создании теплокарты допустимы неизвестные значения (NA). Чтобы отобразить NA на теплокарте, вы можете либо отменить кластеризацию, либо применить «кластеризацию нечувствительную к NA», самостоятельно реализовав функцию расстояния (distance function) (см. раздел «Кластеризация» ниже).

mat_with_na = mat
mat_with_na[sample(c(TRUE, FALSE), nrow(mat)*ncol(mat), replace = TRUE, prob = c(1, 11))] = NA
Heatmap(mat_with_na, na_col = "orange", cluster_rows = FALSE, cluster_columns = FALSE)

# or define a 'NA-insensitive clustering'
dist_with_na = function(x, y) {
    l = is.na(x) | is.na(y)
    x = x[!l]
    y = y[!l]
    sqrt(sum((x - y)^2))
}
Heatmap(mat_with_na, na_col = "orange", clustering_distance_rows = dist_with_na,
    clustering_distance_columns = dist_with_na)

Заголовки

Название (name) теплокарты используется в качестве заголовка для легенды теплокарты. Название теплокарты также играет роль уникального идентификатора, если выводится несколько теплокарт вместе (об этом будет рассказано в следующих разделах).

Heatmap(mat, name = "foo")

Вы можете задать для теплокарты строчный (row title) и столбцовый (column title) заголовки. Обратите внимание на то, что каждый из двух заголовков можно вывести только в одном месте, например, либо сверху, либо снизу. Графические характеристики могут быть заданы с помощью параметров row_title_gp и column_title_gp соответственно. Не забывайте о том, что необходимо использовать функцию gpar(), чтобы задать графические характеристики.

Heatmap(mat, name = "foo", column_title = "I am a column title", 
    row_title = "I am a row title")

Heatmap(mat, name = "foo", column_title = "I am a column title at the bottom", 
    column_title_side = "bottom")

Heatmap(mat, name = "foo", column_title = "I am a big column title", 
    column_title_gp = gpar(fontsize = 20, fontface = "bold"))

Кластеризация

Кластеризация – это, возможно, ключевое достоинство визуализации с помощью теплокарт. Пакет ComplexHeatmap обеспечивает высокую гибкость кластеризации. Чтобы реализовать кластеризацию для разных уровней можно применить следующие варианты: заранее определенный метод, функцию расстояния, объект, который уже содержит кластеризацию, или непосредственно функцию кластеризации. Также можно отображать дендрограммы, используя различные цвета и стили для различных ветвей, чтобы более отчетливо выделить структуру данных.

Рассмотрим основные параметры кластеризации, определяющие, например, размер дендрограмм, показывать ли дендрограммы и с какой стороны их располагать.

Heatmap(mat, name = "foo", cluster_rows = FALSE)

Heatmap(mat, name = "foo", show_column_hclust = FALSE)

Heatmap(mat, name = "foo", row_hclust_side = "right")

Heatmap(mat, name = "foo", column_hclust_height = unit(2, "cm"))

Существует три способа задать метрику расстояния (distance metric) для кластеризации:

  • предопределенный вариант. Допустимыми значениями являются поддерживаемые методы для функции dist(), а также значения pearson, spearman и kendall;
  • пользовательская функция, вычисляющая расстояние на основе матрицы. Функция должна принимать только один аргумент. Обратите внимание, в случае столбцовой кластеризации матрица будет транспонирована автоматически.
  • пользовательская функция, вычисляющая расстояние на основе двух векторов. Функция должна принимать только два аргумента.
Heatmap(mat, name = "foo", clustering_distance_rows = "pearson")

Heatmap(mat, name = "foo", clustering_distance_rows = function(m) dist(m))

Heatmap(mat, name = "foo", clustering_distance_rows = function(m) dist(m))

Мы можем применить робастную кластеризацию на основе попарного расстояния. Самостоятельно задав также параметр col с помощью colorRamp2(), мы можем создать теплокарту нечувствительную к аномалиям.

mat_with_outliers = mat
for(i in  1:10) mat_with_outliers[i, i] = 1000
robust_dist = function(x, y) {
    qx = quantile(x, c(0.1, 0.9))
    qy = quantile(y, c(0.1, 0.9))
    l = x > qx[1] & x  qx[2] & y > qy[1] & y  qy[2]
    x = x[l]
    y = y[l]
    sqrt(sum((x - y)^2))
}
Heatmap(mat_with_outliers, name = "foo", 
    col = colorRamp2(c(-3, 0, 3), c("green", "white", "red")),
    clustering_distance_rows = robust_dist,
    clustering_distance_columns = robust_dist)

Метод иерархической кластеризации может быть задан с помощью параметров clustering_method_rows и clustering_method_columns. Допустимыми являются методы, поддерживаемые функцией hclust().

Heatmap(mat, name = "foo", clustering_method_rows = "single")

По умолчанию кластеризация выполняется функцией hclust(). Но вы также можете использовать результаты кластеризации, генерируемые другими методами, присваивая параметру cluster_rows или cluster_columns объект hclust или dendrogram. В следующих примерах для выполнения кластеризации мы используем методы diana() и agnes() из пакета cluster.

library(cluster)
Heatmap(mat, name = "foo", cluster_rows = as.dendrogram(diana(mat)),
   cluster_columns = as.dendrogram(agnes(t(mat))))

Вы можете визуализировать объект dendrogram с помощью пакета dendextend и сделать внешний вид дендрограммы более индивидуальным.

library(dendextend)
dend = hclust(dist(mat))
dend = color_branches(dend, k = 2)
Heatmap(mat, name = "foo", cluster_rows = dend)

В общем случае параметры cluster_rows и cluster_columns могут быть функциями, вычисляющими кластеризации. Входным аргументом функции должна быть матрица, а возвращаемым значением должен быть объект hclust или dendrogram. Обратите внимание, когда происходит внутреннее выполнение cluster_rows, аргумент m – это исходная матрица mat, а когда выполняется cluster_columns, m – это транспонированная матрица mat.

Heatmap(mat, name = "foo", cluster_rows = function(m) hclust(dist(m)),
    cluster_columns = function(m) hclust(dist(m)))

Названия строк и столбцов

Для названий строк и столбцов можно задать параметры, определяющие видимость, положение и графические характеристики.

Heatmap(mat, name = "foo", row_names_side = "left", row_hclust_side = "right", 
    column_names_side = "top", column_hclust_side = "bottom")

Heatmap(mat, name = "foo", show_row_names = FALSE)

Heatmap(mat, name = "foo", row_names_gp = gpar(fontsize = 20))

Heatmap(mat, name = "foo", row_names_gp = gpar(col = c(rep("red", 4), rep("blue", 8))))

Разделение теплокарты по строкам

Теплокарту можно разделить по строкам. Значение параметра km, превышающее 1, означает применение к строкам кластеризации с помощью метода k-средних.

Heatmap(mat, name = "foo", km = 2)

В общем случае в качестве параметра split может быть передан вектор или блок данных (data frame), в котором различные комбинации уровней разделяют строки теплокарты. На самом деле, кластеризация методом k-средних просто создает вектор классов строк и добавляет к split один дополнительный столбец. Комбинированными строчными заголовками можно управлять с помощью параметра combined_name_fun.

Heatmap(mat, name = "foo", split = rep(c("A", "B"), 6))

Heatmap(mat, name = "foo", split = data.frame(rep(c("A", "B"), 6), rep(c("C", "D"), each = 6)))

Heatmap(mat, name = "foo", split = data.frame(rep(c("A", "B"), 6), rep(c("C", "D"), each = 6)), 
    combined_name_fun = function(x) paste(x, collapse = "\n"))

Heatmap(mat, name = "foo", km = 2, split = rep(c("A", "B"), 6), 
    combined_name_fun = function(x) paste(x, collapse = "\n"))

Heatmap(mat, name = "foo", km = 2, split = rep(c("A", "B"), 6), combined_name_fun = NULL)

Если вас не устраивает применяемый по умолчанию для разделения теплокарты метод k-средних, с легкостью можно использовать другие методы разделения, присвоив параметру split вектор разделения.

pa = pam(mat, k = 3)
Heatmap(mat, name = "foo", split = paste0("pam", pa$clustering))


Высоту зазоров между блоками строк можно задать с помощью параметра gap.

Heatmap(mat, name = "foo", split = paste0("pam", pa$clustering), gap = unit(5, "mm"))

Символьная матрица может быть разделена только с помощью аргумента split.

Heatmap(discrete_mat, name = "foo", split = rep(letters[1:2], each = 5))

Определяемое пользователем тело теплокарты

С помощью параметра rect_gp задаются основные графические характеристики тела теплокарты.

Heatmap(mat, name = "foo", rect_gp = gpar(col = "green", lty = 2, lwd = 2))

Тело теплокарты также может быть определено пользователем. По умолчанию тело теплокарта состоит из массива прямоугольников различного цвета. Если при формировании параметра rect_gp присвоить параметру type значение none, массив для прямоугольников будет инициализирован, но графика не будет отображена. Затем пользователь может задать свою собственную графическую функцию с помощью параметра cell_fun. Функция, переданная в параметре cell_fun, применяется к каждой ячейке теплокарты и предоставляет следующую информацию о каждой ячейке:

  • i – индекс строки в матрице;
  • j – индекс столбца в матрице;
  • x – координата x центральной точки ячейки, измеренная относительно области отображения тела теплокарты;
  • y – координата y центральной точки ячейки, измеренная относительно области отображения тела теплокарты;
  • width – ширина ячейки;
  • height – высота ячейки;
  • fill – цвет ячейки.

В следующем примере мы рисуем прямоугольники с закругленными углами и добавляем текст. Мы поместили теплокарту в переменную и вывели ее на экран явным образом, вызвав функцию draw(), только для того, чтобы не отображалась легенда теплокарты. Данная функциональность будет рассмотрена в следующих разделах.

mat2 = matrix(sample(1:10, 12, replace = TRUE), 4, 3)

ht = Heatmap(mat2, rect_gp = gpar(col = "white", lwd = 2, type = "none"), 
    cell_fun = function(j, i, x, y, width, height, fill) {
        grid.roundrect(x, y, width*0.8, height*0.8, gp = gpar(fill = fill))
        if(mat2[i, j]  4) {
            grid.text("cold", x = x, y = y)
        } else if(mat2[i, j] >= 7) {
            grid.text("hot", x = x, y = y)
        } else {
            grid.text("normal", x = x, y = y)
        }
    },
    cluster_rows = FALSE, cluster_columns = FALSE)
draw(ht, show_heatmap_legend = FALSE)

Класс HeatmapAnnotation

В этом разделе мы рассмотрим только столбцовые аннотации. Строчные аннотации будут описаны в следующих разделах.

Графические характеристики аннотаций имеют достаточно общий характер. Единственным отличием столбцовых аннотаций является то, что они позиционируются относительно столбцов теплокарты. Для создания столбцовых аннотаций используется класс HeatmapAnnotation.

Простая аннотация

Простая аннотация задается в виде вектора, содержащего дискретные классы или непрерывные значения, относящиеся к столбцам. Поскольку простая аннотация представляет собой вектор, несколько простых аннотаций можно задать в виде блока данных (data frame). Цвет простой аннотации можно задать с помощью параметр col, передавая через него дискретные значения или функцию цветового отображения, в зависимости от того, является ли простая аннотация дискретной или непрерывной.

При выводе теплокарты простые аннотации будут представлены в виде строк, содержащих ячейки.

Существует метод draw() для класса HeatmapAnnotation. Этот метод используется неявно, и здесь мы вызываем его только для демонстрации.

df = data.frame(type = c(rep("a", 5), rep("b", 5)))
ha = HeatmapAnnotation(df = df)
ha
## A HeatmapAnnotation object with 1 annotation.
## 
## An annotation with discrete color mapping
## name: type 
## position: column 
## show legend: TRUE
draw(ha, 1:10)

ha = HeatmapAnnotation(df = df, col = list(type = c("a" =  "red", "b" = "blue")))
ha
## A HeatmapAnnotation object with 1 annotation.
## 
## An annotation with discrete color mapping
## name: type 
## position: column 
## show legend: TRUE
draw(ha, 1:10)

ha = HeatmapAnnotation(df = data.frame(age = sample(1:20, 10)),
    col = list(age = colorRamp2(c(0, 20), c("white", "red"))))
ha
## A HeatmapAnnotation object with 1 annotation.
## 
## An annotation with continuous color mapping
## name: age 
## position: column 
## show legend: TRUE
draw(ha, 1:10)

Выведем несколько аннотаций вместе.

ha = HeatmapAnnotation(df = data.frame(type = c(rep("a", 5), rep("b", 5)),
                                       age = sample(1:20, 10)),
    col = list(type = c("a" = "red", "b" = "blue"),
               age = colorRamp2(c(0, 20), c("white", "red")))
)
ha
## A HeatmapAnnotation object with 2 annotations.
## 
## An annotation with discrete color mapping
## name: type 
## position: column 
## show legend: TRUE 
## 
## An annotation with continuous color mapping
## name: age 
## position: column 
## show legend: TRUE
draw(ha, 1:10)

Сложные аннотации

Помимо простых аннотаций существуют сложные аннотации. Сложные аннотации всегда формируются с помощью пользовательских функций. Для каждой столбцовой аннотации создается область отображения, предназначенная для вывода графики. Функция, формирующая аннотацию, управляет выводом графики в эту область. Единственным аргументом функции является индекс столбца, который может быть скорректирован с помощью столбцовой кластеризации.

В следующем примере создана аннотация, представленная точками. Обратите внимание, мы задали параметр xscale таким образом, чтобы каждая точка располагалась посредине соответствующего столбца.

value = rnorm(10)
column_anno = function(index) {
    n = length(index)
    pushViewport(viewport(xscale = c(0.5, n + 0.5), yscale = range(value)))
    grid.points(index, value, pch = 16)
    upViewport() # this is very important in order not to mess up the layout
}
ha = HeatmapAnnotation(points = column_anno)
ha
## A HeatmapAnnotation object with 1 annotation.
## 
## An annotation with self-defined function
## name: points 
## position: column
draw(ha, 1:10)

В случае простой аннотации можно создать подобную функцию, формирующую аннотацию, с помощью функций anno_points() или anno_barplot(). Функция anno_points() вернет функцию, вполне удовлетворяющую нашим требованиям.

ha = HeatmapAnnotation(points = anno_points(value))
draw(ha, 1:10)

ha = HeatmapAnnotation(points = anno_barplot(value))
draw(ha, 1:10)

Также существует функция anno_boxplot(), которая формирует диаграмму «ящик с усами» для каждого столбца матрицы.

ha = HeatmapAnnotation(boxplot = anno_boxplot(mat))
draw(ha, 1:10)

Вы можете объединить несколько аннотаций в одном объекте.

ha = HeatmapAnnotation(df = df, points = anno_points(value))
ha
## A HeatmapAnnotation object with 2 annotations.
## 
## An annotation with discrete color mapping
## name: type 
## position: column 
## show legend: TRUE 
## 
## An annotation with self-defined function
## name: points 
## position: column
draw(ha, 1:10)

Если выводится несколько аннотаций, можно управлять высотой каждой аннотации с помощью параметра annotation_height. Значение параметра annotation_height может быть или числовым значением, или объектом unit. Но если вы задаете высоты с помощью объектов unit, вы должны убедиться в том, что сумма высот не превышает высоту отображенных аннотаций.

ha = HeatmapAnnotation(df = df, points = anno_points(value), boxplot = anno_boxplot(mat),
    annotation_height = c(1, 2, 3))
draw(ha, 1:10)

ha = HeatmapAnnotation(df = df, points = anno_points(value), boxplot = anno_boxplot(mat),
    annotation_height = unit.c(unit(1, "null"), unit(3, "cm"), unit(3, "cm")))
draw(ha, 1:10)

Вы можете добавить аннотации к теплокарте с помощью параметров top_annotation и bottom_annotation. Также вы можете задать суммарную высоту всех столбцовых аннотаций с помощью параметров top_annotation_height и bottom_annotation_height.

ha = HeatmapAnnotation(df = df, points = anno_points(value))
ha_boxplot = HeatmapAnnotation(boxplot = anno_boxplot(mat))
Heatmap(mat, name = "foo", top_annotation = ha, bottom_annotation = ha_boxplot, 
    bottom_annotation_height = unit(2, "cm"))

Чтобы не отображать легенды для аннотаций, можно присвоить параметру show_legend значение FALSE при создании объекта HeatmapAnnotation.

ha = HeatmapAnnotation(df = df, show_legend = FALSE)
Heatmap(mat, name = "foo", top_annotation = ha)

Другие типы аннотаций, демонстрирующие распределение данных в соответствующих строках и столбцах, можно создать с помощью функций anno_histogram() и anno_density().

ha_mix_top = HeatmapAnnotation(histogram = anno_histogram(mat, gp = gpar(fill = rep(2:3, each = 5))),
    density_line = anno_density(mat, type = "line", gp = gpar(col = rep(2:3, each = 5))),
    violin = anno_density(mat, type = "violin", gp = gpar(fill = rep(2:3, each = 5))),
    heatmap = anno_density(mat, type = "heatmap"))
ha_mix_right = HeatmapAnnotation(histogram = anno_histogram(mat, gp = gpar(fill = rep(2:3, each = 5)), which = "row"),
    density_line = anno_density(mat, type = "line", gp = gpar(col = rep(2:3, each = 5)), which = "row"),
    violin = anno_density(mat, type = "violin", gp = gpar(fill = rep(2:3, each = 5)), which = "row"),
    heatmap = anno_density(mat, type = "heatmap", which = "row"), 
    which = "row", width = unit(8, "cm"))
Heatmap(mat, name = "foo", top_annotation = ha_mix_top, top_annotation_height = unit(8, "cm")) + ha_mix_right

При создании аннотаций также можно использовать текст. Функция anno_text() обеспечивает вывод текста в качестве аннотации. С помощью этой функции легко создать названия столбцов, текст которых расположен под определенным углом (данную функцию также можно применить в отношении названий строк в рамках строчных аннотаций). Обратите внимание, пространство, необходимое для текстовых аннотаций, должно быть вычислено вручную.

long_cn = do.call("paste0", rep(list(colnames(mat)), 3))  # just to construct long text
ha_rot_cn = HeatmapAnnotation(text = anno_text(long_cn, rot = 45, just = "left", offset = unit(2, "mm")))
Heatmap(mat, name = "foo", top_annotation = ha_rot_cn, top_annotation_height = unit(2, "cm"))

Класс HeatmapAnnotation также используется для создания строчных аннотаций, которые мы рассмотрим в следующих разделах.

Набор теплокарт

Вы можете создать несколько теплокарт, располагающихся друг за другом по горизонтали. На самом деле, одиночная теплокарта – это частный случай набора теплокарт, который содержит только одну теплокарту.

Функция Heatmap() – это конструктор класса, представляющего одиночную теплокарту. Если необходимо объединить несколько теплокарт в набор, можно присоединять теплокарты друг к другу с помощью операции «+».

mat = matrix(rnorm(80, 2), 8, 10)
mat = rbind(mat, matrix(rnorm(40, -2), 4, 10))
rownames(mat) = paste0("R", 1:12)
colnames(mat) = paste0("C", 1:10)

ht1 = Heatmap(mat, name = "ht1")
ht2 = Heatmap(mat, name = "ht2")
class(ht1)
## [1] "Heatmap"
## attr(,"package")
## [1] "ComplexHeatmap"
class(ht2)
class(ht2)
## [1] "Heatmap"
## attr(,"package")
## [1] "ComplexHeatmap"
ht1 + ht2

В режиме по умолчанию дендрограммы второй теплокарты будут удалены, а последовательность расположения строк будет такой же, как и у первой теплокарты.

Результатом сложения двух теплокарт является объект HeatmapList. Прямой вызов объекта ht_list приведет к вызову метода draw() с параметрами по умолчанию. При явном вызове метода draw() вы получаете больше возможностей для настройки легенды и заголовков.

ht_list = ht1 + ht2
class(ht_list)
## [1] "HeatmapList"
## attr(,"package")
## [1] "ComplexHeatmap"

Вы можете добавить в набор теплокарт произвольное количество теплокарт. Также можно суммировать наборы теплокарт.

ht1 + ht1 + ht1
ht1 + ht_list
ht_list + ht1
ht_list + ht_list

Заголовки

Набор теплокарт имеет заголовки независимые по отношению к заголовкам отдельных теплокарт.

ht1 = Heatmap(mat, name = "ht1", row_title = "Heatmap 1", column_title = "Heatmap 1")
ht2 = Heatmap(mat, name = "ht2", row_title = "Heatmap 2", column_title = "Heatmap 2")
ht_list = ht1 + ht2

draw(ht_list, row_title = "Two heatmaps, row title", row_title_gp = gpar(col = "red"),
    column_title = "Two heatmaps, column title", column_title_side = "bottom")

Легенды

Легенды для всех теплокарт и всех аннотаций будут отображены в одном месте. Легенды для теплокарт и легенды для аннотаций выводятся в отдельные области отображения.

df = data.frame(type = c(rep("a", 5), rep("b", 5)))
ha = HeatmapAnnotation(df = df, col = list(type = c("a" =  "red", "b" = "blue")))

ht1 = Heatmap(mat, name = "ht1", column_title = "Heatmap 1", top_annotation = ha)
ht2 = Heatmap(mat, name = "ht2", column_title = "Heatmap 2")
ht_list = ht1 + ht2

draw(ht_list)

draw(ht_list, heatmap_legend_side = "left", annotation_legend_side = "bottom")

draw(ht_list, show_heatmap_legend = FALSE, show_annotation_legend = FALSE)

Вы можете отобразить легенды только для некоторых теплокарт, присвоив соответствующее логическое значение параметру show_heatmap_legend.

ht1 = Heatmap(mat, name = "ht1", column_title = "Heatmap 1", top_annotation = ha)
ht2 = Heatmap(mat, name = "ht2", column_title = "Heatmap 2", show_heatmap_legend = FALSE)
ht1 + ht2

Класс ComplexHeatmap создает легенды только для теплокарт и простых аннотаций. Пользовательские легенды можно передать через параметр annotation_legend_list в виде набора объектов grob.

ha = HeatmapAnnotation(points = anno_points(rnorm(10)))
ht2 = Heatmap(mat, name = "ht2", column_title = "Heatmap 2", top_annotation = ha, show_heatmap_legend = FALSE)
lgd = legendGrob(c("dots"), pch = 16)
draw(ht1 + ht2, annotation_legend_list = list(lgd))

Можно задать графические характеристики легенд для простых аннотаций. Эти характеристики передаются в качестве аргументов методу color_mapping_legend() класса ColorMapping.

draw(ht1 + ht2, legend_grid_width = unit(6, "mm"), 
    legend_title_gp = gpar(fontsize = 14, fontface = "bold"))

Расстояние между теплокартами

Расстояние между теплокартами можно задать с помощью параметра gap, используя объект unit.

draw(ht_list, gap = unit(1, "cm"))

draw(ht_list + ht_list, gap = unit(c(3, 6, 9, 0), "mm"))

Размер теплокарт

Для некоторых (не всех) теплокарт можно задать фиксированную ширину.

ht1 = Heatmap(mat, name = "ht1", column_title = "Heatmap 1")
ht2 = Heatmap(mat, name = "ht2", column_title = "Heatmap 2", width = unit(5, "cm"))
ht1 + ht2

Автоматические преобразования

Если отображается несколько теплокарт, производятся некоторые автоматические преобразования. Должна быть определена главная теплокарта, которая по умолчанию является первой. Некоторые параметры всех остальных теплокарт будут приведены в соответствие с параметрами главной теплокарты. Происходят следующие преобразования:

  • удаляются строчные кластеры;
  • удаляются строчные заголовки;
  • если главная теплокарта разделена по строкам, все остальные теплокарты также будут разделены на тех же уровнях, что и главная теплокарта.

Главную теплокарту можно задать с помощью параметра main_heatmap. Его значением может быть числовой индекс или имя теплокарты (имя должно быть предварительно задано при создании объекта Heatmap).

ht1 = Heatmap(mat, name = "ht1", column_title = "Heatmap 1", km = 2)
ht2 = Heatmap(mat, name = "ht2", column_title = "Heatmap 2")
ht1 + ht2

draw(ht2 + ht1)

draw(ht2 + ht1, main_heatmap = "ht1")

Если у главной теплокарты нет строчной кластеризации, у всех остальных теплокарт также не будет строчной кластеризации.

ht1 = Heatmap(mat, name = "ht1", column_title = "Heatmap 1", cluster_rows = FALSE)
ht2 = Heatmap(mat, name = "ht2", column_title = "Heatmap 2")
ht1 + ht2

Набор теплокарт со строчными аннотациями

Строчные аннотации

Строчные аннотации также создаются с помощью класса HeatmapAnnotation, но при этом параметру which присваивается значение row.

df = data.frame(type = c(rep("a", 6), rep("b", 6)))
ha = HeatmapAnnotation(df = df, which = "row", width = unit(1, "cm"))
draw(ha, 1:12)

Можно отобразить несколько строчных аннотаций вместе.

ha_combined = HeatmapAnnotation(df = df, boxplot = anno_boxplot(mat, which = "row"), 
    which = "row", annotation_width = c(1, 3))
draw(ha_combined, 1:12)

Объединение теплокарт и строчных аннотаций

По существу, строчные и столбцовые аннотации – это идентичные графические объекты, но в приложениях существуют некоторые отличия. В рамках пакета ComplexHeatmap строчные аннотации располагаются в том же месте, где и теплокарта, а столбцовые аннотации являются своего рода дополнительными компонентами теплокарты. Со строчными аннотациями можно производить такие же действия, как и с теплокартами: вы можете присоединять строчные аннотации к теплокарте, или к набору теплокарт, или даже к такому же объекту строчной аннотации.

ht1 = Heatmap(mat, name = "ht1")
ht1 + ha + ht1

Также можно создать сложные строчные аннотации. Обратите внимание, дендрограмма и строчный заголовок размещены по разные стороны от набора теплокарт с помощью соответствующих значений параметров row_hclust_side и row_sub_title_side.

ht1 = Heatmap(mat, name = "ht1", km = 2)
ha_boxplot = HeatmapAnnotation(boxplot = anno_boxplot(mat, which = "row"), 
    which = "row", width = unit(2, "cm"))
draw(ha_boxplot + ht1, row_hclust_side = "left", row_sub_title_side = "right")

В случае строчных аннотаций, можно визуализировать данные с помощью более сложной графики. В следующем примере строчные аннотации также разделены с помощью кластеризации методом k-средних. В пользовательской функции distribution, формирующей аннотацию, параметр x – это индекс строки в «текущем» блоке строк. Функция distribution будет применена к каждому блоку строк.

ht1 = Heatmap(mat, name = "ht1", km = 2)
random_data = lapply(1:12, function(x) runif(20))
random_data[1:6] = lapply(random_data[1:6], function(x) x*0.5)
ha2 = HeatmapAnnotation(distribution = function(index) {
        random_data = random_data[index]
        n = length(index)

        for(i in seq_len(n)) {
            y = random_data[[i]]
            pushViewport(viewport(x= 0, y = (i-0.5)/n, width = unit(9, "cm"), 
                height = 1/n*0.8, just = "left", xscale = c(0, 20), yscale = c(0, 1)))
            if(index[i] %in% 1:6) fill = "blue" else fill = "red"
            grid.polygon(c(1:20, 20, 1), c(y, 0, 0), default.units = "native", 
                gp = gpar(fill = fill, col = NA))
            grid.yaxis(main = FALSE, gp = gpar(fontsize = 8))
            upViewport()
        }
    }, which = "row", width = unit(10, "cm"))
draw(ht1 + ha2, row_hclust_side = "left", row_sub_title_side = "right")

Если не требуется отображать теплокарту, а необходимо лишь вывести набор строчных аннотаций, то при создании теплокарты можно использовать пустую матрицу без столбцов. При использовании матрицы без столбцов вы по-прежнему можете разделить строчные аннотации.

nr = nrow(mat)
ha = HeatmapAnnotation(df = df, which = "row", width = NULL)
Heatmap(matrix(nrow = nr, ncol = 0), split = sample(c("A", "B"), nr, replace = TRUE)) + 
    ha_boxplot + ha2 + ha

Также можно добавить к строчным аннотациям дендрограммы.

dend = hclust(dist(mat))
Heatmap(matrix(nrow = nr, ncol = 0), cluster_rows = dend) + 
    ha_boxplot + ha2 + ha

Доступ к компонентам

Каждый компонент теплокарты и набора теплокарт имеет имя. Вы можете перейти к любой области отображения с помощью функции seekViewport(). Представленный ниже рисунок содержит почти все типы компонентов.

ha_column1 = HeatmapAnnotation(points = anno_points(rnorm(10)))
ht1 = Heatmap(mat, name = "ht1", km = 2, row_title = "Heatmap 1", column_title = "Heatmap 1", 
    top_annotation = ha_column1)

ha_column2 = HeatmapAnnotation(df = data.frame(type = c(rep("a", 5), rep("b", 5))))
ht2 = Heatmap(mat, name = "ht2", row_title = "Heatmap 2", column_title = "Heatmap 2",
    bottom_annotation = ha_column2)

ht_list = ht1 + ht2
draw(ht_list, row_title = "Heatmap list", column_title = "Heatmap list", 
    heatmap_legend_side = "right", annotation_legend_side = "left")

Компоненты имеют следующие имена:

  • global – область отображения, содержащая весь рисунок;
  • global_column_title – область отображения, содержащая столбцовый заголовок для набора теплокарт;
  • global_row_title – область отображения, содержащая строчный заголовок для набора теплокарт;
  • main_heatmap_list – область отображения, содержащая набор теплокарт и строчные аннотации;
  • heatmap_@{heatmap_name} – область отображения, содержащая одиночную теплокарту;
  • annotation_@{annotation_name} – область отображения, содержащая строчную или столбцовую аннотацию;
  • @{heatmap_name}_heatmap_body_@{i} – тело теплокарты;
  • @{heatmap_name}_column_title – столбцовый заголовок для одиночной теплокарты;
  • @{heatmap_name}_row_title_@{i} – строчный заголовок для одиночной теплокарты. @{i} – индекс блока строк, поскольку тело теплокарты может быть разделено на несколько частей;
  • @{heatmap_name}_hclust_row_@{i} – дендрограмма для i-го блока строк;
  • @{heatmap_name}_hclust_column – столбцовая дендрограмма;
  • @{heatmap_name}_row_names_@{i} – область отображения, содержащая названия строк;
  • @{heatmap_name}_column_names – область отображения, содержащая названия столбцов;
  • heatmap_legend – область отображения, содержащая все легенды для теплокарт;
  • legend_@{heatmap_name} – область отображения, содержащая легенду для одиночной теплокарты;
  • annotation_legend – область отображения, содержащая все легенды для аннотаций;
  • legend_@{annotation_name} – область отображения, содержащая легенду для одиночной аннотации.
ht_list

seekViewport("annotation_points")
grid.text("points", unit(0, "npc") - unit(2, "mm"), 0.5, default.units = "npc", just = "right")

seekViewport("ht1_heatmap_body_2")
grid.text("outlier", 1.5/10, 2.5/4, default.units = "npc")

seekViewport("annotation_type")
grid.text("type", unit(1, "npc") + unit(2, "mm"), 0.5, default.units = "npc", just = "left")

Реальные применения

В матрице экспрессии генов строки представляют собой гены. Вместе с теплокартой экспрессии можно отобразить дополнительную информацию о генах, например, длину генов и тип генов.

expr = readRDS(paste0(system.file(package = "ComplexHeatmap"), "/extdata/gene_expression.rds"))
mat = as.matrix(expr[, grep("cell", colnames(expr))])

type = gsub("s\\d+_", "", colnames(mat))
ha = HeatmapAnnotation(df = data.frame(type = type))

Heatmap(mat, name = "expression", km = 5, top_annotation = ha, 
    top_annotation_height = unit(4, "mm"), show_row_names = FALSE, 
    show_column_names = FALSE) +
Heatmap(expr$length, name = "length", col = colorRamp2(c(0, 100000), c("white", "orange")),
    width = unit(5, "mm")) +
Heatmap(expr$type, name = "type", width = unit(5, "mm")) +
Heatmap(expr$chr, name = "chr", col = rand_color(length(unique(expr$chr))), 
    width = unit(5, "mm"))

Следующий пример – это визуализация OncoPrint [ссылка]. Основная идея заключается в том, что пользователь самостоятельно задает тело теплокарты. Кроме стиля по умолчанию, реализованного cBioPortal [ссылка], также представлены дополнительные гистограммы с обеих сторон теплокарты, показывающие количество различных мутаций для каждого образца и для каждого гена. Исходный код можно найти здесь [ссылка].

Следующий пример визуализирует корреляцию между метилированием и экспрессией, а также другую информацию в виде аннотаций (данные сгенерированы случайным образом). На теплокарте строки представляют дифференциально метилированные регионы (differentially methylated regions, DMRs). Теплокарты представляют следующее (слева направо):

  1. метилирование для каждого DMR (по строкам) в образцах;
  2. направление метилирования: гиперметилирование или гипометилирование (теплокарта с одним столбцом);
  3. экспрессия генов, связанных с соответствующими DMRs (например, ближайший ген);
  4. значение корреляции между метилированием и экспрессией (-log10(p-value));
  5. тип гена. Т.е. кодирует ли ген белок или является длинной некодирующей РНК (long non-coding RNA, lincRNA);
  6. аннотация для моделей генов. Т.е. расположен ли DMR в интроне (intragenic region) соответствующего гена или DMR является межгенным (intergenic);
  7. расстояние от DMR до сайта инициации транскрипции (transcription start site, TSS) соответствующего гена;
  8. перекрытие DMRs энхансерами (enhancer) (цвет показывает какая часть DMR перекрыта).

Исходный код можно найти здесь.

Информация о сессии

## R version 3.2.0 (2015-04-16)
## Platform: x86_64-unknown-linux-gnu (64-bit)
## Running under: Ubuntu 14.04.2 LTS
## 
## locale:
##  [1] LC_CENGINE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8       
##  [4] LC_COLLATE=C               LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
##  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                  LC_ADDRESS=C              
## [10] LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
## [1] grid      stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] dendextend_0.18.3    cluster_2.0.1        GetoptLong_0.1.0     colorspace_1.2-6    
## [5] circlize_0.2.4       ComplexHeatmap_1.1.5 knitr_1.10.5         markdown_0.7.7      
## 
## loaded via a namespace (and not attached):
##  [1] formatR_1.2         magrittr_1.5        evaluate_0.7        stringi_0.4-1      
##  [5] GlobalOptions_0.0.6 whisker_0.3-2       RColorBrewer_1.1-2  rjson_0.2.15       
##  [9] tools_3.2.0         stringr_1.0.0       shape_1.4.2

По материалам: bioconductor.org

Добавить комментарий

Ваш адрес email не будет опубликован.

закрыть

Поделиться

Отправить на почту
закрыть

Вход

закрыть

Регистрация

+ =