R ggplot2中facet_grid设置scales='free'不生效如何解决
问题
- 使用
facet_grid()绘制2×2分面图时,设置scales = "free"、space = "free"参数后,对角位置的两个子图(左上facet_1 = 'A', facet_2 = 'a'、右下facet_1 = 'B', facet_2 = 'b')x轴范围远大于数据实际分布,参数未生效。 - 复现代码:
df = data.frame( x = c(0, 1, 0, 1, 0, 60, 0, 60), y = c(1.5, 0.3, 1.5, 0.3, 1.8, 0.1, 1.8, 0.1), facet_1 = c('A', 'A', 'B', 'B', 'A', 'A', 'B', 'B'), facet_2 = c('a', 'a', 'b', 'b', 'b', 'b', 'a', 'a')) df %>% ggplot(aes(x = x, y = y)) + geom_point() + geom_line() + facet_grid(facet_1~facet_2, scales = 'free', space = 'free') # scales = 'free_x' 同样无效

- 目前仅能通过
patchwork包拆分数据、单独绘制子图后拼接,实现坐标轴自适应数据范围的效果,代码如下:
df1 = df %>% filter(facet_1 == 'A',facet_2 == 'a') df2 = df %>% filter(facet_1 == 'A',facet_2 == 'b') df3 = df %>% filter(facet_1 == 'B',facet_2 == 'a') df4 = df %>% filter(facet_1 == 'B',facet_2 == 'b') p1 = df1 %>% ggplot(aes(x = x, y = y)) + geom_point() + geom_line() p2 = df2 %>% ggplot(aes(x = x, y = y)) + geom_point() + geom_line() p3 = df3 %>% ggplot(aes(x = x, y = y)) + geom_point() + geom_line() p4 = df4 %>% ggplot(aes(x = x, y = y)) + geom_point() + geom_line() library(patchwork) p1+p2+p3+p4

- 诉求:不拆分数据手动拼接的前提下,能否直接在ggplot2体系内实现和patchwork效果一致的、子图坐标轴完全自适应的分面图?
原因
原生facet_grid()的设计逻辑是严格的行列对齐网格分面:同一列的所有子图强制共享x轴范围,同一行的所有子图强制共享y轴范围,scales = "free"参数仅支持不同列/不同行之间的轴范围独立,无法打破同列/同行的轴绑定。
对应示例数据的分布:
- 第一列(
facet_2 = 'a')包含两个子图:A+a组x范围为01,`B+a`组x范围为060,整列x轴自动取最大公共范围0~60,导致左上子图x轴冗余 - 第二列(
facet_2 = 'b')包含两个子图:A+b组x范围为060,`B+b`组x范围为01,整列x轴同样取最大公共范围0~60,导致右下子图x轴冗余
解决方案
方案1:使用ggh4x包的facet_grid2(推荐,完全兼容原生facet_grid语法)
ggh4x是ggplot2的成熟扩展包,其中的facet_grid2()函数和原生facet_grid()用法完全一致,仅新增independent参数用于解除同列/同行的轴绑定,无需拆分数据即可实现每个子图坐标轴完全独立,效果和patchwork拼接完全一致,同时保留facet_grid的边缘条带布局。
先安装包(已安装可跳过):install.packages("ggh4x")
实现代码:
library(ggh4x) df %>% ggplot(aes(x = x, y = y)) + geom_point() + geom_line() + facet_grid2( facet_1~facet_2, scales = "free", space = "free", independent = "all" # 可选值"x"/"y"/"all",指定需要完全独立的轴方向 )
方案2:使用原生facet_wrap调整布局(无需安装扩展包)
原生facet_wrap()的scales = "free"默认支持每个子图坐标轴完全独立,只需将两个分面变量合并为交互因子,手动指定面板顺序后设置2行排布,即可实现类似效果。该方案缺点是分面条带为每个子图单独显示,和facet_grid的边缘统一标签布局有差异。
实现代码:
df %>% # 生成分面组合因子,lex.order = TRUE保证面板顺序和facet_grid布局一致 mutate(facet_pair = interaction(facet_1, facet_2, lex.order = TRUE)) %>% ggplot(aes(x = x, y = y)) + geom_point() + geom_line() + facet_wrap( ~facet_pair, scales = "free", nrow = 2, strip.position = "top" )
内容的提问来源于stack exchange,提问作者zhiwei li
相关产品推荐
相关产品推荐

