之前我们已经说过一些拼图的知识了:[[88-R可视化20-R的几种基于ggplot的拼图解决方案]] [[89-R可视化21-利用aplot拼图实现类似热图注释柱效果]] [[119-R可视化37-利用循环实现ggplot批量作图并拼图]]
最近有同学在后台向我提问,如何能够把原本拼图的间隙调小一些。
忽然想到了很多话题以及知识点,今天正好分享一下。
这里直接用iris 数据集,并且为了表现每个ggplot 对象的边界,我再边上加了一个黑框:
p1 <- ggplot(iris) + geom_point(aes(Sepal.Length,
Sepal.Width)) +
theme(legend.position = "none",
plot.background = element_rect(color = "gray30"))
p1 / p1 / p1
这里我就以最熟悉的patchwork 的方法举例了。
也就是借助行列调整,亦或是design 的参数,调整所有图在画布上的比例,比如:
p_list <- lapply(1:4, function(x) {p1})
design <- "
122
1#3
443
"
p2 <- wrap_plots(p_list, design = design)
p2
这里design 可以搞定,非常容易。
可是,大部分的拼图语法,考虑的仅仅是各个图形的排列,以及它们长宽的相对大小。
如果是间隙呢?
可以看到,以独立ggplot 为对象的内容,其本身就是紧密相连的:
我们可不可以把它们上下左右,向四周拉开呢?也就是让每张图之间存在一点间隙?
搜寻了一圈,发现无论是patchwork 亦或是cowplot,都没有提供比较方便的,设定间隙的参数。
或许我们可以通过分配给四张图相同的width 和heights,再把小的给空白?
design <- "
1#2
###
3#4
"
wrap_plots(p_list, widths = c(6,1,6),
heights = c(6,1,6), design = design)
但图片一多,比如4x4,处理design 又是一个烦心事。
除了设定design外,还可以通过创建空对象的方式,将其按照某种规则与其他图像排列。
比如我们有:
我们可不可以不借助design,手动插入这些空隙呢?
比如我们创建NULL 或者空的ggplot()
白版。
接着,我们需要在 1x2 1x2 的位置加入这些白板,形成空隙的视觉。而且它需要按照顺序插入到我们用于排列的列表对象中。并且,我们还需要在指定位置设置设置好他们的witdh 与height。
如果是3 x 3 呢?
情况只会更加复杂。
由此看来,还不如通过design 设定。
如之前图所示:
如果是去掉axis 的text 与title,patchwork 还可以“紧紧” 地把图片压在一块吗?
(p1 <- ggplot(iris) + geom_point(aes(Sepal.Length,
Sepal.Width)) +
theme(legend.position = "none",
plot.background = element_rect(color = "gray30"),
axis.title = element_blank(),
axis.text.x = element_blank()))
p_list <- lapply(1:4, function(x) {p1})
wrap_plots(p_list,nrow = 4)
思考了一下,逐渐还原了粉丝的问题:
如果是让各自保留的这一点点空隙也不需要呢?
想到aplot 拼图是可以非常紧密的拼接(毕竟是设计于热图的注释柱的):
p1 %>% insert_bottom(p1) %>%
insert_bottom(p1) %>%
insert_bottom(p1)
间隙就没有啦。
如果是 2x2 的图片,并不能很好的操作:
pn1 <- p1 %>% insert_right(p1)
pn2 <- p1 %>% insert_right(p1)
insert_bottom(.data = pn1, pn2)
Error in x$plotlist[[i]] + xlim2(mp) : 二进列运算符中有非数值参数
因为aplot 针对的是某个图的上下左右:
p1 %>% insert_right(p1) %>%
insert_left(p1) %>%
insert_bottom(p1)
如果是长宽分别1 的情况下,aplot 还是蛮好用的。
如果是9 个图呢?重复使用管道?实在是不够优雅。
试试看递归:
p_list <- lapply(1:8, function(x) {p1})
multi_Aplot <- function(x){
if(x == 1){
return(p_list[[1]])
}
return(multi_Aplot(x-1) %>% insert_bottom(p_list[[x]]))
}
multi_Aplot(8)
无论是压缩保留的间隙,亦或是增大间隙,grid 都是可以自定义调整。
我们只需要设置viewport
函数,选定对应画布位置作图即可:
pushViewport(viewport(x = 0, y = 0,
width = 1, height = 0.25,
just = c("left", "bottom")))
print(p1, newpage = F)
popViewport()
pushViewport(viewport(x = 0, y = 0.25,
width = 1, height = 0.25,
just = c("left", "bottom")))
print(p1, newpage = F)
值得注意的是,默认下的ggplot 对象,其边缘就是会存在一些空白的:
因此我们需要适当地让它们大一点。
但问题却是,因为每个对象其本身存在空白边缘,其他的空白边缘就会遮盖下方图形的内容:
如果是图与图之间想要达到aplot 的空隙效果,则必然会出现上图的结果。
那么aplot 那种贴合的作图方法是怎么做到的呢?手撕一下源码?
有没有更加优雅的拼图间隙控制的方法呢?欢迎后台告诉我哦。