厚缊

诹图——ggmatrix

厚缊 / 2019-12-29


这个包的主要基于两个原因:昨天朋友告诉我被翻牌子把rectriangle整合进ggcor,我考虑了之后觉得放在ggcor不是很合适,就新开了一个包;另外一个是在做ggcor的过程中有很多新想法,需要先找个地方测试。当然,就目前来说,ggmatrix除了细节做的不够精致以外,其它的俨然有成为ggcor超集的趋势,看来我要一边捡芝麻一边仍西瓜了。庆幸的是,ggcor正在做互作网络一块的内容,也算两个有所区别,不重复劳动。ggmatrix差不多就是一天的时间整完的,不完美是必然。

安装

# install.packages("devtools")
devtools::install_github("houyunhuang/ggmatrix")

案例(一)

ggmatrix的缘起就是上下不一样的三角形热图,所以介绍也从这个热图开始。故事开始之前先造个数据(后面会讲到,这样造数据完全可以避免,因为有matrixs_to_df()函数)。

library(ggmatrix) ## 0.1.2版本
library(RColorBrewer)
df <- data.frame(x = rep(1:11, 14),
                 y = rep(1:14, each = 11),
                 group = sample(LETTERS[1:5], 154, replace = TRUE),
                 values1 = rnorm(154, mean = 10, sd = 5),
                 values2 = rnorm(154, mean = -10, sd = 2),
                 stringsAsFactors = FALSE)

geom_triangle()函数

ggmatrix提供了处理上下不一样的三角形热图的图层函数geom_triangle(),该函数与一般的geom_polygon()函数的区别是多了两个填充颜色映射属性fill.upperfill.lower,可以单独指定上下三角形的颜色映射。当然,为了符合一般geom_polygon()函数的使用习惯,我保留了fill参数,当设置fill时表示上下三角是同一的。

默认填充色(fill)为空,只画出上下三角形。

ggplot(df, aes(x = x, y = y)) + geom_triangle()

当设置fill参数时,表明把上下三角形当成一个整体来处理,映射颜色也完全相同。

ggplot(df, aes(x = x, y = y)) + geom_triangle(fill = "lightblue")

ggplot(df, aes(x = x, y = y)) + geom_triangle(aes(fill = values1))

既然要画上下三角不一样的热图,关键的当然就是怎么做到不一样。我们可以单独设置上下三角形的填充颜色。

## 设置上三角颜色为浅蓝色
ggplot(df, aes(x = x, y = y)) + geom_triangle(fill.upper = "lightblue")

## 设置上三角颜色为浅蓝色,且设置下三角颜色为橙色
ggplot(df, aes(x = x, y = y)) + 
  geom_triangle(fill.upper = "lightblue", fill.lower = "orange")

全都手动设置也太过于笨拙了吧,我们看看怎么处理上下三角的颜色映射。geom_triangle()可以单独设置上三角或者下三角映射,注意当把上下三角填充颜色映射给其它变量时,一定要同时加上对应的scale函数,我还不懂怎么添加默认映射

ggplot(df, aes(x = x, y = y, fill.upper = values1)) +
  geom_triangle() +
  scale_fill_upper_gradientn(colours = c("red", "white", "blue")) 

同时映射上下三角,是不是感觉不用ggnewscale或者relayer包的黑科技了,会爽很多。

ggplot(df, aes(x = x, y = y, fill.upper = values1, fill.lower = values2)) +
  geom_triangle(mode = "lb-rt") +
  scale_fill_upper_gradientn(colours = brewer.pal(5, "Greys")) +
  scale_fill_lower_gradientn(colours = brewer.pal(5, "YlGnBu"))

也可以映射离散变量。

ggplot(df, aes(x = x, y = y, fill.upper = group, fill.lower = values2)) +
  geom_triangle() +
  scale_fill_upper_manual(values = brewer.pal(5, "Set1")) +
  scale_fill_lower_gradientn(colours = c("#E9A3C9", "#F7F7F7", "#A1D76A"),
                             guide = guide_legend())

