Closed ixxmu closed 3 hours ago
分面(facet)是ggplot2
的一个常用功能,当绘制的指标过多时,我们可以利用facet函数分类绘图,使得数据展示完整且美观。
本文使用R内置数据集mpg进行演示,该数据集包含11个变量,包括汽车的品牌、型号、车型、发动机排量、气缸数量、马力、重量、加速度、型号年份、产地和燃油经济性能等。以下是每个变量的详细说明:
library(ggplot2)
mpg$manufacturer <- factor(mpg$manufacturer,levels = unique(mpg$manufacturer))
mpg$model <- factor(mpg$model,levels = unique(mpg$model))
mpg$trans <- factor(mpg$trans,levels = unique(mpg$trans))
mpg$drv <- factor(mpg$drv,levels = unique(mpg$drv))
mpg$fl <- factor(mpg$fl,levels = unique(mpg$fl))
mpg$class <- factor(mpg$class,levels = unique(mpg$class))
summary(mpg)
# manufacturer model displ year cyl
# dodge :37 caravan 2wd : 11 Min. :1.600 Min. :1999 Min. :4.000
# toyota :34 ram 1500 pickup 4wd: 10 1st Qu.:2.400 1st Qu.:1999 1st Qu.:4.000
# volkswagen:27 dakota pickup 4wd : 9 Median :3.300 Median :2004 Median :6.000
# ford :25 mustang : 9 Mean :3.472 Mean :2004 Mean :5.889
# chevrolet :19 civic : 9 3rd Qu.:4.600 3rd Qu.:2008 3rd Qu.:8.000
# audi :18 jetta : 9 Max. :7.000 Max. :2008 Max. :8.000
# (Other) :74 (Other) :177
# trans drv cty hwy fl class
# auto(l4) :83 f:106 Min. : 9.00 Min. :12.00 p: 52 compact :47
# manual(m5):58 4:103 1st Qu.:14.00 1st Qu.:18.00 r:168 midsize :41
# auto(l5) :39 r: 25 Median :17.00 Median :24.00 e: 8 suv :62
# manual(m6):19 Mean :16.86 Mean :23.44 d: 5 2seater : 5
# auto(s6) :16 3rd Qu.:19.00 3rd Qu.:27.00 c: 1 minivan :11
# auto(l6) : 6 Max. :35.00 Max. :44.00 pickup :33
# (Other) :13 subcompact:35
head(mpg)
# A tibble: 6 × 11
## manufacturer model displ year cyl trans drv cty hwy fl class
# <fct> <fct> <dbl> <int> <int> <fct> <fct> <int> <int> <fct> <fct>
#1 audi a4 1.8 1999 4 auto(l5) f 18 29 p compact
#2 audi a4 1.8 1999 4 manual(m5) f 21 29 p compact
#3 audi a4 2 2008 4 manual(m6) f 20 31 p compact
#4 audi a4 2 2008 4 auto(av) f 21 30 p compact
#5 audi a4 2.8 1999 6 auto(l5) f 16 26 p compact
#6 audi a4 2.8 1999 6 manual(m5) f 18 26 p compact
我们看一个简单的例子:使用R内置数据集mpg查看displ(发动机排量)与hwy(高速公路里程)的相关性:
library(ggplot2)
library(patchwork)
library(ggpubr)
p1 <- ggplot(mpg, aes(displ, hwy)) +
geom_point(size = 3,col = "#88c4e8") +
labs(x = "Engine displacement", y = "Highway miles per gallon") +
guides(colour = "none") + theme_bw(base_size = 18) +
stat_cor(aes(label = paste(..r.label.., ..p.label.., sep = '~`,`~')),
method = 'spearman',
label.x.npc = 'left', label.y.npc = 'top', size = 6)
如果我们想分别检查不同class(车型)中这一相关性是否依然存在,那就可以按照class分面,这样就不用提取数据分别绘图。
p2 <- p1 + facet_wrap(~ class)
可以看到初始图中的点按照class拆分为多个子图,以上每个子图对应顶部标签所示分组。
下面我们开始系统记录一下ggplot2
的分面方法。ggplot2
包提供了两种分面方法:
facet_wrap()
函数。将数据根据一个或多个变量进行分面,按行或列进行排列,仅是分面图逐个排列,例如左到右,上到下。facet_grid()
函数。考虑分面方向,可以同时控制行和列的分面,形成table网格对照关系。适合用来表示两个变量的交互效应。facet_wrap()
函数的写法比较多样,例如如果我们想按照class(车型)分组,达到和上例相同的效果,还可以写作:
p1 + facet_wrap(facets = vars(class))
p1 + facet_wrap(facets = class ~ .)
p1 + facet_wrap(facets = . ~ class)
table(mpg$class,mpg$year)
# 1999 2008
# compact 25 22
# midsize 20 21
# suv 29 33
# 2seater 2 3
# minivan 6 5
# pickup 16 17
# subcompact 19 16
p1 + facet_wrap(facets = vars(class, year))
p1 + facet_wrap(facets = c("class", "year"))
p1 + facet_wrap(facets = ~ class + year)
p1 + facet_wrap(facets = ~ class ~ year)
获得了7×2=14个子图,第一个子图中的每个点就代表1999年的compact车型的displ(发动机排量)与hwy(高速公路里程)。
调整输入列名的顺序即可修改分面标签的顺序(另几种写法同理):
p1 + facet_wrap(facets = ~ year + class)
facet_wrap()
函数提供了很多参数用于分面的调整,主要包括:nrow
,ncol
:设置分面排列成的行和列数;scales
:设置坐标轴刻度是否固定。默认为"fixed
",所有分面的坐标轴刻度范围一致;设置为"free
"则会自动适配分面的数据范围自由调整,也可以单独设置成"free_x
"或"free_y
";shrink
:也和坐标轴刻度有关,如果为TRUE
(默认值)则按统计后的数据调整刻度范围,否则按统计前的数据设定坐标;drop
:表示是否去掉没有数据的分组,默认情况下不显示,逻辑值为FALSE
;as.table
:和小图排列顺序有关的选项。如果为TRUE
(默认)则按表格方式排列,即最大值(指分组level值)排在表格最后即右下角,否则排在左上角;margins
:是否设置一个所有分组的综合统计分面,默认情况为FALSE
,即不设置;space
:设置分面空间是否可以按照数据进行缩放,参数和scales
一样;labeller
:设置分面标签,默认直接显示分面变量的值,也可以简单加上变量的名称,如:"label_both
"。labeller
参数把组名也加上:p1 + facet_wrap(facets = ~ year + class, labeller = "label_both")
p1 + facet_wrap(facets = ~ year + class, labeller = label_both)
我们还可以自定义函数,比如我们定义一个对输入年份截取3-4位数字的函数,然后使用labeller
函数转换为参数传递给labeller
选项:
SUB <- function(x) {
substr(as.character(x), 3, 4)
}
p1 + facet_wrap(facets = ~ year + class,
labeller = labeller(year = SUB))
或者直接指定替换内容,例如1999年换成20世纪,2008年换成21世纪(我学不好生物是有原因的)
year2 <- c("1999" = "20th century", "2008" = "21st century")
p1 + facet_wrap(facets = ~ year + class,
labeller = labeller(year = year2))
使用strip.position
函数可以调整分面标签的位置,例如调整至右方:
p1 + facet_wrap(facets = ~ year, strip.position = "right")
这一方法我们之前也写过一个例子:图片复现 | 富集分析条形图-调整分面标记的位置
分面本身堆砌的顺序也可以调整。在facet_wrap()
中的dir
参数默认值为h
(水平方向),as.table
参数默认值为TRUE
,它会按照我们日常看表格的习惯来从上至下,从左至右排布。以下图为例:
p1 + facet_wrap(facets = ~ year + class, labeller = "label_both")
如果要想按照垂直方向摆放图片,只需调整dir
参数默认值为v
(垂直方向)即可:
p1 + facet_wrap(facets = ~ year + class, labeller = "label_both", dir = "v")
而当as.table
参数设置为FALSE
时,则是按照绘图的逻辑,从下到上摆放(下次调整分组顺序时也要记得绘图的逻辑与阅读顺序是反的):
p1 + facet_wrap(facets = ~ year + class, labeller = "label_both",as.table = F)
比如让所有分面排成一行或两列:
p1 + facet_wrap(facets = ~ class, nrow = 1)
p1 + facet_wrap(facets = ~ class, ncol = 2)
以上我们可以看到所有子图的坐标轴都是固定的(即所有子图完全一样,默认scales = fixed
),如果想要坐标轴根据每个子图中的实际数值范围来决定,我们可以用设置scales
选项为free_x
(X轴自由浮动,固定Y轴);free_y
(Y轴自由浮动,固定X轴);free
(X和Y轴都自由浮动)。
p1 + facet_wrap(facets = ~ class, ncol = 3, scales = 'free')
p1 + facet_wrap(facets = ~ class, ncol = 3, scales = 'free_y')
之前更的一个帖子也许更能突出这一参数的价值:R语言画图 | 箱线图(二)一个示例
三组数据的组别并不完全一致,因此我们设置facet_wrap(.~DataSet,scales = "free_x",nrow = 1)
以上内容我们可以发现facet_wrap()
函数结果只有一个维度,它的排布没有行列的概念,只是根据子集作图然后按顺序排布。接下来我们了解一下使用facet_grid()
函数。它既可以进行单分组,例如我们设置以year来按行分面,依旧有很多写法:
按行分面:
p1 + facet_grid(facets = year ~ .)
p1 + facet_grid(year ~ .)
p1 + facet_grid(rows = vars(year))
p1 + facet_grid(rows = "year")
按列分面:
p1 + facet_grid(facets = ~ year)
p1 + facet_grid(. ~ year)
p1 + facet_grid(cols = vars(year))
也可以既按行也按列分面:这也是facet_grid()
函数的优势所在。例如行按year,列按class分面:
p1 + facet_grid(year ~ class)
亦或者持续叠加更多分组:
p1 + facet_grid(drv ~ year + class)
其他的参数使用和facet_warp()
基本一致,例如:
p1 + facet_grid(year ~ class, scales = "free")
修改一个margin
参数即可:
p1 + facet_grid(year ~ class, scales = "free", margins = T)
如果只想显示其中一个分组方向的汇总数据,可以直接指定分面的变量名:
p1 + facet_grid(year ~ class, scales = "free", margins = "year")
facet_wrap()
:当你有一个分类变量,并希望快速查看不同类别的图形时,使用facet_wrap()
更为简便。facet_grid()
:更适合用于显示两个相关变量之间的关系。对于需要明确区分行和列时,比如分组比较,facet_grid()
显得更为合适。1、日常分享的小懒猫:R语言绘图|分面标签设置
2、狗图:ggplot2系列教程 第4节——分面
3、科研后花园:R可视化——ggplot2包实现图形分面技巧汇总
4、生态R学社:ggplot2 facet :绘制分面图的好帮手
https://mp.weixin.qq.com/s/Gg-d4M9W-TEw3nFglqbocg