ggplot2包是R语言一个强大的绘图包,具有各种各样的功能,能够模仿甚至超越目前存在99%的绘图软件。它的底层逻辑类似ps的图层逻辑,通过一层又一层的函数,不断地覆盖并完善图形,直至完成。而facet(分面)是ggplot2中常用的一个函数,通常绘制的指标过多时,我们可以利用facet相关函数完成各子图的绘图,使得数据展示完整且美观。由于不同指标可能存在数据的数量级差异,因此今天主要与大家分享如何使用 geom_blank 函数在各个分面获得更好的坐标轴范围。
大家可能会好奇为什么进行分面?分面有什么作用? 这里可以大声告诉你,在做报告和发表专业期刊甚至是顶级期刊(Nnature、Science、Cell、PNAS)时的很多图形中都用到了分面。它就好比九宫格甚至可以设置更多图像,先将数据划分成多个子集,并将每个子数据集填充绘制到页面各小图形中。通常我们绘图时用到的分面有两种类型: 1)facet_wrap -- 封装类型 生成一个 1 维的多宫格,然后按行或按列顺序添加子图。具体如下图:
2)facet_grid -- 网格类型 生成一个 2 维的多网格,通过行列对应不同因子型的变量。具体如下图: 特别提醒:两者具体区别也可以看出,一个是生成1维的,另一个是生成2维的。也就是说,如果想要分别用两个变量来表征多个子数据集时可以优先考虑用facet_grid函数来绘图。当然,如果想用facet_wrap函数来绘制2维也可以,但是绘图的效果可能不好。接下来,先与大家简单分享下分面示例: 这里使用R语言自带的数据集:"mpg" 1) 绘制单独的面板 -- facet_null () # 加载R包 library(ggplot2)
# 绘制散点图 ggplot(mpg, aes(cty, hwy)) + geom_point() + facet_null() # 绘制单一面板
2) facet_wrap 单一变量:var ~ . ggplot(mpg, aes(cty, hwy)) + geom_point() + facet_wrap(cyl ~ .)
3) facet_wrap 多变量:var(var1 , var2) 或者 var1~var2 ggplot(mpg, aes(cty, hwy)) + geom_point() + #facet_wrap( cyl ~ drv) facet_wrap(vars(cyl, drv))
4) facet_grid 一行多列或者是多行一列:. ~ var 或 var ~ . ggplot(mpg, aes(cty, hwy)) + geom_point() + # facet_grid( . ~ cyl) facet_grid(cyl ~ .)
5) facet_grid 多行多列:. ~ var 或 var ~ . ggplot(mpg, aes(cty, hwy)) + geom_point() + facet_grid(drv ~ cyl)
关于facet分面其他的一些细节,在这里我们不赘述了,网上也有很多相关介绍。今天主要想和大家分享一下有关facet分面中如何设定更好的坐标轴范围。该函数有一个参数--scales,它主要作用是可以根据不同子图(各分面的数据集范围)对x和y轴进行自动生成(但是自动生成的范围不一定是我们想要的,如导致图的比例不美观等等)。而平时我们使用的scale_y_continuous都是对一个图形背景所有的范围进行设置,不能很好的解决这个问题。这里,我们推荐使用geom_blank函数来完成该功能。
1) 我们先构建一个数据集:由于是随机构建的,可以设置种子保证每次结果复现一致 set.seed(20220219) create_df <- rbind(data.frame(group="a", x = runif(100), y = rnorm(100, mean = 5)), data.frame(group="b", x = runif(100), y = rnorm(100, mean = 5, sd = 3)+20), data.frame(group="c", x = runif(100), y = rnorm(100, mean = 5, sd = 5)+30)) str(create_df)
2) 紧接着把构建的数据绘制成图: ggplot() + geom_point(data = create_df, aes(x = x, y = y, colour = group), size = 3) + facet_wrap( ~ group, scales = "free_y") + # 使用scale ="free_y"允许y轴在保持x轴不变的情况下变化(意思可以更改y轴范围) theme_bw()
这里可以利用?facet_wrap查看相关函数的介绍 , scales = "free" 对应的介绍也非常详细~可以看出来由于图形比例不当,导致的图结果并不美观。 3) 调整图形坐标轴的比例,如果使用单一面板或所有相同比例的数据时,通常使用 coord_cartesian 函数。但是当具有不同比例的面板时,这个效果并不好,它强制所有内容都处于相同的比例。结果如下: ggplot() + geom_point(data = create_df, aes(x = x, y = y, colour = group), size = 3) + facet_wrap( ~ group, scales = "free_y") + coord_cartesian(ylim = c(0, 75)) + theme_bw()
从图来看,点确实是聚集起来了,但是各分面都有多余的空间。使得图看起来不协调。 另一种我们还可以选择使用 expand_limits() 强制各分面从原点开始。使用 scale_y_continuous(expand=c(0,0)) 删除 y 轴限制的缓冲区。其中expand 的两个值是 c(乘数缓冲区,加法缓冲区)。通过包含 c(0,0),我们不包含轴刻度上的任何缓冲区。结果如下: ggplot() + geom_point(data = create_df, aes(x = x, y = y, colour = group), size = 3) + facet_wrap( ~ group, scales = "free_y") + expand_limits(y = 0) + scale_y_continuous(expand = c(0, 0)) + theme_bw()
从图来看还是不能很好的解决不同比例的y轴范围。为了解决这些问题,可以使用 geom_blank,它能够完美的解决各分面的坐标轴范围问题。首先创建一个数据集,其中包含我们数据集中每个组级别的 y 轴的最小值和最大值。然后使用 geom_blank 将其传递给 ggplot 就可以完美解决了。 blank_data <- data.frame(group = c("a", "a", "b", "b", "c", "c"), x = 0, y = c(2, 8, 10, 40, 20, 50))
ggplot() + geom_point(data = create_df, aes(x = x, y = y, colour = group), size = 3) + geom_blank(data = blank_data, aes(x = x, y = y)) + facet_wrap( ~ group, scales = "free_y") + scale_y_continuous(expand = c(0, 0)) + theme_bw()
关于数据集的设定我们需要考虑几点: 1)group分组的名称要一一对应 2)对应y轴的值要有两个点(最小值和最大值) 3)要考虑清楚各分面哪个范围的图看起来更加美观,比例更加协调 感兴趣的同学可以通过以下方式与我们沟通、交流和学习:
|