ggmatrix提供了五种颜色映射函数,每个函数的用法均和对应的原ggplot2中的函数相同。

  • scale_fill_lower/upper_gradient()——ggplot2scale_fill_gradient()

  • scale_fill_lower/upper_gradient2()——ggplot2scale_fill_gradient2()

  • scale_fill_lower/upper_gradientn()——ggplot2scale_fill_gradientn()

  • scale_fill_lower/upper_identity()——ggplot2scale_fill_identity()

  • scale_fill_lower/upper_manual()——ggplot2中`scale_fill_manual()

矩阵热图

之所以叫ggmatrix,主要是突出这个在做矩阵热图上的一些小优势,而产生优势的核心是matrixs_to_df()函数。划重点:现在的版本中,matrixs_to_df()函数的第一个参数是x需要是矩阵列表,当xdata.frame或者matrix时,自动转换为list,若是多多个矩阵,需要用list()进行包装。

matrixs_to_df(mtcars)
## # A tibble: 352 x 5
##    .rownames         .colnames    m1 .row.id .col.id
##  * <chr>             <chr>     <dbl>   <int>   <int>
##  1 Mazda RX4         mpg        21        32       1
##  2 Mazda RX4 Wag     mpg        21        31       1
##  3 Datsun 710        mpg        22.8      30       1
##  4 Hornet 4 Drive    mpg        21.4      29       1
##  5 Hornet Sportabout mpg        18.7      28       1
##  6 Valiant           mpg        18.1      27       1
##  7 Duster 360        mpg        14.3      26       1
##  8 Merc 240D         mpg        24.4      25       1
##  9 Merc 230          mpg        22.8      24       1
## 10 Merc 280          mpg        19.2      23       1
## # … with 342 more rows
m1 <- matrix(rnorm(20 * 20), ncol = 20)
m2 <- matrix(rnorm(20 * 20, mean = -10), ncol = 20)
m3 <- matrix(rnorm(20 * 20, mean = 12), ncol = 20)
matrixs_to_df(list(m1 = m1, m2 = m2, m3 = m3))
## # A tibble: 400 x 7
##    .rownames .colnames     m1     m2    m3 .row.id .col.id
##  * <chr>     <chr>      <dbl>  <dbl> <dbl>   <int>   <int>
##  1 row1      col1      -0.861  -9.13  13.7      20       1
##  2 row2      col1      -1.43  -12.5   13.1      19       1
##  3 row3      col1      -2.89  -10.7   13.2      18       1
##  4 row4      col1      -0.813  -9.41  10.6      17       1
##  5 row5      col1       0.782 -10.8   10.8      16       1
##  6 row6      col1      -0.286  -9.80  10.6      15       1
##  7 row7      col1       1.26  -11.6   11.8      14       1
##  8 row8      col1       0.295 -10.9   13.2      13       1
##  9 row9      col1      -0.300  -8.95  12.0      12       1
## 10 row10     col1       0.129 -10.5   11.9      11       1
## # … with 390 more rows

支持按照输入的第一个矩阵聚类。

matrixs_to_df(list(m1 = m1, m2 = m2, m3 = m3), cluster.type = "all")
## # A tibble: 400 x 7
##    .rownames .colnames      m1     m2    m3 .row.id .col.id
##  * <chr>     <chr>       <dbl>  <dbl> <dbl>   <int>   <int>
##  1 row2      col1      -1.43   -12.5   13.1      20       1
##  2 row3      col1      -2.89   -10.7   13.2      19       1
##  3 row4      col1      -0.813   -9.41  10.6      18       1
##  4 row10     col1       0.129  -10.5   11.9      17       1
##  5 row20     col1      -0.0939 -10.8   11.4      16       1
##  6 row6      col1      -0.286   -9.80  10.6      15       1
##  7 row8      col1       0.295  -10.9   13.2      14       1
##  8 row17     col1       0.835   -9.16  10.6      13       1
##  9 row9      col1      -0.300   -8.95  12.0      12       1
## 10 row14     col1       1.17   -11.3   11.9      11       1
## # … with 390 more rows
matrixs_to_df(list(m1 = m1, m2 = m2, m3 = m3), cluster.type = "row")
## # A tibble: 400 x 7
##    .rownames .colnames      m1     m2    m3 .row.id .col.id
##  * <chr>     <chr>       <dbl>  <dbl> <dbl>   <int>   <int>
##  1 row2      col1      -1.43   -12.5   13.1      20       1
##  2 row3      col1      -2.89   -10.7   13.2      19       1
##  3 row4      col1      -0.813   -9.41  10.6      18       1
##  4 row10     col1       0.129  -10.5   11.9      17       1
##  5 row20     col1      -0.0939 -10.8   11.4      16       1
##  6 row6      col1      -0.286   -9.80  10.6      15       1
##  7 row8      col1       0.295  -10.9   13.2      14       1
##  8 row17     col1       0.835   -9.16  10.6      13       1
##  9 row9      col1      -0.300   -8.95  12.0      12       1
## 10 row14     col1       1.17   -11.3   11.9      11       1
## # … with 390 more rows
matrixs_to_df(list(m1 = m1, m2 = m2, m3 = m3), cluster.type = "col")
## # A tibble: 400 x 7
##    .rownames .colnames     m1     m2    m3 .row.id .col.id
##  * <chr>     <chr>      <dbl>  <dbl> <dbl>   <int>   <int>
##  1 row1      col1      -0.861  -9.13  13.7      20       1
##  2 row2      col1      -1.43  -12.5   13.1      19       1
##  3 row3      col1      -2.89  -10.7   13.2      18       1
##  4 row4      col1      -0.813  -9.41  10.6      17       1
##  5 row5      col1       0.782 -10.8   10.8      16       1
##  6 row6      col1      -0.286  -9.80  10.6      15       1
##  7 row7      col1       1.26  -11.6   11.8      14       1
##  8 row8      col1       0.295 -10.9   13.2      13       1
##  9 row9      col1      -0.300  -8.95  12.0      12       1
## 10 row10     col1       0.129 -10.5   11.9      11       1
## # … with 390 more rows

当然,文本也是可以聚类的。

string.matrix <- matrix(sample(LETTERS[1:4], 100, replace = TRUE), nrow = 10)
matrixs_to_df(string.matrix, cluster.type = "all")
## # A tibble: 100 x 5
##    .rownames .colnames m1    .row.id .col.id
##  * <chr>     <chr>     <chr>   <int>   <int>
##  1 row2      col4      D          10       1
##  2 row7      col4      B           9       1
##  3 row3      col4      A           8       1
##  4 row9      col4      A           7       1
##  5 row8      col4      C           6       1
##  6 row1      col4      B           5       1
##  7 row4      col4      B           4       1
##  8 row6      col4      B           3       1
##  9 row5      col4      C           2       1
## 10 row10     col4      D           1       1
## # … with 90 more rows

也可以手动指定顺序。

row.order <- sample(1:20)
col.order <- sample(1:20)
matrixs_to_df(list(m1 = m1, m2 = m2, m3 = m3), 
              row.order = row.order, col.order = col.order)
## # A tibble: 400 x 7
##    .rownames .colnames     m1     m2    m3 .row.id .col.id
##  * <chr>     <chr>      <dbl>  <dbl> <dbl>   <int>   <int>
##  1 row8      col4      -2.48  -10.7   13.9      20       1
##  2 row4      col4      -0.351  -8.58  12.1      19       1
##  3 row9      col4      -0.397 -10.5   12.8      18       1
##  4 row13     col4       1.60   -9.12  10.5      17       1
##  5 row17     col4      -1.29   -8.73  12.8      16       1
##  6 row7      col4      -0.608  -9.21  11.0      15       1
##  7 row20     col4      -1.22  -11.6   11.2      14       1
##  8 row15     col4      -0.777 -12.2   12.7      13       1
##  9 row11     col4      -0.527  -8.89  12.0      12       1
## 10 row10     col4      -0.814 -10.8   11.1      11       1
## # … with 390 more rows

在传入矩阵时,推荐使用`list(name1 = mat1, name2 = mat2)的形式,其中列表的名字自动处理成转换后长数据的变量名。若没有指定,自动命名为m1,m2……

