厚缊

诹图——ggcor简介(十二)

厚缊 / 2020-03-19


这篇文章是给science的组合图结个尾,讲讲怎么控制更多的细节,从内容上说可能会分成两个大的模块,一部分主要讲单独绘制这个连接线部分的图如何控制,另一部分则主要在组合图的环境中如何控制,前者是基础,后面的就是在这个基础上结合一点ggcor的细节。

安装

若后续代码运行不成功,自行检查版本号。

## install.packages("devtools)
devtools::install_github("houyunhuang/ggcor") 
## 安装过老版本的加 force = TRUE 参数
packageVersion("ggcor")
## [1] '0.9.4.3'

额外属性映射

上一期中,我们主要解释了如何把图做出来,这一篇主要目标是把图做好看,而且能反应更多的信息。

对于这样的连接图(类似于网络图),我们一般就是处理边的颜色、粗细和线型,和边相关的都可以在geom_link()中设置,和节点(或者说端点)相关的都是在geom_*_point()里面设置。看个简单的例子:

library(ggcor)
library(ggplot2)
data("varespec", package = "vegan")
data("varechem", package = "vegan")

correlate(varespec[1:20], varechem, cor.test = TRUE) %>% 
  as_cor_tbl() %>% 
  parallel_layout() %>% 
  ggplot() + 
  geom_link(aes(colour = r, size = r, linetype = r < 0), 
            data = function(data) filter(data, 
                                         abs(r) > 0.5, p.value < 0.05)) +
  geom_start_point(fill = "red", shape = 23, size = 4) +
  geom_end_point(fill = "blue", shape = 21, size = 4) +
  geom_start_label(aes(x = x - 0.05), hjust = 1, size = 5) +
  geom_end_label(aes(x = xend + 0.05), hjust = 0, size = 5) +
  scale_size_area(max_size = 2,
                  breaks = c(0.6, 0.3, -0.3, -0.6)) +
  scale_color_viridis_c() +
  scale_linetype_manual(values = c("TRUE" = "dashed", "FALSE" = "solid")) +
  guides(linetype = guide_legend(order = 1, override.aes = list(size = 2)),
         size = guide_legend(order = 2),
         colour = guide_colorbar(order = 3)) +
  coord_cartesian(xlim = c(-0.2, 1.2)) +
  theme_void()

当然,完全可以事先把没有边连接的节点全部过滤掉。

correlate(varespec[1:20], varechem, cor.test = TRUE) %>% 
  as_cor_tbl() %>% 
  filter(abs(r) > 0.5, p.value < 0.05) %>% 
  parallel_layout() %>% 
  ggplot() + 
  geom_link(aes(colour = r, size = r, linetype = r < 0),
            curvature = 0.08) +
  geom_start_point(fill = "red", shape = 23, size = 4) +
  geom_end_point(fill = "red", shape = 21, size = 4) + 
  geom_start_label(aes(x = x - 0.05), hjust = 1, size = 5) +
  geom_end_label(aes(x = xend + 0.05), hjust = 0, size = 5) +
  scale_size_area(max_size = 2,
                  breaks = c(0.6, 0.3, -0.3, -0.6)) +
  scale_color_viridis_c() +
  scale_linetype_manual(values = c("TRUE" = "dashed", "FALSE" = "solid")) +
  guides(linetype = guide_legend(order = 1, override.aes = list(size = 2)),
         size = guide_legend(order = 2),
         colour = guide_colorbar(order = 3)) +
  coord_cartesian(xlim = c(-0.2, 1.2)) +
  theme_void()

vegan包里面的这两个数据集太辣鸡了,做出来不忍直视,有兴趣用自己的数据测试下效果,你也可以把节点的点(Point)变成矩形堆叠在一起(类似于堆叠柱状图)。

组合图

ggcor提供这两种模式的图,都是为了更好的和相关性组合在一起,这样能更好的展示信息。我们先看平行坐标:

mantel <- mantel_test(varespec, varechem,
                      spec.select = list(Spec01 = 1:7,
                                         Spec02 = 8:18,
                                         Spec03 = 19:37,
                                         Spec04 = 38:44)) %>% 
  parallel_layout(start.var = env, end.var = spec,
                  start.x = 15, end.x = 20, stretch = FALSE) %>% 
  mutate(rd = cut(r, breaks = c(-Inf, 0.2, 0.4, Inf),
                  labels = c("< 0.2", "0.2 - 0.4", ">= 0.4")),
         pd = cut(p.value, breaks = c(-Inf, 0.01, 0.05, Inf),
                  labels = c("< 0.01", "0.01 - 0.05", ">= 0.05")))
corr <- fortify_cor(varechem, cor.test = TRUE)

## 先关闭映射继承
options(ggcor.link.inherit.aes = FALSE)
quickcor(corr) + geom_square() +
  geom_link(aes(colour = pd, size = rd), data = mantel) +
  geom_link_point(data = mantel) +
  geom_end_label(aes(x = xend + 0.5), hjust = 0, data = mantel) +
  scale_size_manual(values = c(0.5, 1, 2)) +
  scale_colour_manual(values = c("#D95F02", "#1B9E77", "#A2A2A288")) +
  guides(size = guide_legend(title = "Mantel's r",
                             override.aes = list(colour = "grey35"), 
                             order = 2),
         colour = guide_legend(title = "Mantel's p", 
                               override.aes = list(size = 3), 
                               order = 1),
         fill = guide_colorbar(title = "Pearson's r", order = 3)) +
  expand_axis(x = 23)

