技巧 | 如何使用R语言的基础绘图系统的拼图功能

我们知道ggplot2工具包有很多方便的拼图拓展包,如cowplotpatchwork等,而本篇就来介绍在使用R语言的基础绘图系统如何进行拼图。需要明确的是,基础绘图系统的拼图功能不需要借助任何其他的工具包,而且它是通过参数而非函数来实现这一功能的。

基础绘图系统拼图主要有两种方法:

  • 第一种方法比较常见且易于操作,是在par函数中对mfrow或者mfcol参数进行设置,这种方式实际上实现的是分子图的功能,各子图之间相互独立;

  • 第二种方法需要同时对par函数的figpltnew三个参数进行设置来实现,使用比较灵活但要经过多次试验才能得到较佳的效果,它主要用来实现组图功能,即将几个相互联系的图形通过合理布局形成一个整体。

本篇主要介绍第二种方法,不过在此之前需要先通过第一种方法来介绍下基础绘图系统中的四种边框概念。

1 基础绘图系统中的四种边框

在推文graphics | 基础绘图系统(二)—— 绘图参数及par函数中有如下示意图:

上图中红色字体对应的就是四种边框,在只有单个图形的图片中:

  • 外边框(outer  margin)与图片边界相重合,是不能变化位置的;

  • 内边框(inner margin)的位置决定了图片的页面距大小;

  • 图形边框(figure margin)和绘图区边框(plot side)之间用于放置坐标轴刻度、标签、图形标题等要素;

  • 绘图区边框内用于绘制几何图形。

实际上,这种情况下,inner margin和figure margin根本没有区分的必要。在默认状况下,outer、inner、figure margin三种边框是重合的。

但在有子图的情况下,inner margin和figure margin的区别就体现出来了,前者是整幅图的内边框,而后者相当于各子图的外边框。

box函数可以在绘图时显示各类边框,该函数在推文graphics | 基础绘图系统(五)——plot函数功能再探和低级绘图函数中有所介绍。

par(mfrow = c(2,2))
plot(1:5)
par("fig")

plot(1:5)
par("fig")

plot(1:5)
par("fig")

plot(1:5)
par("fig")

box("fig", col = "red")
box("inner", col = "blue")
  • 红色边框为子图的figure margin,蓝色边框为整副图的inner margin(默认与outer margin重合)。

# 四次par("fig)的输出结果

## [1] 0.0 0.5 0.5 1.0
## [1] 0.5 1.0 0.5 1.0
## [1] 0.0 0.5 0.0 0.5
## [1] 0.5 1.0 0.0 0.5
  • 从输出结果可以看出,子图的位置可以通过fig参数控制。

了解以上边框概念后,我们就可以通过手动设置fig参数来进行组图了。在图形的基础上在叠加新图形也有两种途径:

学习本推文接下来的内容前,请务必先阅读以下推文尤其是“布局参数”部分,以了解各参数的含义:

2 待拼图子图形介绍

绘图案例来自Nature Communications期刊上一篇论文:

  • Burke, M., González, F., Baylis, P. et al. Higher temperatures increase suicide rates in the United States and Mexico. Nature Clim Change 8, 723–729 (2018). https://doi.org/10.1038/s41558-018-0222-x

原图如下:

该图由一幅地图和两幅直方图组成。在作者提供的原代码中只是单独绘制了这三幅图形,并没有提供组图的代码。本文尝试对其进行组装。

原代码对数据的处理过程比较复杂,这里将最终的处理结果作为示例数据(需要数据的读者请在公众号后台发送关键词“示例数据”获取):

library(tidyverse)
library(sf)
load("38-2.usa.rdata")
load("38-3.mex.rdata")
load("38-4.colhist1.rdata")
load("38-5.colhist2.rdata")
usa_siggy <- filter(usa, siggy == T)
mex_siggy <- filter(mex, siggy == T)

论文作者绘制地图的代码的简化版:

plot(st_geometry(usa), col = usa$color,
     lwd = 0.025, border = NA,
     xlim = c(-125, -66), ylim = c(17, 47))
plot(st_geometry(mex), col = mex$color,
     lwd = 0.025, border = NA, add = T)
