如何在ggplot中制作分年度对比的分组发散条形图?
解决方案
方案1:同一图中交错排列年份条形
通过在数据分组时加入year维度,使用interaction(role, year)作为x轴变量,配合position_dodge()实现同角色下两年条形的并排交错。
修改后的完整代码:
# 调整数据汇总:按role、define、year分组 support_sum <- support %>% group_by(role, define, year) %>% # 新增year分组 count(name = "n_support") %>% group_by(role, year) %>% # 按role和year计算百分比 mutate(percent_support = n_support / sum(n_support)) %>% ungroup() %>% mutate(percent_support_labels = percent(percent_support, accuracy = 1)) # 设置发散格式,保留year维度 support_sum_div <- support_sum %>% mutate(percent_support = if_else(define %in% c("Strongly Agree", "Agree"), percent_support, -percent_support)) %>% mutate(percent_support_labels = percent(percent_support, accuracy = 1)) # 修正标签为绝对值百分比 support_sum_div_labs <- support_sum_div %>% mutate(percent_support_labels = abs(percent_support)) %>% mutate(percent_support_labels = percent(percent_support_labels, accuracy = 1)) # 重新排序define因子,创建role+year交互变量 support_div_ordered <- support_sum_div_labs %>% mutate(define = fct_relevel(define, "Neutral", "Strongly Disagree", "Disagree", "Agree", "Strongly Agree"), define = fct_rev(define), role_year = interaction(role, year, sep = " - ")) # 绘制交错条形的发散图 support_div_ordered %>% ggplot(aes(x = role_year, y = percent_support, fill = define)) + geom_col(position = position_dodge(width = 0.8), width = 0.7) + # 启用dodge实现并排 geom_text(aes(label = percent_support_labels), position = position_dodge(width = 0.8), # 文本位置匹配dodge vjust = 0.5, color = "white", fontface = "bold", size = 3) + coord_flip() + scale_fill_manual(breaks = c("Neutral", "Strongly Disagree", "Disagree", "Agree", "Strongly Agree"), values = c( "Neutral" = "gold", "Strongly Disagree" = "slateblue", "Disagree" = "plum", "Agree" = "#41b6c4", "Strongly Agree" = "dodgerblue4" )) + labs(title = "People are supportive of each other (2021 vs 2023)", x = "Role - Year", fill = NULL) + theme_minimal() + theme(axis.title.x = element_blank(), panel.grid = element_blank(), legend.position = "top")
方案2:对齐拆分图的中线
确保两张独立图的x轴范围完全一致,并用cowplot::plot_grid的align参数实现水平对齐,同时统一图表元素(如标题、轴标签)。
修改后的代码示例:
# 定义通用绘图函数,避免重复代码 plot_diverge <- function(data, year_label) { data %>% ggplot(aes(x = role, y = percent_support, fill = define)) + geom_col() + geom_text(aes(label = percent_support_labels), position = position_stack(vjust = 0.5), color = "white", fontface = "bold") + coord_flip(xlim = c(0, length(unique(data$role)) + 0.5)) + # 设置统一x轴范围 scale_fill_manual(breaks = c("Neutral", "Strongly Disagree", "Disagree", "Agree", "Strongly Agree"), values = c( "Neutral" = "gold", "Strongly Disagree" = "slateblue", "Disagree" = "plum", "Agree" = "#41b6c4", "Strongly Agree" = "dodgerblue4" )) + labs(title = paste("Support in", year_label), x = NULL, fill = NULL) + theme_minimal() + theme(axis.text.x = element_blank(), axis.title.x = element_blank(), panel.grid = element_blank(), legend.position = "none") # 只在一张图显示图例 } # 拆分数据并绘图 support_2021 <- support_div_ordered %>% filter(year == 2021) support_2023 <- support_div_ordered %>% filter(year == 2023) plot_2021 <- plot_diverge(support_2021, "2021") plot_2023 <- plot_diverge(support_2023, "2023") + theme(legend.position = "top") # 保留一个图例 # 对齐合并图表 plot_grid(plot_2023, plot_2021, align = "h", ncol = 2) + labs(title = "People are supportive of each other (2021 vs 2023)")
内容的提问来源于stack exchange,提问作者Kiirsti Owen
相关产品推荐
相关产品推荐

