2013-03-19 3 views
21

Создание тепловых карт в R - тема многих сообщений, обсуждений и итераций. Моя основная проблема заключается в том, что сложно сочетать визуальную гибкость решений, доступных в решетке levelplot() или базовую графику image(), с легкой кластеризацией базовых heatmap(), peeatmap's pheatmap() или gplots 'heatmap.2(). Это крошечная деталь, которую я хочу изменить - диагональную ориентацию меток по оси х. Позвольте мне показать вам свою точку зрения в коде.Ориентация диагональных меток на оси x в тепловой карте (ых)

#example data 
d <- matrix(rnorm(25), 5, 5) 
colnames(d) = paste("bip", 1:5, sep = "") 
rownames(d) = paste("blob", 1:5, sep = "") 

Вы можете изменить ориентацию легко диагональной с levelplot():

require(lattice) 
levelplot(d, scale=list(x=list(rot=45))) 

enter image description here

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

Теперь, переходя к фактической heatmap() связанных функций, кластеризация и все основные визуальные эффекты супер-простой - почти не требуется никакой регулировки:

heatmap(d) 

enter image description here

и так здесь:

require(gplots) 
heatmap.2(d, key=F) 

enter image description here

и, наконец, моя любимая:

require(pheatmap) 
pheatmap(d) 

enter image description here

Но все из них не имеют никакого выбора, чтобы повернуть метки. В руководстве для pheatmap указано, что я могу использовать grid.text для ориентации моих меток. Какая радость - особенно при кластеризации и изменении порядка отображения ярлыков. Если я не пропущу что-то здесь ...

Наконец-то есть старый добрый image(). Я могу повернуть метки, в общем, это самое настраиваемое решение, но не кластеризация.

image(1:nrow(d),1:ncol(d), d, axes=F, ylab="", xlab="") 
text(1:ncol(d), 0, srt = 45, labels = rownames(d), xpd = TRUE) 
axis(1, label=F) 
axis(2, 1:nrow(d), colnames(d), las=1) 

enter image description here

Так что я должен сделать, чтобы получить мой идеал, быстрый Heatmap с кластеризация и ориентации и приятные визуальные особенности взлома? Моя лучшая ставка меняет heatmap() или pheatmap() как-то, потому что эти два, кажется, самые универсальные в настройке. Но любые решения приветствуются.

+0

Базовая графика не позволяет контролировать вращение меток ярлыков произвольными углами - поэтому вы должны использовать «текстовый» взлом », который вы показываете на последнем примере« образ ». Вероятно, я передал бы 'xaxt = FALSE' в мой вызов' heatmap', а затем добавлю ось без меток, а затем добавлю метки с помощью 'text', так же, как вы делаете с' image'. –

+0

@GavinSimpson Проблема с этим подходом заключается в том, что вам необходимо вручную определить порядок меток по оси x при кластеризации. Возможно, но немного больно. Тем не менее, спасибо, указав на то, что 'heatmap()' создается с использованием базовой графики, а не сетки (я думал, что это сетка как 'pheatmap()'). –

+0

Существует решение этого - у меня есть что-то работающее, что я просто пишу в качестве ответа. Это было немного больше, чем я думал. Решение скоро ... –

ответ

15

Чтобы исправить pheatmap, все, что вам действительно нужно сделать, это пойти в pheatmap:::draw_colnames и настроить несколько параметров в вызове до grid.text(). Вот один из способов сделать это, используя assignInNamespace(). (Это может понадобиться дополнительные настройки, но вы получите картину;):

library(grid)  ## Need to attach (and not just load) grid package 
library(pheatmap) 

## Your data 
d <- matrix(rnorm(25), 5, 5) 
colnames(d) = paste("bip", 1:5, sep = "") 
rownames(d) = paste("blob", 1:5, sep = "") 

## Edit body of pheatmap:::draw_colnames, customizing it to your liking 
draw_colnames_45 <- function (coln, ...) { 
    m = length(coln) 
    x = (1:m)/m - 1/2/m 
    grid.text(coln, x = x, y = unit(0.96, "npc"), vjust = .5, 
     hjust = 1, rot = 45, gp = gpar(...)) ## Was 'hjust=0' and 'rot=270' 
} 

