在R的ggplot中为facet_wrap添加纵向分类标签
问题描述
我有一个包含6个站点(城市)的数据集,每两个站点归为一个名为method的类别。我想用facet_wrap绘制每个站点的图表,设置为2列3行(每行对应一个method),并为每行添加method名称作为纵向标签,每个分面添加站点名称作为横向标签。我无法使用facet_grid,因为它会生成不符合需求的布局,且无法为单个分面设置标签。尝试过facet_wrap(method~factor(city_f....)和facet_grid(method~factor(city_f....)都没达到预期,想知道怎么用facet_wrap结合分类变量添加纵向标签。现有代码如下:
ggplot(effect, aes(x=year, y= log10(effect+1), fill=type))+ geom_boxplot(width=0.6)+ facet_wrap(~factor(city_f, levels=c('S','M','G','R','O1','O2')), ncol = 2, labeller = as_labeller(new_labels2))+ scale_y_continuous(n.breaks = 8)+ theme(axis.text.x = element_text(size = 8), axis.text.y = element_text(size = 6))+ labs(x="year", y="log[effect+1]", title="Effect by city")+ geom_hline(yintercept=0,linetype="dashed")+ geom_hline(aes(yintercept=-Inf)) + geom_vline(aes(xintercept=-Inf))
解决方案
思路前提
首先确保每个站点(city_f)和对应的method绑定好,并且调整因子顺序,保证同一个method下的两个站点在facet_wrap中排在同一行。这里提供两种实用方法:
方法一:用annotation_custom给facet_wrap添加纵向行标签
这种方法不需要额外包(仅依赖ggplot2和grid),直接在现有图表基础上添加自定义注释:
- 绑定站点与method的映射关系
# 先创建映射表,替换成你的实际method名称 method_map <- data.frame( city_f = c('S','M','G','R','O1','O2'), method = c("方法A", "方法A", "方法B", "方法B", "方法C", "方法C") ) # 合并到原数据集 effect <- merge(effect, method_map, by = "city_f") # 调整因子顺序,保证同一method的站点相邻 effect$city_f <- factor(effect$city_f, levels = c('S','M','G','R','O1','O2'))
- 绘制基础图表并添加纵向标签
library(ggplot2) library(grid) p <- ggplot(effect, aes(x=year, y= log10(effect+1), fill=type))+ geom_boxplot(width=0.6)+ # 把站点标签放在分面底部,行间距调大给method标签留空间 facet_wrap(~city_f, ncol = 2, labeller = as_labeller(new_labels2), strip.position = "bottom")+ scale_y_continuous(n.breaks = 8)+ theme( axis.text.x = element_text(size = 8), axis.text.y = element_text(size = 6), strip.text = element_text(size = 10, face = "bold"), panel.spacing.y = unit(1.5, "cm") )+ labs(x="year", y="log[effect+1]", title="Effect by city")+ geom_hline(yintercept=0,linetype="dashed")+ geom_hline(aes(yintercept=-Inf)) + geom_vline(aes(xintercept=-Inf)) # 添加每行的method纵向标签,y_positions根据图表高度调整(0-1为相对位置) method_labels <- unique(effect$method) y_positions <- c(0.85, 0.5, 0.15) for(i in seq_along(method_labels)){ p <- p + annotation_custom( grob = textGrob(method_labels[i], rot = 90, gp = gpar(fontsize=10, fontface="bold")), xmin = -Inf, xmax = -Inf, ymin = y_positions[i], ymax = y_positions[i] ) } # 显示图表 print(p)
方法二:用patchwork按method分组拼接图表
这种方法更灵活,能精准控制每行的标题和布局:
- 拆分数据集并定义绘图函数
library(ggplot2) library(patchwork) # 按method拆分数据 method_list <- split(effect, effect$method) # 定义单个城市的绘图模板 plot_city <- function(data){ ggplot(data, aes(x=year, y= log10(effect+1), fill=type))+ geom_boxplot(width=0.6)+ facet_wrap(~city_f, ncol=2, labeller = as_labeller(new_labels2))+ scale_y_continuous(n.breaks = 8)+ theme( axis.text.x = element_text(size = 8), axis.text.y = element_text(size = 6), strip.text = element_text(size = 10, face = "bold") )+ geom_hline(yintercept=0,linetype="dashed")+ geom_hline(aes(yintercept=-Inf)) + geom_vline(aes(xintercept=-Inf)) }
- 分别绘制每行并组合
# 给每个method的子图添加纵向标题 plot1 <- plot_city(method_list[["方法A"]]) + plot_annotation(title = "方法A", theme = theme(plot.title = element_text(angle = 90, vjust = 0.5))) plot2 <- plot_city(method_list[["方法B"]]) + plot_annotation(title = "方法B", theme = theme(plot.title = element_text(angle = 90, vjust = 0.5))) plot3 <- plot_city(method_list[["方法C"]]) + plot_annotation(title = "方法C", theme = theme(plot.title = element_text(angle = 90, vjust = 0.5))) # 组合成3行2列,统一收集图例和全局标题 (plot1 / plot2 / plot3) + plot_layout(guides = "collect") + plot_annotation(title = "Effect by city", xlab = "year", ylab = "log[effect+1]")
内容的提问来源于stack exchange,提问作者sueb2
相关产品推荐
相关产品推荐

