使用ggh4x::facet_manual时如何在空白面板下方显示X轴
问题描述
我正在处理多组有时共享数值范围的图形(示例数据未体现该特性),希望用ggh4x::facet_manual实现并排展示,但无法在图形下方的空白面板区域显示X轴。
facet_manual()的官方文档中,axes参数可选值如下:
- "margins"或FALSE:仅在外部边缘绘制轴(默认)
- "x":在外部边缘和所有内部X轴绘制轴
- "y":在外部边缘和所有内部Y轴绘制轴
- "all"或TRUE:为每个面板绘制轴
但这些选项都无法让空白面板(如示例设计中的#和h位置)显示X轴。
可复现代码如下:
# Data ---- library(tibble) reprex_data <- tibble( date = as.Date(rep( rep( c( "2022-01-15", "2022-02-15", "2022-03-15", "2022-04-15", "2022-05-15", "2022-06-15", "2022-07-15", "2022-08-15", "2022-09-15", "2022-10-15", "2022-11-15", "2022-12-15", "2023-01-15", "2023-02-15", "2023-03-15", "2023-04-15", "2023-05-15", "2023-06-15", "2023-07-15", "2023-08-15", "2023-09-15", "2023-10-15", "2023-11-15", "2023-12-15" ), 2 ), rep(c(1L, 5L), each = 24L) )), group = c( "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B", "C", "E", "F", "D", "B" ), value = c( 1032.8, 976.4, 885.6, 893.7, 793.8, 777.4, 847.8, 815.9, 795.4, 862.7, 873.4, 1086.4, 964.1, 870.4, 837.8, 812, 778, 759.1, 731.4, 759.6, 778.3, 820.3, 857.7, 943.7, 200.4, 38.6, 20.6, 64.5, 245.7, 188.2, 38.6, 17.6, 56.2, 235.1, 182.6, 36.7, 17.4, 56.6, 238.6, 183.9, 34.6, 17.6, 65.5, 238.6, 165.5, 34.1, 16.5, 48.8, 234, 157.8, 34.3, 16.1, 47.8, 237.8, 164.2, 34.3, 16.9, 52, 241.1, 157.8, 34.8, 17, 51.8, 241.6, 160, 36.4, 16.1, 47.4, 242.3, 173.9, 36.6, 17.1, 55.3, 246.9, 179.7, 38.1, 17.4, 62.3, 242.8, 219.9, 42.5, 21.1, 103.7, 257.5, 201.9, 40.6, 18.3, 93.6, 240.3, 186.6, 37.5, 18.9, 72.7, 238.7, 182.4, 36.7, 18.6, 63.4, 237, 173.4, 34.3, 17.8, 56.3, 231.5, 164.1, 34, 16, 54, 227.9, 150.1, 31.9, 15, 48.8, 235.6, 145.6, 31.7, 14, 46.8, 234.6, 151.9, 32.3, 16, 48.8, 234.7, 154.3, 33.8, 15.8, 49, 239.7, 163.8, 36.8, 16.9, 56, 243.4, 177.4, 37.3, 18, 60.2, 243.9, 196, 37.4, 20.2, 76.8, 243.5 ) ) # Code ---- # install.packages("ggh4x") library(ggplot2) library(ggh4x) design <- c("a# bc d# ef #h") ggplot(data = reprex_data) + geom_point(aes(x = date, y= value), colour = "black", size = 1.5, shape = 19, alpha = 0.2) + geom_line(aes(x = date, y = value), colour = "black", linewidth = 0.5, alpha = 0.2) + facet_manual(~ group, design, scales = "free_y")
解决方案
facet_manual的axes参数仅对包含数据的面板生效,空白面板没有对应的数据组,因此无法直接通过参数控制显示X轴。以下两种方法可实现需求:
方法1:添加虚拟数据组
给空白面板对应的位置添加虚拟数据组,让axes参数能识别并绘制X轴:
library(dplyr) # 创建虚拟数据,包含空白面板的组和X轴范围 dummy_data <- tibble( date = range(reprex_data$date), group = rep(c("#", "h"), each = 2), value = 0 # 虚拟值,后续会隐藏 ) # 合并原始数据与虚拟数据 reprex_data_full <- bind_rows(reprex_data, dummy_data) # 绘制图形,设置axes="x"显示所有X轴 ggplot(data = reprex_data_full) + geom_point(aes(x = date, y= value), colour = "black", size = 1.5, shape = 19, alpha = 0.2) + geom_line(aes(x = date, y = value), colour = "black", linewidth = 0.5, alpha = 0.2) + facet_manual(~ group, design, scales = "free_y", axes = "x") + # 隐藏虚拟组的Y轴范围(排除虚拟值0) scale_y_continuous(limits = function(y) { if (any(y == 0)) { range(y[y != 0]) } else { range(y) } })
方法2:手动修改gtable对象
直接提取ggplot的gtable结构,复制已有面板的X轴并添加到空白面板下方:
library(grid) library(gtable) # 先绘制基础图形 p <- ggplot(data = reprex_data) + geom_point(aes(x = date, y= value), colour = "black", size = 1.5, shape = 19, alpha = 0.2) + geom_line(aes(x = date, y = value), colour = "black", linewidth = 0.5, alpha = 0.2) + facet_manual(~ group, design, scales = "free_y", axes = "x") # 转换为gtable对象 gt <- ggplotGrob(p) # 获取已有底部X轴的模板(取第一个底部轴) axis_template <- gt$grobs[grepl("axis-b", gt$layout$name)][[1]] # 定位空白面板的位置(通过gtable布局确认) blank_panel_pos <- c( which(gt$layout$t == 1 & gt$layout$l == 2), # 第一行第二列的空白面板 which(gt$layout$t == 3 & gt$layout$l == 2), # 第三行第二列的空白面板 which(gt$layout$t == 5 & gt$layout$l == 1) # 第五行第一列的空白面板 ) # 给每个空白面板添加X轴 for (pos in blank_panel_pos) { gt <- gtable_add_grob( gt, axis_template, t = gt$layout$b[pos] + 1, # 放在面板下方 l = gt$layout$l[pos], r = gt$layout$r[pos] ) } # 调整轴的高度,避免重叠 gt$heights[gt$layout$b[blank_panel_pos] + 1] <- unit(5, "pt") # 绘制修改后的图形 grid.draw(gt)
方法1操作简单,适合快速实现;方法2无需修改原始数据,更灵活,但需要对gtable结构有基础了解。
内容的提问来源于stack exchange,提问作者cravetheflame
相关产品推荐
相关产品推荐