## For pheatmap_1.0.8 and later: 
draw_colnames_45 <- function (coln, gaps, ...) { 
    coord = pheatmap:::find_coordinates(length(coln), gaps) 
    x = coord$coord - 0.5 * coord$size 
    res = textGrob(coln, x = x, y = unit(1, "npc") - unit(3,"bigpts"), vjust = 0.5, hjust = 1, rot = 45, gp = gpar(...)) 
    return(res)} 

## 'Overwrite' default draw_colnames with your own version 
assignInNamespace(x="draw_colnames", value="draw_colnames_45", 
ns=asNamespace("pheatmap")) 

## Try it out 
pheatmap(d) 

enter image description here

+1

Ну, для вас это небольшая настройка, для меня это большой шаг. В конце дня вы являетесь мастером сетки;) Спасибо, Джош! –

+0

@GeekOnAcid - Ну, спасибо, как обычно, за интересный вопрос! По правде говоря, это первый раз, когда я использовал 'assignInNamespace()', и оба они и 'pheatmap' - приятные находки. Сначала я сделал «trace (pheatmap ::: draw_colnames, edit = TRUE)», чтобы попробовать пару вещей, но как только я нашел исправление, вам понадобилось нечто менее интерактивное, чем это. Выключает 'assignInNamespace()' билет, и я буду использовать его довольно немного вперед. Приветствия. –

+0

+1 То же самое можно сделать и для версии «heatmap», но в этом случае проще просто запустить вызов сюжета дважды и использовать 'add.expr'. –

7

Это немного сложнее, чем предполагалось в моем комментарии, потому что heatmap разбивает область построения, чтобы рисовать дендрограммы, а последний участок участка - это не участок image, к которому вы хотите прикрепить ярлыки.

Существует решение, хотя как heatmap содержит аргумент add.expr, который принимает выражение для оценки при рисовании image. Также необходимо знать переупорядочение меток, которые происходят из-за заказа дендрограмм.Последний бит включает в себя немного неэффективного взлома, так как я сначала нарисую тепловую карту, чтобы получить информацию о переупорядочении, а затем используйте ее, чтобы правильно нарисовать тепловую карту с помощью угловых меток.

Первый пример из ?heatmap

x <- as.matrix(mtcars) 
rc <- rainbow(nrow(x), start = 0, end = .3) 
cc <- rainbow(ncol(x), start = 0, end = .3) 
hv <- heatmap(x, col = cm.colors(256), scale = "column", 
       RowSideColors = rc, ColSideColors = cc, margins = c(5,10), 
       xlab = "specification variables", ylab = "Car Models", 
       main = "heatmap(<Mtcars data>, ..., scale = \"column\")") 

На данном этапе, этикетки не как мы хотим их, но hv содержит информацию, которую мы должны изменить порядок colnames из mtcars в компоненте $colInd:

> hv$colInd 
[1] 2 9 8 11 6 5 10 7 1 4 3 

Вы можете использовать это, как вы бы выход из order например:

> colnames(mtcars)[hv$colInd] 
[1] "cyl" "am" "vs" "carb" "wt" "drat" "gear" "qsec" "mpg" "hp" 
[11] "disp" 

Теперь использовать это для создания этикеток, которые мы хотим в правильном порядке:

labs <- colnames(mtcars)[hv$colInd] 

Затем мы вновь называем heatmap, но на этот раз мы указываем labCol = "" для подавления маркировки переменных столбцов (используя нулевую длину строки). Мы также используем звонок для text, чтобы нарисовать метки под нужным углом. Вызов text является:

text(x = seq_along(labs), y = -0.2, srt = 45, labels = labs, xpd = TRUE) 

, который, по сути, что у вас есть в вашем вопросе. Играйте со значением y, так как вам нужно отрегулировать это на длину строк, чтобы метки не перекрывались с участком image. Мы указываем labels = labs, чтобы передать этикетки, которые мы хотим провести, в требуемом порядке. Весь звонок text передается в add.expr без кавычек. Вот весь вызов:

hv <- heatmap(x, col = cm.colors(256), scale = "column", 
       RowSideColors = rc, ColSideColors = cc, margins = c(5,10), 
       xlab = "specification variables", ylab = "Car Models", 
       labCol = "", 
       main = "heatmap(<Mtcars data>, ..., scale = \"column\")", 
       add.expr = text(x = seq_along(labs), y = -0.2, srt = 45, 
           labels = labs, xpd = TRUE)) 

