如何为ggplot绘制的图表添加额外图例?
问题描述
我用ggplot绘制了一幅柱状图,想给图中柱状图上方的深橙色(darkorange3)和深蓝色(steelblue4)小型置信区间(errorbar)添加对应颜色和文字的图例。尝试过相关方案但未成功,用annotate方法还导致图表压缩。实际图表中,翻转后的x轴每个类别对应8个误差棒,且“National average”线并不总是与柱状图顶部平行。调整color和fill的manual设置、添加新geom_point等方法都没用,求可行方案。
解决方案
核心思路是把误差棒的颜色映射到变量,而非直接硬编码color参数,让ggplot自动生成对应图例。具体步骤如下:
- 单独整理误差棒数据:将所有置信区间数据提取为独立数据框,包含分组、位置、上下限等字段,统一用一个
geom_errorbar绘制,避免多次调用。 - 在
aes中映射color:让误差棒颜色与评估阶段关联,同时指定对应颜色值。 - 调整图例顺序与样式:确保新颜色图例和原有填充图例区分开,显示顺序符合需求。
修改后的完整代码
library(ggplot2) library(dplyr) # 生成示例数据 plot_data <- expand.grid( Arviointi = c("First Assessment", "Second Assessment"), Mittari = c("happy_share", "lonely_share", "self_satisfaction_share", "enjoyment_share") ) plot_data <- plot_data %>% mutate(value = runif(n(), 0.15, 0.85)) # 自定义标签和回答选项 custom_labels <- c("statement1", "statement2", "question3?", "question4?") ss <- data.frame( Mittari = unique(plot_data$Mittari), vastaukset = c("Agree/Strongly agree", "Yes", "Yes", "Often/Very often") ) plot_data <- plot_data %>% left_join(ss, by = "Mittari") %>% mutate(facet = case_when( Mittari %in% c("happy_share", "lonely_share") ~ "Based on Teacher Assessments", Mittari %in% c("enjoyment_share", "self_satisfaction_share") ~ "Based on Child Self-Assessments" )) # 单独整理误差棒数据(示例为happy_share,可扩展到所有Mittari) error_data <- plot_data %>% filter(Mittari == "happy_share") %>% mutate( ymin = case_when( Arviointi == "First Assessment" ~ value - 0.05, Arviointi == "Second Assessment" ~ value - 0.08 ), ymax = case_when( Arviointi == "First Assessment" ~ value + 0.09, Arviointi == "Second Assessment" ~ value + 0.04 ), x_nudge = case_when( Arviointi == "First Assessment" ~ 0.1125, Arviointi == "Second Assessment" ~ -0.1125 ) ) # 绘制图表 ggplot(plot_data, aes(x = Mittari, y = value, fill = Arviointi)) + geom_col(position = position_dodge2(reverse = TRUE), width = 0.45, alpha = 0.85) + geom_vline(aes(xintercept = 0, color = "National Average")) + geom_text(aes(group = Mittari, y = 0.35, label = vastaukset), size = 3.4, hjust = 0.5, vjust = -2.1, colour = "grey8") + # 统一绘制误差棒,映射color到Arviointi geom_errorbar( data = error_data, aes(x = Mittari, ymin = ymin, ymax = ymax, color = Arviointi), position = position_nudge(x = error_data$x_nudge), width = 0, size = 1.5 ) + geom_errorbar(data = plot_data, aes(x = Mittari, ymin = value, ymax = value, group = Arviointi, width = 0.45), position = position_dodge2(reverse = TRUE)) + # 同时设置fill和color的手动颜色值 scale_fill_manual( values = c("First Assessment" = "steelblue", "Second Assessment" = "darkorange"), name = "Assessment" ) + scale_color_manual( values = c( "First Assessment" = "steelblue4", "Second Assessment" = "darkorange3", "National Average" = "black" ), name = "Legend" ) + facet_grid(facet ~., scales = "free_y", space = "free_y", switch = "y") + theme_minimal(base_family = "Arial") + coord_flip() + scale_y_continuous( labels = scales::percent_format(scale = 100), breaks = seq(0, 1, by = 0.1), minor_breaks = NULL, limits = c(0, 1) ) + scale_x_discrete(breaks = c("happy_share", "lonely_share", "self_satisfaction_share", "enjoyment_share"), labels = custom_labels) + labs(y = NULL, x = NULL) + # 调整图例顺序和样式 guides( fill = guide_legend(order = 1, title = "Assessment"), color = guide_legend(order = 2, title = "Confidence Interval & National Average") ) + theme( legend.text = element_text(size = 10.5), legend.spacing.y = unit(-0.1, "cm"), panel.spacing = unit(3, "lines"), strip.text.y.left = element_blank() )
补充说明
- 若要给所有
Mittari添加误差棒,只需扩展error_data的筛选条件,补充每个类别的ymin、ymax和x_nudge规则。 - 颜色映射到变量后,ggplot自动生成图例,无需手动添加annotate或额外geom元素,避免图表压缩问题。
- 通过
scale_color_manual可统一控制误差棒和“National Average”线的颜色,同时在图例中展示。
内容的提问来源于stack exchange,提问作者Billyboy
相关产品推荐
相关产品推荐

