如何在ggplot2 facet_wrap各分面中添加多层X轴绘制条形图
ggplot2分面嵌套多层X轴实现方案
原代码使用interaction()合并年份和季度字段,会直接把两个值拼接成单行文本标签,无法实现分层嵌套效果,同时原代码存在两个小问题:一是映射的y轴变量Series不存在,实际数据字段为Series1;二是Series1为字符格式,直接绘图会导致数值映射错误,需要先转成数值型。
基础实现(无需额外依赖包)
先预处理数据:
library(ggplot2) # 构造并清洗数据 df <- data.frame( Years = c("2016","2016","2016","2016", "2017","2017","2017","2017", "2016","2016","2016","2016", "2017","2017","2017","2017"), Quarters = c("1","2","3","4", "1","2","3","4", "1","2","3","4", "1","2","3","4"), panel= c("A","A","A","A", "A","A","A","A", "B","B","B","B", "B","B","B","B"), Series1 = as.numeric(c("100","200","300","400","500","600","700","800", "400","200","300","600","500","300","700","800")) )
绘图核心逻辑是把季度作为第一级X轴刻度,手动在刻度下方添加年份作为第二级标签:
ggplot(df, aes(x = Quarters, y = Series1)) + geom_col(width = 0.7) + # 分面仅释放X轴自由度即可 facet_wrap(~panel, scales = "free_x") + # 配置第一级X轴(季度) scale_x_discrete( name = NULL, labels = c("Q1","Q2","Q3","Q4"), expand = c(0,0) ) + # 添加第二级X轴标签(年份),定位到每个年份对应季度组的中心下方 annotate( geom = "text", x = c(2.5, 6.5, 2.5, 6.5), # 每个分面里2016年中心在Q1-Q4中点2.5,2017年在Q5-Q8中点6.5 y = -60, # 标签位置在X轴下方,可根据自身y轴范围调整 label = rep(c("2016", "2017"), 2), fontface = "bold", size = 3.8 ) + # 可选:添加年份组分隔线,分层效果更清晰 geom_vline(xintercept = 4.5, color = "gray60", linetype = "dashed") + # 关闭裁剪防止轴外标签被截断,y轴下限设为0避免负值区域显示 coord_cartesian(clip = "off", ylim = c(0, NA)) + theme( # 给底部二级标签预留足够空间 plot.margin = margin(b = 22), axis.text.x = element_text(margin = margin(t = 6)) )
简化实现(借助ggh4x包)
如果不想手动计算二级标签位置,可以用ggh4x扩展包提供的嵌套轴向导,自动识别层级关系:
library(ggh4x) ggplot(df, aes(x = interaction(Years, Quarters, lex.order = TRUE), y = Series1)) + geom_col(width = 0.7) + facet_wrap(~panel, scales = "free_x") + scale_x_discrete( name = NULL, labels = rep(c("Q1","Q2","Q3","Q4"), 2), # 调用嵌套轴向导自动生成二级标签 guide = guide_axis_nested() ) + theme( # 配置二级轴的分隔线和标签样式 ggh4x.axis.nestline.x = element_line(linewidth = 1), ggh4x.axis.nesttext.x = element_text(face = "bold") )
两种方案都可以在每个分面内实现「年份在上层分组、季度在下层刻度」的嵌套X轴效果,和facet_wrap的分面逻辑完全兼容。
内容的提问来源于stack exchange,提问作者user14845003
相关产品推荐
相关产品推荐