Какие результаты в:

enter image description here

+0

Ницца. Благодарю. Получение позиции этикеток имеет решающее значение, поэтому спасибо за это решение, однако «грубо» это :) –

+0

Да, очень приятно. Только в прошлом месяце я узнал от вас о 'plot (..., panel.last)', а теперь здесь 'heatmap (..., add.expr)'. Хорошие напоминания о том, что я должен лучше следить за удобными аргументами, такими как (или, может быть, лучше сканировать некоторые ваши задние столбы для подобных камней). –

4

решение с использованием lattice::levelplot и latticeExtra::dendrogramGrob:

library(lattice) 
library(latticeExtra) 

Пример данных:

d <- matrix(rnorm(25), 5, 5) 
colnames(d) = paste("bip", 1:5, sep = "") 
rownames(d) = paste("blob", 1:5, sep = "") 

Вы должны определить дендрограммы для строк и Столбцы (вычисленный внутренне в heatmap):

dd.row <- as.dendrogram(hclust(dist(d))) 
row.ord <- order.dendrogram(dd.row) 

dd.col <- as.dendrogram(hclust(dist(t(d)))) 
col.ord <- order.dendrogram(dd.col) 

и передать их функции dendrogramGrob в legend аргумент levelplot.

Я определил новую тему с цветами из RColorBrewer и изменил ширину и цвет границ ячеек с border и border.lwd:

myTheme <- custom.theme(region=brewer.pal(n=11, 'RdBu')) 

levelplot(d[row.ord, col.ord], 
      aspect = "fill", xlab='', ylab='', 
      scales = list(x = list(rot = 45)), 
      colorkey = list(space = "bottom"), 
      par.settings=myTheme, 
      border='black', border.lwd=.6, 
      legend = 
      list(right = 
       list(fun = dendrogramGrob, 
        args = 
        list(x = dd.col, ord = col.ord, 
         side = "right", 
         size = 10)), 
       top = 
       list(fun = dendrogramGrob, 
        args = 
        list(x = dd.row, 
         side = "top")))) 

levelplot with dendrogram

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

levelplot(d[row.ord, col.ord], 
      aspect = "fill", xlab='', ylab='', 
      scales = list(x = list(rot = 45)), 
      colorkey = list(space = "bottom"), 
      par.settings=myTheme, 
      border='black', border.lwd=.6, 
      shrink=c(.75, .95), 
      legend = 
      list(right = 
       list(fun = dendrogramGrob, 
        args = 
        list(x = dd.col, ord = col.ord, 
         side = "right", 
         size = 10)), 
       top = 
       list(fun = dendrogramGrob, 
        args = 
        list(x = dd.row, 
         side = "top")))) 

levelplot with dendrogram and scaled cell sizes

+0

Очень аккуратно, приветствует Оскара! –

2

я был в состоянии принять ответ Gavin Симпсона и поправили его немного вниз, чтобы работать на меня для простых целей прототипирования, где data1 является read.csv() объекта, и data1_matrix конечно матрица, полученная из этого

heatmap(data_matrix, Rowv=NA, Colv=NA, col=heat.colors(64), scale='column', margins=c(5,10), 
    labCol="", add.expr = text(x = seq_along(colnames(data1)), y=-0.2, srt=45, 
    labels=colnames(data1), xpd=TRUE)) 

Стрела! Спасибо, Гэвин.

Ключевая бит для этой работы является частью до add.expr бит, где он поставил labCol к «», которое необходимо для предотвращения прежних (прямой вниз) меток из перекрывающихся с новыми 45 градусами из них

5

Я также ищу метод для поворота текста меток с помощью тепловой карты. В конце концов мне удалось найти такое решение:

library(gplots) 

library(RColorBrewer) 

heatmap.2(x,col=rev(brewer.pal(11,"Spectral")),cexRow=1,cexCol=1,margins=c(12,8),trace="none",srtCol=45) 

Ключевой аргумент srtCol(or srtRow for row labels), который используется для вращения меток столбцов в gplots.

+0

Нет, когда я использую свои данные примера с вашим решением, он не работает. Это дает мне ошибку, что '' srtCol "не является графическим параметром'. –

Смежные вопросы