前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >120-R可视化38-尝试控制拼图的间隙

120-R可视化38-尝试控制拼图的间隙

作者头像
北野茶缸子
发布2022-04-05 15:42:36
发布2022-04-05 15:42:36
2.8K10
代码可运行
举报
运行总次数:0
代码可运行

前言

之前我们已经说过一些拼图的知识了:[[88-R可视化20-R的几种基于ggplot的拼图解决方案]] [[89-R可视化21-利用aplot拼图实现类似热图注释柱效果]] [[119-R可视化37-利用循环实现ggplot批量作图并拼图]]

最近有同学在后台向我提问,如何能够把原本拼图的间隙调小一些。

忽然想到了很多话题以及知识点,今天正好分享一下。

这里直接用iris 数据集,并且为了表现每个ggplot 对象的边界,我再边上加了一个黑框:

代码语言:javascript
代码运行次数:0
复制
p1 <- ggplot(iris) + geom_point(aes(Sepal.Length,
                              Sepal.Width)) + 
  theme(legend.position = "none",
        plot.background = element_rect(color = "gray30"))
p1 / p1 / p1

1-如果是一般的布局

这里我就以最熟悉的patchwork 的方法举例了。

也就是借助行列调整,亦或是design 的参数,调整所有图在画布上的比例,比如:

代码语言:javascript
代码运行次数:0
复制
p_list <- lapply(1:4, function(x) {p1})
design <- "
  122
  1#3
  443
"
p2 <- wrap_plots(p_list, design = design)
p2

这里design 可以搞定,非常容易。

可是,大部分的拼图语法,考虑的仅仅是各个图形的排列,以及它们长宽的相对大小。

如果是间隙呢?

2-间隙可长,可短吗?

通过design设定

可以看到,以独立ggplot 为对象的内容,其本身就是紧密相连的:

我们可不可以把它们上下左右,向四周拉开呢?也就是让每张图之间存在一点间隙?

搜寻了一圈,发现无论是patchwork 亦或是cowplot,都没有提供比较方便的,设定间隙的参数。

或许我们可以通过分配给四张图相同的width 和heights,再把小的给空白?

代码语言:javascript
代码运行次数:0
复制
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 还可以“紧紧” 地把图片压在一块吗?

代码语言:javascript
代码运行次数:0
复制
(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)

思考了一下,逐渐还原了粉丝的问题:

如果是让各自保留的这一点点空隙也不需要呢?

3-让元素各自保留的间隙也删除

尝试aplot

想到aplot 拼图是可以非常紧密的拼接(毕竟是设计于热图的注释柱的):

代码语言:javascript
代码运行次数:0
复制
p1 %>% insert_bottom(p1) %>%
  insert_bottom(p1) %>% 
  insert_bottom(p1)

间隙就没有啦。

如果是 2x2 的图片,并不能很好的操作:

代码语言:javascript
代码运行次数:0
复制
pn1 <- p1 %>% insert_right(p1) 
pn2 <- p1 %>% insert_right(p1) 
insert_bottom(.data = pn1, pn2)
Error in x$plotlist[[i]] + xlim2(mp) : 二进列运算符中有非数值参数

因为aplot 针对的是某个图的上下左右:

代码语言:javascript
代码运行次数:0
复制
p1 %>% insert_right(p1) %>%
  insert_left(p1) %>% 
  insert_bottom(p1)

如果是长宽分别1 的情况下,aplot 还是蛮好用的。

如果是9 个图呢?重复使用管道?实在是不够优雅。

使用递归结合aplot

试试看递归:

代码语言:javascript
代码运行次数:0
复制
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自行调整

无论是压缩保留的间隙,亦或是增大间隙,grid 都是可以自定义调整。

我们只需要设置viewport 函数,选定对应画布位置作图即可:

代码语言:javascript
代码运行次数:0
复制
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 那种贴合的作图方法是怎么做到的呢?手撕一下源码?

有没有更加优雅的拼图间隙控制的方法呢?欢迎后台告诉我哦。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-03-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 北野茶缸子 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 1-如果是一般的布局
  • 2-间隙可长,可短吗?
    • 通过design设定
    • 添加空的元素增加间隙
    • 间隙可短吗?
  • 3-让元素各自保留的间隙也删除
    • 尝试aplot
    • 使用递归结合aplot
    • grid自行调整
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档