如何在含柱状图与散点的ggplot绘图中正确显示图例
问题:ggplot图例无法正确匹配柱状图与散点符号
我有如下结构的DataFrame:
COUNTRY YEAR y AT 2019 25 AT 2020 38.0 AT 2021 23.4 BE 2019 11.1 BE 2020 18.6 BE 2021 15.0 DK 2019 31.1 DK 2020 43.6 DK 2021 42.0
需求是用柱状图展示2021年的数据,散点展示2019、2020年的数据,但当前图例无法正确显示对应符号。原代码如下:
countries <- c("AT", "BE", "DK") years <- c(2019, 2020, 2021) values <- c(25, 38.0, 23.4, 11.1, 18.6, 15.0, 31.1, 43.6, 42.0) df <- data.frame( COUNTRY = rep(countries, each = 3), YEAR = rep(years, times = 3), y = values ) ggplot(df, aes(x = COUNTRY, y = y, group = YEAR, shape = as.factor(YEAR))) + geom_bar(data = subset(df, YEAR == 2021), aes(fill = "2021"), stat = 'identity', position = 'dodge', alpha = 0.7) + geom_point(data = subset(df, YEAR == 2020), aes(fill = "2020"), position = position_dodge(width = 0.4), size = 3, shape = 19, color = "red") + geom_point(data = subset(df, YEAR == 2019), aes(fill = "2019"), position = position_dodge(width = 0.4), size = 3, shape = 4, color = "blue") + scale_fill_manual(values = c("2021" = "grey", "2020" = "red", "2019" = "blue")) + labs(x = "Country", y = "y", fill = "") + theme_minimal() + theme(legend.position = "right")
希望图例中2021年显示柱状/填充方块,2019和2020年分别显示对应的散点形状。
解决方案
原代码的问题在于把所有年份的图例都绑定到fill属性,但散点的形状和颜色没有与图例建立正确关联,导致图例符号统一显示为方块。修改思路是将柱状图的fill与散点的shape/color统一映射到YEAR因子,再通过手动刻度和图例引导来匹配样式:
修改后的代码:
countries <- c("AT", "BE", "DK") years <- c(2019, 2020, 2021) values <- c(25, 38.0, 23.4, 11.1, 18.6, 15.0, 31.1, 43.6, 42.0) df <- data.frame( COUNTRY = rep(countries, each = 3), YEAR = factor(rep(years, times = 3), levels = years), # 转换为有序因子 y = values ) ggplot(df, aes(x = COUNTRY, y = y, group = YEAR)) + # 2021年柱状图,映射fill到YEAR geom_bar(data = subset(df, YEAR == 2021), aes(fill = YEAR), stat = 'identity', position = position_dodge(width = 0.8), alpha = 0.7) + # 2019、2020年散点,映射shape和color到YEAR geom_point(data = subset(df, YEAR != 2021), aes(shape = YEAR, color = YEAR), position = position_dodge(width = 0.8), size = 3) + # 手动设置填充色、形状、颜色 scale_fill_manual(values = c("2019" = NA, "2020" = NA, "2021" = "grey")) + scale_shape_manual(values = c("2019" = 4, "2020" = 19, "2021" = 15)) + # 15是填充方块,对应柱状图 scale_color_manual(values = c("2019" = "blue", "2020" = "red", "2021" = NA)) + # 统一图例,合并fill、shape、color的引导项 guides( fill = guide_legend(override.aes = list(shape = NA)), shape = guide_legend(override.aes = list(fill = NA)), color = guide_legend(override.aes = list(fill = NA)) ) + # 合并图例为一个,去掉冗余标题 labs(x = "Country", y = "y", fill = "Year", shape = "Year", color = "Year") + theme_minimal() + theme(legend.position = "right")
关键修改说明
- 将
YEAR转换为有序因子,确保图例顺序符合年份逻辑 - 全局aes不再绑定shape,而是在各geom中分别映射
fill(柱状图)和shape/color(散点)到YEAR - 通过
scale_*_manual分别设置各年份的样式:2021年仅保留fill,2019/2020年仅保留shape和color - 使用
guides()手动覆盖图例的aes属性,避免散点图例显示填充色、柱状图图例显示形状 - 统一所有图例的标题为"Year",让ggplot自动合并为一个图例
这样修改后,图例中2021年显示填充方块(对应柱状图),2019年显示蓝色叉形,2020年显示红色圆点,完美匹配图表元素。
内容的提问来源于stack exchange,提问作者Bob
相关产品推荐
相关产品推荐