plot(st_geometry(usa_siggy), add = T, lwd = 1.5)
plot(st_geometry(mex_siggy), add = T, lwd = 1.5)

关于使用plot函数绘制地图的方法,本号已有两篇相关推文,这里不再赘述:

论文作者绘制两幅直方图的代码的简化版:

# 直方图1
hist(usa$plotValue, breaks = seq(-4.5, 7, 0.5),
     col = colhist1, axes = F, xlim = c(-10, 10),
     xlab = "", ylab = "", main = "")
axis(1, tick = F, line = -0.5, 
     labels = seq(-3, 3, 1),
     at = seq(-3, 3, 1) - 0.25)
# 直方图2
hist(mex$plotValue, breaks = c(-15, seq(-4.5, 7, 0.5),15),
     col = colhist2, axes = F,  xlim = c(-10, 10),
     xlab = "", ylab = "", main = "")
axis(1, tick = F, line = -0.5,
     labels = seq(-10, 10, 1),
     at =seq(-10, 10, 1) - 0.25)

hist函数绘制直方图的方法见以下推文:

3 拼图过程

首先根据各子图的位置和大小对fig参数进行粗略的设置,从第二幅子图开始还需要设置new参数。

为了更好观察各子图之间的位置关系,可以使用box函数显示出子图的plot和figure边框,这里对不同子图的边框赋予不同的颜色加以区分。

此外,fig参数的设置还依赖于导出图片的尺寸,因此图片尺寸需要提前确定。导出图片及其尺寸确定的方法见以下推文:

关键设置见下列代码中的行注释:

jpeg("38-6.jpeg", width = 10, height = 6,
     units = "in", res = 600)
# 地图
par(fig = c(0.05, 0.8, 0.05, 0.95)) # 设置fig参数
plot(st_geometry(usa), col = usa$color,
     lwd = 0.025, border = NA,
     xlim = c(-125, -66), ylim = c(17, 47))
plot(st_geometry(mex), col = mex$color,
     lwd = 0.025, border = NA, add = T)
plot(st_geometry(usa_siggy), add = T, lwd = 1.5)
plot(st_geometry(mex_siggy), add = T, lwd = 1.5)
box(col = "red") # 添加plot边框
box("fig", col = "red") # 添加fig边框
# 直方图1
par(fig = c(0.7, 0.95, 0.5, 0.95),
    new = T) # 设置fig和new参数
hist(usa$plotValue, breaks = seq(-4.5, 7, 0.5),
     col = colhist1, axes = F, xlim = c(-10, 10),
     xlab = "", ylab = "", main = "")
axis(1, tick = F, line = -0.5, 
     labels = seq(-3, 3, 1),
     at = seq(-3, 3, 1) - 0.25)
box(col = "green") # 添加plot边框
box("fig", col = "green")
# 直方图2
par(fig = c(0.5, 0.95, 0.05, 0.5),
    new = T) # 设置fig和new参数
hist(mex$plotValue, breaks = c(-15, seq(-4.5, 7, 0.5),15),
     col = colhist2, axes = F,  xlim = c(-10, 10),
     xlab = "", ylab = "", main = "")
axis(1, tick = F, line = -0.5,
     labels = seq(-10, 10, 1),
     at =seq(-10, 10, 1) - 0.25)
box(col = "blue") # 添加plot边框
box("fig", col = "blue") # 添加fig边框
box("outer") # 添加外边框
dev.off()

从上面的草图中可以看出,地图和直方图都未能充分利用各自的图形区域,因此需要对plt参数进行设置。

  • 地图的figure和plot边框之间没有其他要素,因此可以使二者重合,即设置plt = c(0, 1, 0, 1)

  • 直方图的figure和plot边框底部间隙需要放置刻度标签,因此需要留出空间,设置plt = c(0, 1, 0.2, 0.8)

  • 直方图位置可以适当往左和中间靠近,需要对相应的fig参数作略微调整。

关键设置见下列代码中的行注释:

jpeg("38-7.jpeg", width = 10, height = 6,
     units = "in", res = 600)
# 地图
par(fig = c(0.05, 0.8, 0.05, 0.95),
    plt = c(0, 1, 0, 1)) # 设置plt参数
