You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在含柱状图与散点的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 17:55:14