matrixs_to_df(mtcars)
## # A tibble: 352 x 5
##    .rownames         .colnames    m1 .row.id .col.id
##  * <chr>             <chr>     <dbl>   <int>   <int>
##  1 Mazda RX4         mpg        21        32       1
##  2 Mazda RX4 Wag     mpg        21        31       1
##  3 Datsun 710        mpg        22.8      30       1
##  4 Hornet 4 Drive    mpg        21.4      29       1
##  5 Hornet Sportabout mpg        18.7      28       1
##  6 Valiant           mpg        18.1      27       1
##  7 Duster 360        mpg        14.3      26       1
##  8 Merc 240D         mpg        24.4      25       1
##  9 Merc 230          mpg        22.8      24       1
## 10 Merc 280          mpg        19.2      23       1
## # … with 342 more rows
matrixs_to_df(list(kk = mtcars))
## # A tibble: 352 x 5
##    .rownames         .colnames    kk .row.id .col.id
##  * <chr>             <chr>     <dbl>   <int>   <int>
##  1 Mazda RX4         mpg        21        32       1
##  2 Mazda RX4 Wag     mpg        21        31       1
##  3 Datsun 710        mpg        22.8      30       1
##  4 Hornet 4 Drive    mpg        21.4      29       1
##  5 Hornet Sportabout mpg        18.7      28       1
##  6 Valiant           mpg        18.1      27       1
##  7 Duster 360        mpg        14.3      26       1
##  8 Merc 240D         mpg        24.4      25       1
##  9 Merc 230          mpg        22.8      24       1
## 10 Merc 280          mpg        19.2      23       1
## # … with 342 more rows

