ixxmu / mp_duty

抓取网络文章到github issues保存
https://archives.duty-machine.now.sh/
115 stars 30 forks source link

R语言画图 | ggplot2分面标签设置 #5760

Closed ixxmu closed 3 hours ago

ixxmu commented 3 hours ago

https://mp.weixin.qq.com/s/Gg-d4M9W-TEw3nFglqbocg

ixxmu commented 3 hours ago

R语言画图 | ggplot2分面标签设置 by 被炸熟的虾

前言:

分面(facet)是ggplot2的一个常用功能,当绘制的指标过多时,我们可以利用facet函数分类绘图,使得数据展示完整且美观。

本文使用R内置数据集mpg进行演示,该数据集包含11个变量,包括汽车的品牌、型号、车型、发动机排量、气缸数量、马力、重量、加速度、型号年份、产地和燃油经济性能等。以下是每个变量的详细说明:

  1. manufacturer(制造商):汽车制造商的名称。
  2. model(型号):汽车的型号。
  3. displ(发动机排量):汽车发动机的排量(升)。
  4. year(型号年份):汽车的型号年份。
  5. cyl(气缸数量):汽车发动机的气缸数量。
  6. trans(变速器类型):汽车的变速器类型。
  7. drv(驱动方式):汽车的驱动方式(前驱、后驱或四驱)。
  8. cty(城市里程):汽车的城市里程(每加仑)。
  9. hwy(高速公路里程):汽车的高速公路里程(每加仑)。
  10. fl(燃料类型):汽车使用的燃料类型。
  11. class(车型):汽车的车型。
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)
多变量叠加
如果想再叠加一层其他变量,比如year(型号年份)可以按照如下写法:
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), 34)
}
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")
我们设置了先yearclass,因此会先按year再按class来排序。两个变量的各自顺序分别按照各自的因子(levels)顺序。

如果要想按照垂直方向摆放图片,只需调整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_xX轴自由浮动,固定Y轴);free_yY轴自由浮动,固定X轴);freeXY轴都自由浮动)。

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 :绘制分面图的好帮手


被炸熟的虾
自己的摸索,发现问题麻烦告诉作者,光速回来改正