Orientacja diagonalnych etykiet na osi x w heatmapie (s)

[18]}Tworzenie heatmap w R było tematem wielu postów, dyskusji i iteracji. Moim głównym problemem jest to, że trudno jest połączyć wizualną elastyczność rozwiązań dostępnych w kratce levelplot() lub podstawowej grafice image(), z łatwym klastrem basic' s heatmap(), pheatmap 's pheatmap() lub gplots' heatmap.2(). To drobny szczegół, który chcę zmienić-orientacja diagonalna etykiet na osi X. Pokażę Ci mój punkt w kodzie.

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

Można zmienić orientację na diagonalną łatwo z levelplot():

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

Tutaj wpisz opis obrazka

Ale nakładanie klastrów wydaje się bolesne. Podobnie jak inne opcje wizualne, takie jak dodawanie obramowań wokół komórek heatmapy. Teraz, przejście do rzeczywistych funkcji powiązanych, grupowanie i wszystkie podstawowe wizualizacje są super proste - prawie nie wymaga regulacji:]}
heatmap(d)

Tutaj wpisz opis obrazka

I tak jest tutaj:

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

Tutaj wpisz opis obrazka

I na koniec mój ulubiony:

require(pheatmap)
pheatmap(d) 

Tutaj wpisz opis obrazka

Ale wszystkie nie mają opcji obracania etykiet. Podręcznik dla pheatmap sugeruje, że mogę użyć grid.text do niestandardowego orientowania moich etykiet. Co za radość - szczególnie przy grupowaniu i zmianie kolejności wyświetlanych etykiet. Chyba, że coś mi umyka...

Wreszcie jest stare dobre image(). Mogę obracać etykiety, ogólnie jest to najbardziej konfigurowalne rozwiązanie, ale nie ma opcji grupowania.

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)

Tutaj wpisz opis obrazka

Więc co zrobić, aby uzyskać idealną, szybką heatmapę, z grupowaniem i orientacją i ładnymi funkcjami wizualnymi? Moja najlepsza oferta to zmiana heatmap() lub pheatmap(), ponieważ te dwie wydają się być najbardziej wszechstronne w dostosowaniu. Ale wszelkie rozwiązania mile widziane.

Author: Geek On Acid, 2013-03-19

6 answers

Aby naprawić pheatmap, wszystko, co naprawdę chcesz zrobić, to przejść do pheatmap:::draw_colnames i dostosować kilka ustawień w wywołaniu do grid.text(). Jest na to jeden sposób, używając assignInNamespace(). (Może wymagać dodatkowych poprawek, ale masz zdjęcie ;):

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)

Tutaj wpisz opis obrazka

 20
Author: Josh O'Brien,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-10 17:55:32

Jest to nieco bardziej skomplikowane niż mój komentarz zakładał, ponieważ heatmap rozbija obszar wykresu w celu narysowania dendrogramów, a ostatni obszar wykresu nie jest image wykresem, do którego chcesz dołączyć etykiety.

Istnieje rozwiązanie, ponieważ heatmap dostarcza argumentu add.expr, który pobiera wyrażenie, które ma być oceniane podczas rysowania image. Trzeba również wiedzieć, Zmiana kolejności etykiet, która odbywa się ze względu na kolejność dendrogramu. Ostatni kawałek wiąże się z odrobiną nieeleganckiego włamania, ponieważ najpierw narysuję heatmapę, aby uzyskać informacje o zmianie kolejności, a następnie użyj tego, aby narysować heatmap poprawnie z etykietami pod kątem.

Najpierw przykład z ?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\")")
Na tym etapie etykiety nie są takie, jakie chcemy, ale hv zawierają informacje potrzebne do zmiany kolejności colnames z mtcars w jego komponencie $colInd: {]}
> hv$colInd
 [1]  2  9  8 11  6  5 10  7  1  4  3

