如何使用ggplot2的facet_wrap,实现分组X轴保留专属因子不丢失?
解决ggplot2 facet_wrap中不同分组保留独立X轴因子水平的问题
要让gc1组始终显示A、B、C所有因子水平,ps1组仅显示D、E、F且互不干扰,推荐使用ggh4x包的facetted_pos_scales功能,它支持为不同分面单独配置轴刻度。
方法一:使用ggh4x包(推荐)
这个方法能确保所有gc1分面都显示A、B、C,不管子分组是否有对应数据,ps1分面同理。
library(ggplot2) library(ggh4x) # 生成数据 set.seed(1234) df = data.frame(ps = paste(rep(c("ps1","gc1"),6)), cr = rep(LETTERS[1:3],4), id = rep(x = month.abb[1:4], each = 3)) df = df[order(df$ps),] df[df$ps == "ps1","cr"] <- sample(LETTERS[4:6], size = 6, replace = TRUE) df.all = rbind(df,df,df,df,df,df) df.all$val = rnorm(n = nrow(df.all)) # 绘图并设置分面X轴刻度 ggplot(df.all, aes(x = cr, y = val)) + geom_violin() + geom_point(position = position_jitter(width = 0.1, height = 0.1), alpha= .3) + facet_wrap(vars(ps, id), scales = "free_x", ncol = 4) + facetted_pos_scales( x = list( ps == "gc1" ~ scale_x_discrete(limits = c("A", "B", "C")), ps == "ps1" ~ scale_x_discrete(limits = c("D", "E", "F")) ) )
方法二:预处理数据(无需额外包)
如果不想依赖第三方包,可以通过为每个ps分组固定cr的因子水平来实现:
library(ggplot2) library(dplyr) # 生成数据(同上) set.seed(1234) df = data.frame(ps = paste(rep(c("ps1","gc1"),6)), cr = rep(LETTERS[1:3],4), id = rep(x = month.abb[1:4], each = 3)) df = df[order(df$ps),] df[df$ps == "ps1","cr"] <- sample(LETTERS[4:6], size = 6, replace = TRUE) df.all = rbind(df,df,df,df,df,df) df.all$val = rnorm(n = nrow(df.all)) # 预处理:为每个ps分组设置固定的cr因子水平 df.all <- df.all %>% group_by(ps) %>% mutate( cr = case_when( ps == "gc1" ~ factor(cr, levels = c("A", "B", "C")), ps == "ps1" ~ factor(cr, levels = c("D", "E", "F")) ) ) %>% ungroup() # 绘图 ggplot(df.all, aes(x = cr, y = val)) + geom_violin() + geom_point(position = position_jitter(width = 0.1, height = 0.1), alpha= .3) + facet_wrap(vars(ps, id), scales = "free_x", ncol = 4)
这种方法下,即使某个gc1的子分组缺少某个水平,对应的分面仍会显示该刻度,但不会有图形元素。
内容的提问来源于stack exchange,提问作者M. Beausoleil
相关产品推荐
相关产品推荐