矩阵热图可视化

初始化函数是ggmat,可以直接把要可视化的矩阵列表丢进去,底层调用matrixs_to_df()函数转换成数据框,对于比较复杂的设置,建议先用matrixs_to_df()函数进行数据转换,然后把结果数据传递给ggmat(),这样不会让绘图过程显得过于复杂

简单情形

ggmat(mtcars)

ggmat(mtcars) + geom_tile(aes(fill = m1), colour = "grey90")

ggmat(mtcars) + geom_point(aes(size = m1, colour = m1))

ggmat(mtcars, cluster.type = "all") + 
  geom_tile(aes(fill = m1), colour = "grey90")

ggmat(string.matrix, cluster.type = "all") + 
  geom_tile(aes(fill = m1), colour = "grey90")

ggmat(mtcars, cluster.type = "all", tree.type = "all") + 
  geom_tile(aes(fill = m1), colour = "grey90") +
  theme_matrix()

ggmat(t(mtcars), cluster.type = "all", tree.type = "col", 
      col.tree.position = "bottom", col.tree.max.height = 50) + 
  geom_tile(aes(fill = m1), colour = "grey90") +
  remove_axis() +
  theme_matrix() +
  coord_polar()

添加其它辅助元素

geom_text()或者geom_label()可以添加数据标签。

library(ggcor)
ggmat(string.matrix, cluster.type = "all") + 
  geom_tile(aes(fill = m1), colour = "grey90") +
  geom_text(aes(label = m1))

m4 <- matrix(rnorm(81), nrow = 9)
df <- matrixs_to_df(list(value = m4))
ggmat(df) + 
  geom_tile(aes(fill = value), colour = "grey90") +
  geom_number(aes(num = value)) +
  scale_fill_gradient2n(limits = range(m4))

折腾了很久的ggcor现在用ggmatrix也可以很简单的实现,容我尴尬的笑一笑

cor <- correlate(mtcars, cor.test = TRUE)
ggmat(cor) + 
  geom_tile(aes(fill = r), colour = "grey90") +
  geom_mark(aes(p.value = p.value), r = NA) +
  scale_fill_gradient2n()