plot(st_geometry(usa), col = usa$color,
     lwd = 0.025, border = NA,
     xlim = c(-125, -66), ylim = c(17, 47))
plot(st_geometry(mex), col = mex$color,
     lwd = 0.025, border = NA, add = T)
plot(st_geometry(usa_siggy), add = T, lwd = 1.5)
plot(st_geometry(mex_siggy), add = T, lwd = 1.5)
box(col = "red")
box("fig", col = "red")
# 直方图1
par(fig = c(0.6, 0.95, 0.5, 0.9), new = T,
    plt = c(0, 1, 0.2, 0.8)) # 调整fig参数和设置plt参数
hist(usa$plotValue, breaks = seq(-4.5, 7, 0.5),
     col = colhist1, axes = F, xlim = c(-10, 10),
     xlab = "", ylab = "", main = "")
axis(1, tick = F, line = -0.5, 
     labels = seq(-3, 3, 1),
     at = seq(-3, 3, 1) - 0.25)
box(col = "green")
box("fig", col = "green")
# 直方图2
par(fig = c(0.55, 0.95, 0.1, 0.5), new = T,
    plt = c(0, 1, 0.2, 0.8)) # 调整fig参数和设置plt参数
hist(mex$plotValue, breaks = c(-15, seq(-4.5, 7, 0.5),15),
     col = colhist2, axes = F,  xlim = c(-10, 10),
     xlab = "", ylab = "", main = "")
axis(1, tick = F, line = -0.5,
     labels = seq(-10, 10, 1),
     at =seq(-10, 10, 1) - 0.25)
box(col = "blue")
box("fig", col = "blue")
box("outer")
dev.off()

上图的布局已经基本合理,再做以下调整:

关键设置见下列代码中的行注释:

jpeg("38-8.jpeg", width = 10, height = 6,
     units = "in", res = 600)
# 地图
par(fig = c(0, 0.8, 0.05, 0.95),
    plt = c(0, 1, 0, 1)) # fig的第一个元素改为0
plot(st_geometry(usa), col = usa$color,
     lwd = 0.025, border = NA,
     xlim = c(-125, -66), ylim = c(17, 47))
plot(st_geometry(mex), col = mex$color,
     lwd = 0.025, border = NA, add = T)
plot(st_geometry(usa_siggy), add = T, lwd = 1.5)
plot(st_geometry(mex_siggy), add = T, lwd = 1.5)
# 直方图1
par(fig = c(0.6, 0.95, 0.5, 0.9), new = T,
    plt = c(0, 1, 0.2, 0.8))
hist(usa$plotValue, breaks = seq(-4.5, 7, 0.5),
     col = colhist1, axes = F, xlim = c(-10, 10),
     xlab = "", ylab = "", main = "")
axis(1, tick = F, line = -0.5, 
     labels = seq(-3, 3, 1),
     at = seq(-3, 3, 1) - 0.25)
mtext("United States", side = 4, line = -5, las = 1) # 添加文本
mtext("Percentage change in suicide \n rate per C",
     side = 1, line = 3, las = 1) # 添加文本
# 直方图2
par(fig = c(0.55, 0.95, 0.1, 0.5), new = T,
    plt = c(0, 1, 0.2, 0.8))
hist(mex$plotValue, breaks = c(-15, seq(-4.5, 7, 0.5),15),
     col = colhist2, axes = F,  xlim = c(-10, 10),
     xlab = "", ylab = "", main = "")
axis(1, tick = F, line = -0.5,
     labels = seq(-10, 10, 1),
     at =seq(-10, 10, 1) - 0.25)
mtext("Mexico", side = 4, line = -4, las = 1) # 添加文本
mtext("Percentage change in suicide rate per C",
     side = 1, line = 2, las = 1) # 添加文本
box("outer")
dev.off()

至此基本复原了论文中的原图。

本号至今已经有多篇集中介绍基础绘图系统的基本语法的推文了,详细可点击话题标签“制表与可视化专辑”查看。本篇是在这些推文基础上的技巧应用。

读者可以根据需要先学习下相关的历史推文,或者直接练习一下本篇的案例。示例数据请在公众号后台发送关键词“示例数据”获取。


往期推荐阅读:

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值