Używasz tego tak, jakbyś miał wyjście z order np.:

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

Teraz Użyj tego, aby wygenerować etykiety chcemy w odpowiedniej kolejności:

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

Następnie ponownie wywołujemy heatmap, ale tym razem określamy labCol = "", aby wyłączyć etykietowanie zmiennych kolumn(używając ciągów o zerowej długości). Używamy również wywołania text, aby narysować etykiety pod żądanym kątem. Wezwanie do text to:

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

Co jest w zasadzie tym, co masz w swoim pytaniu. Graj z wartością y, ponieważ musisz dostosować ją do długości łańcuchów, aby etykiety nie pokrywały się z image fabuła Określamy labels = labs, aby przejść w etykietach, które chcemy narysować w wymaganej kolejności. Całe wywołanie text jest przekazywane do add.expr bez cytatu. Oto cała rozmowa:

 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))

Co daje:

Tutaj wpisz opis obrazka

 8
Author: Gavin Simpson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-19 17:20:26

Szukam również metody obracania tekstu etykiety za pomocą heatmap. W końcu udało mi się znaleźć takie rozwiązanie:

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)

Kluczowym argumentem jest srtCol(or srtRow for row labels), który jest używany do obracania etykiet kolumn w gplots.

 7
Author: Yongsheng Cheng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-14 14:17:09

Najnowsza wersja pheatmap (1.0.12) wersja z 2019-01-04 wspiera to argumentem angle_col.

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

#update to latest version on CRAN
install.packages("pheatmap")
library("pheatmap")
pheatmap(d, angle_col = 45)

Ładna heatmapa z podkręconymi etykietami kolumn

Stworzyłem pakiet na Githubie z ulepszoną wersją funkcji heatmap.2. Umożliwia To dostosowanie etykiet osi, w tym argumentu srtCol przekazywanego do funkcji axis. Można go zainstalować z: https://github.com/TomKellyGenetics/heatmap.2x

library("devtools")
install_github("TomKellyGenetics/heatmap.2x")
library("heatmap.2x")

heatmap.2x(d, scale = "none", trace = "none", col = heat.colors, srtCol = 45)

ulepszona heatmap.2x z podklejonymi etykietami kolumn

Od wersji 2.12.1 z gplots, funkcja heatmap.2 obsługuje również argument srtCol.

library("gplots")
heatmap.2(d, scale = "none", trace = "none", srtCol = 45)

heatmap.2 z zakrzywionymi etykietami kolumn

 6
Author: Tom Kelly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-28 06:50:03

Rozwiązanie za pomocą lattice::levelplot i latticeExtra::dendrogramGrob:

library(lattice)
library(latticeExtra)

Przykładowe dane:

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

Należy zdefiniować dendrogramy dla wierszy i kolumn (obliczone wewnętrznie w 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)

I przekazać je do funkcji dendrogramGrob w legend argument levelplot.

Zdefiniowałem nowy motyw z kolorami z RColorBrewer i zmodyfikowano szerokość i kolor obramowań komórek za pomocą border i 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"))))

poziomica z dendrogramem

Możesz nawet użyć argumentu shrink, aby skaluj rozmiar komórek proporcjonalna do ich wartości.

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 z dendrogramem i skalowanymi rozmiarami komórek

 5
Author: Oscar Perpiñán,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-20 22:22:42

Udało mi się wziąć odpowiedź Gavina Simpsona i przyciąć ją trochę do pracy dla mnie dla prostych celów prototypowania, gdzie data1 jest odczyt.obiekt csv () i data1_matrix oczywiście macierz wytworzona z tego

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))
Boom! Dzięki Gavin.

Kluczowym bitem do tego działania jest część przed add.expr bitem, w którym ustawił labCol na"", co jest konieczne, aby zapobiec nakładaniu się pierwszych (prostych) etykiet na nowe 45 stopni

 2
Author: boulder_ruby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-07 01:59:09