在R的ggplot2分组柱状图中添加双侧柱子垂直时间标签的方法
问题描述
现有如下样本数据集,基于两个时间点的调研结果,按group1和group2分组:
df <- structure(list(label2plot = c("yes", "no", "yes", "no", "yes", "no", "yes", "no"), gruppe = c("group1", "group1", "group2","group2", "group1", "group1", "group2", "group2"), cohort = structure(c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L), levels = c("20172018", "20192020"), class = "factor"), var_abs = c(4979L, 3214L, 129L, 130L, 5476L, 3556L, 89L, 74L), var_rel = c(0.789565, 0.8035, 0.871622, 0.8125, 0.793163, 0.805254, 0.839623, 0.860465)), class = "data.frame", row.names = c(NA, -8L))
使用以下代码绘制分组柱状图,每个组单独展示:
var_label <- "blabla" title <- "blublub" subtitle <- "blablub" val_label <- c("yes", "no") packages2check <- c("ggplot2", "stringr") for (package in packages2check) { if (!requireNamespace(package, quietly = TRUE)) { install.packages(package) library(package, character.only = TRUE) } else { library(package, character.only = TRUE) } } ggplot() + geom_bar ( data = df, aes( x = factor(label2plot, levels = val_label), y = var_rel, group = cohort, fill = label2plot ), stat = "identity", position = position_dodge(), color = "white", linewidth = 0.5 ) + scale_y_continuous( labels = scales::percent, limits = c(0, 1.15), breaks = seq(0, 1, 0.2) ) + theme_classic() + theme( legend.position = "none", plot.title = element_text(hjust = 0.5, size = 14, face = "bold"), plot.subtitle = element_text(hjust = 0.5), plot.caption = element_text(hjust = 0.5), ) + scale_fill_manual(values = c("yes" = "#AFCDE4", "no" = "#389DC3")) + geom_text( data = df, size = 3, position = position_dodge2(preserve = 'single', width = 0.9), hjust = 0.5, vjust = -0.5, color = "black", aes( x = factor(label2plot, levels = val_label), y = var_rel, label = paste0(sprintf("%.1f", var_rel * 100), "%", "\n(N=", var_abs, ")") ) ) + labs( subtitle = paste(subtitle), title = str_wrap(title, 45), x = var_label, y = "", fill = "" ) + facet_wrap( ~ gruppe)
当前图表中,yes和no类别的两个时间点柱子仅左侧显示垂直cohort标签,需要实现每个柱子都对应显示垂直的时间点标签。
解决方案
通过新增一个geom_text图层,专门为每个柱子添加垂直的cohort标签,并通过位置对齐保证标签与柱子一一对应。以下是修改后的完整代码:
var_label <- "blabla" title <- "blublub" subtitle <- "blablub" val_label <- c("yes", "no") packages2check <- c("ggplot2", "stringr") for (package in packages2check) { if (!requireNamespace(package, quietly = TRUE)) { install.packages(package) library(package, character.only = TRUE) } else { library(package, character.only = TRUE) } } ggplot() + geom_bar ( data = df, aes( x = factor(label2plot, levels = val_label), y = var_rel, group = cohort, fill = label2plot ), stat = "identity", position = position_dodge(), color = "white", linewidth = 0.5 ) + # 新增的cohort垂直标签图层 geom_text( data = df, aes( x = factor(label2plot, levels = val_label), y = -0.05, # 标签位置:柱子底部下方 label = cohort, group = cohort ), position = position_dodge(width = 0.9), # 和柱状图的dodge宽度匹配 angle = 90, # 设置垂直显示 hjust = 1, vjust = 0.5, size = 3 ) + scale_y_continuous( labels = scales::percent, limits = c(-0.1, 1.15), # 调整y轴下限,容纳底部标签 breaks = seq(0, 1, 0.2) ) + theme_classic() + theme( legend.position = "none", plot.title = element_text(hjust = 0.5, size = 14, face = "bold"), plot.subtitle = element_text(hjust = 0.5), plot.caption = element_text(hjust = 0.5), ) + scale_fill_manual(values = c("yes" = "#AFCDE4", "no" = "#389DC3")) + geom_text( data = df, size = 3, position = position_dodge2(preserve = 'single', width = 0.9), hjust = 0.5, vjust = -0.5, color = "black", aes( x = factor(label2plot, levels = val_label), y = var_rel, label = paste0(sprintf("%.1f", var_rel * 100), "%", "\n(N=", var_abs, ")") ) ) + labs( subtitle = paste(subtitle), title = str_wrap(title, 45), x = var_label, y = "", fill = "" ) + facet_wrap( ~ gruppe)
关键修改说明:
- 新增
geom_text图层:专门用于渲染cohort的垂直标签,设置angle = 90实现垂直显示 - 位置对齐:
position = position_dodge(width = 0.9)与柱状图的position_dodge()参数匹配,确保标签和对应柱子对齐 - 标签位置调整:
y = -0.05将标签放在柱子底部下方,同时调整scale_y_continuous的limits为c(-0.1, 1.15),避免标签被截断 - 分组设置:
aes中指定group = cohort,保证每个时间点的标签被正确分配到对应柱子
如果希望将标签放在柱子顶部,只需修改geom_text的y参数为y = var_rel + 0.02,并调整vjust参数即可。
内容的提问来源于stack exchange,提问作者Dierforth
相关产品推荐
相关产品推荐