当你把平行坐标情况下组合想明白了,在上下三角的情况下几乎一模一样,无外乎就是在计算坐标的时候的方法变了。有几个小问题是需要根据自己的数据调整的:第一个是quickcor()的坐标范围都是根据相关系数矩阵热图自动调整的,但是加上这个表达mantel 检验信息的内容后明显会溢出原范围,需要自己手动来用expand_axis()函数扩展坐标范围;第二个是要出漂亮的图,当然得靠自己用ggplot2的机制一点点的去调整了。

corr2 <- get_upper_data(corr) ## 只能是上下三角 我们保留上三角
mantel <- mantel_test(varespec, varechem,
                      spec.select = list(Spec01 = 1:7,
                                         Spec02 = 8:18,
                                         Spec03 = 19:37,
                                         Spec04 = 38:44)) %>% 
  combination_layout(cor_tbl = corr2) %>% 
  mutate(xend = xend + 1,
         rd = cut(r, breaks = c(-Inf, 0.2, 0.4, Inf),
                  labels = c("< 0.2", "0.2 - 0.4", ">= 0.4")),
         pd = cut(p.value, breaks = c(-Inf, 0.01, 0.05, Inf),
                  labels = c("< 0.01", "0.01 - 0.05", ">= 0.05")))

## 先关闭映射继承
options(ggcor.link.inherit.aes = FALSE)
quickcor(corr2) + geom_square() +
  geom_link(aes(colour = pd, size = rd), data = mantel,
            curvature = 0.05) +
  geom_link_point(data = mantel) +
  geom_start_label(aes(x = x - 0.5), hjust = 1, data = mantel) +
  scale_size_manual(values = c(0.5, 1, 2)) +
  scale_colour_manual(values = c("#D95F02", "#1B9E77", "#A2A2A288")) +
  guides(size = guide_legend(title = "Mantel's r",
                             override.aes = list(colour = "grey35"), 
                             order = 2),
         colour = guide_legend(title = "Mantel's p", 
                               override.aes = list(size = 3), 
                               order = 1),
         fill = guide_colorbar(title = "Pearson's r", order = 3)) +
  expand_axis(x = -6)

过滤不显著的连接

最近有个问题出现的频率比较高,这个问题应该要分开考虑,在平行坐标中若是完全不展示不显著的点,也不做组合图,可以在计算完cor_tbl之后直接过滤,然后处理坐标,若是还想展现节点信息,你需要在作图的时候(也就是geom_link())中去过滤,这个时候不影响节点;对于上下三角的组合图,本质上你在哪个阶段过滤都行。

mantel <- mantel_test(varespec, varechem,
                      spec.select = list(Spec01 = 1:7,
                                         Spec02 = 8:18,
                                         Spec03 = 19:37,
                                         Spec04 = 38:44)) %>% 
  combination_layout(cor_tbl = corr2) %>% 
  mutate(xend = xend + 1,
         rd = cut(r, breaks = c(-Inf, 0.2, 0.4, Inf),
                  labels = c("< 0.2", "0.2 - 0.4", ">= 0.4")),
         pd = cut(p.value, breaks = c(-Inf, 0.01, Inf),
                  labels = c("< 0.01", "0.01 - 0.05")))

quickcor(corr2) + geom_square() +
  geom_link(aes(colour = pd, size = rd), 
            data = filter(mantel, p.value < 0.05), curvature = 0.05) +
  geom_link_point(data = mantel) +
  geom_start_label(aes(x = x - 0.5), hjust = 1, data = mantel) +
  scale_size_manual(values = c(0.5, 1, 2)) +
  scale_colour_manual(values = c("#D95F02", "#1B9E77")) +
  guides(size = guide_legend(title = "Mantel's r",
                             override.aes = list(colour = "grey35"), 
                             order = 2),
         colour = guide_legend(title = "Mantel's p", 
                               override.aes = list(size = 3), 
                               order = 1),
         fill = guide_colorbar(title = "Pearson's r", order = 3)) +
  expand_axis(x = -6)

难道非得组合?

原来的都是非得组合,现在不组合我感觉也很好看。

mantel_test(varespec, varechem,
            spec.select = list(Spec01 = 1:7,
                               Spec02 = 8:18,
                               Spec03 = 19:37,
                               Spec04 = 38:44)) %>% 
  combination_layout(cor_tbl = corr2) %>% 
  mutate(xend = xend + 1,
         rd = cut(r, breaks = c(-Inf, 0.2, 0.4, Inf),
                  labels = c("< 0.2", "0.2 - 0.4", ">= 0.4")),
         pd = cut(p.value, breaks = c(-Inf, 0.01, 0.05, Inf),
                  labels = c("< 0.01", "0.01 - 0.05", ">= 0.05"))) %>% 
ggplot() +
  geom_link(aes(colour = pd, size = rd), curvature = 0.1) +
  geom_link_point() +
  geom_start_label(aes(x = x - 0.5), hjust = 1) +
  geom_end_label(aes(x = xend + 0.5), hjust = 0) +
  scale_size_manual(values = c(0.5, 1, 2)) +
  scale_colour_manual(values = c("#D95F02", "#1B9E77", "#A2A2A288")) +
  guides(size = guide_legend(title = "Mantel's r",
                             override.aes = list(colour = "grey35"), 
                             order = 2),
         colour = guide_legend(title = "Mantel's p", 
                               override.aes = list(size = 3), 
                               order = 1)) +
  coord_fixed(xlim = c(-5, 15)) +
  theme_void() +
  theme(legend.position = c(0.75, 0.7))

小结

这么久的更新,终于把这个部分结束战斗了,后续我们可能会把procrutes 检验加进来,作为mantel检验的一种替代。最后说一句,在前面平行坐标组合图的例子可能埋了雷,但是都是可以解决的,遇到了先自己摸索下。提示:若你打乱过数据的顺序,可能出现对不上的情况,但是这个问题不会出现在上下三角的组合图中。