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

如何用ggplot2与newggscale实现城乡双组比例符号渐变色映射

使用ggplot2和newggscale制作带多组渐变比例符号的地图问题

需求说明

  • 用R的ggplot2和newggscale包制作地图,为城市(Urban)和乡村(Rural)位置添加比例符号,符号颜色随COUNT数值渐变:
    • 城市:蓝色系渐变,COUNT越低颜色越浅,越高越深
    • 乡村:红色系渐变,COUNT越低颜色越浅,越高越深

初始实现问题

在使用new_scale_color()/new_scale_fill()管理多组渐变色时遇到两个问题:

  1. 出现两个DMA图例
  2. 城乡位置未按COUNT值呈现正确的渐变色

初始尝试代码

ok_cities_correct_clean <- ok_cities_correct_clean %>%
  mutate(
    color_gradient = case_when(
      # 城市按COUNT划分颜色区间
      CLASSIF == "Urban" & COUNT <= 10 ~ "lightblue",      # COUNT 1-10
      CLASSIF == "Urban" & COUNT <= 20 ~ "lightskyblue",   # COUNT 10-20
      CLASSIF == "Urban" & COUNT <= 30 ~ "dodgerblue",     # COUNT 20-30
      CLASSIF == "Urban" & COUNT > 30 ~ "darkblue",        # COUNT 30+
      
      # 乡村按COUNT划分颜色区间
      CLASSIF == "Rural" & COUNT <= 10 ~ "lightpink",      # COUNT 1-10
      CLASSIF == "Rural" & COUNT <= 20 ~ "lightcoral",     # COUNT 10-20
      CLASSIF == "Rural" & COUNT <= 30 ~ "firebrick",      # COUNT 20-30
      CLASSIF == "Rural" & COUNT > 30 ~ "darkred",         # COUNT 30+
      
      TRUE ~ "gray"  # 未匹配情况默认颜色
    )
  )

ggplot() +
  
  # 添加俄克拉荷马州郡县(浅灰填充,无边界)
  geom_sf(
    data = ok_counties_reproj,
    fill = "#f5f5f5",
    color = "black",
    size = 0
  ) +
  
  # 添加DMA边界(塔尔萨和俄克拉荷马城)
  geom_sf(
    data = ok_DMA,
    aes(fill = DMA, color = DMA),
    linewidth = 1.5,
    alpha = 0.75
  ) +
  
  # 设置DMA填充色
  scale_fill_manual(
    values = c("Tulsa, OK" = "#4575b4", 
               "Oklahoma City, OK" = "#5ab4ac")
  ) +
  
  # 设置DMA边界色
  scale_color_manual(
    values = c("Tulsa, OK" = "#4575b4", 
               "Oklahoma City, OK" = "#5ab4ac")
  ) +
  
  # 添加郡县边界(无填充)
  geom_sf(
    data = ok_counties_reproj,
    fill = NA,
    color = "black",
    size = 1
  ) +
  
  new_scale_color() +
  
  # 添加城市点:按color_gradient填充,size对应COUNT
  geom_sf(
    data = ok_cities_correct_clean %>%
      filter(COUNT > 0),
    aes(size = COUNT, fill = color_gradient),
    show.legend = TRUE
  ) +
  
  # 调整比例符号的大小范围
  scale_size_continuous(
    range = c(1, 10),
    name = "提及频率"
  )

预期效果 vs 实际效果

  • 预期:
    1. 1个对应COUNT大小的比例符号图例
    2. 1个包含城市蓝色渐变、乡村红色渐变的颜色图例
  • 实际:
    1. 出现两个DMA图例
    2. 城乡点未按COUNT正确显示渐变色

更新后的问题

使用修改后的代码解决了渐变色问题,但出现重复的DMA图例(一个正确,另一个边框正确但填充为灰色),删除重复图例时会影响其他地图元素。

更新后的代码

# 过滤COUNT=0的记录并分箱
ok_cities_correct_clean <- ok_cities_correct_clean %>%
  filter(COUNT > 0) %>%
  mutate(
    color_gradient = cut(
      COUNT,
      breaks = c(0, 10, 20, 30, Inf),
      labels = c("1 - 10", "11 - 20", "21 - 30", "> 30"),
      right = TRUE
    )
  )

# 定义颜色调色板
cities_urban <- c("lightblue", "lightskyblue", "dodgerblue", "darkblue")
names(cities_urban) <- labels


cities_rural <- c("lightpink", "lightcoral", "firebrick", "darkred")
names(cities_rural) <- labels



ggplot() +
  
  # 添加俄克拉荷马州郡县
  geom_sf(
    data = ok_counties_reproj,
    fill = "#f5f5f5",
    color = "black",
    size = 0
  ) +
  
  # 添加DMA边界
  geom_sf(
    data = ok_DMA,
    aes(fill = DMA, color = DMA),
    linewidth = 1.5,
    alpha = 0.75,
    show.legend = c(fill = TRUE, color = FALSE)
  ) +
  
  # 添加郡县边界(无填充)
  geom_sf(
    data = ok_counties_reproj,
    fill = NA,
    color = "black",
    size = 1
  ) +
  
  # 设置DMA填充与边界色
  scale_fill_manual(
    values = c(
      "Tulsa, OK" = "#4575b4",
      "Oklahoma City, OK" = "#5ab4ac"
    ),
    aesthetics = c("fill", "color"),
    guide = guide_legend(override.aes = list(
      color = c("#5ab4ac", "#4575b4")
    ))
  ) +
  
  new_scale_color() +
  
  # 添加城市点(Urban)
  geom_sf(
    data = ok_cities_correct_clean %>%
      filter(COUNT > 0, CLASSIF == "Urban"),
    aes(size = COUNT, color = color_gradient)
  ) +
  
  scale_color_manual(
    values = cities_urban, na.value = "gray", name = "城市"
  ) +
  
  new_scale_color() +
  
  # 添加乡村点(Rural)
  geom_sf(
    data = ok_cities_correct_clean %>%
      filter(COUNT > 0, CLASSIF == "Rural"),
    aes(size = COUNT, color = color_gradient)
  ) +
  
  scale_color_manual(
    values = cities_rural, na.value = "gray", name = "乡村"
  ) +
  
  scale_size_continuous(
    range = c(1, 10),
    name = "提及频率"
  )

解决建议

1. 消除重复DMA图例

问题根源是scale_fill_manual中aesthetics = c("fill", "color")的设置,结合后续new_scale_color()调用,导致DMA的color尺度残留并生成额外图例。修改方案:

  • 移除scale_fill_manual中的aesthetics参数
  • 单独设置scale_color_manual控制DMA边界色,并通过show.legend = FALSE隐藏其图例
  • 保留scale_fill_manual控制DMA填充色,作为唯一的DMA图例

修改后的DMA相关代码片段:

# 添加DMA边界
geom_sf(
  data = ok_DMA,
  aes(fill = DMA, color = DMA),
  linewidth = 1.5,
  alpha = 0.75
) +

# 设置DMA填充色(显示图例)
scale_fill_manual(
  values = c(
    "Tulsa, OK" = "#4575b4",
    "Oklahoma City, OK" = "#5ab4ac"
  ),
  name = "DMA区域"
) +

# 设置DMA边界色(隐藏图例)
scale_color_manual(
  values = c(
    "Tulsa, OK" = "#4575b4",
    "Oklahoma City, OK" = "#5ab4ac"
  ),
  show.legend = FALSE
) +

2. 优化颜色图例与比例符号的一致性

  • 确保城乡点的color_gradient分箱标签统一,让两个颜色图例的区间对应一致
  • 通过guide_legend调整颜色图例的符号大小,与比例符号的尺寸匹配:
scale_color_manual(
  values = cities_urban, na.value = "gray", name = "城市",
  guide = guide_legend(override.aes = list(size = c(3,5,7,9)))
)

完整修正后的代码

# 数据预处理
ok_cities_correct_clean <- ok_cities_correct_clean %>%
  filter(COUNT > 0) %>%
  mutate(
    color_gradient = cut(
      COUNT,
      breaks = c(0, 10, 20, 30, Inf),
      labels = c("1 - 10", "11 - 20", "21 - 30", "> 30"),
      right = TRUE
    )
  )

# 定义调色板
cities_urban <- c("lightblue", "lightskyblue", "dodgerblue", "darkblue")
names(cities_urban) <- levels(ok_cities_correct_clean$color_gradient)

cities_rural <- c("lightpink", "lightcoral", "firebrick", "darkred")
names(cities_rural) <- levels(ok_cities_correct_clean$color_gradient)

# 绘制地图
ggplot() +
  # 郡县底图
  geom_sf(
    data = ok_counties_reproj,
    fill = "#f5f5f5",
    color = "black",
    size = 0
  ) +
  # DMA区域
  geom_sf(
    data = ok_DMA,
    aes(fill = DMA, color = DMA),
    linewidth = 1.5,
    alpha = 0.75
  ) +
  # DMA填充色图例(唯一)
  scale_fill_manual(
    values = c(
      "Tulsa, OK" = "#4575b4",
      "Oklahoma City, OK" = "#5ab4ac"
    ),
    name = "DMA区域"
  ) +
  # DMA边界色(隐藏图例)
  scale_color_manual(
    values = c(
      "Tulsa, OK" = "#4575b4",
      "Oklahoma City, OK" = "#5ab4ac"
    ),
    show.legend = FALSE
  ) +
  # 郡县边界
  geom_sf(
    data = ok_counties_reproj,
    fill = NA,
    color = "black",
    size = 1
  ) +
  # 切换颜色尺度(城市点)
  new_scale_color() +
  geom_sf(
    data = filter(ok_cities_correct_clean, CLASSIF == "Urban"),
    aes(size = COUNT, color = color_gradient)
  ) +
  scale_color_manual(
    values = cities_urban,
    name = "城市",
    guide = guide_legend(override.aes = list(size = c(3,5,7,9)))
  ) +
  # 切换颜色尺度(乡村点)
  new_scale_color() +
  geom_sf(
    data = filter(ok_cities_correct_clean, CLASSIF == "Rural"),
    aes(size = COUNT, color = color_gradient)
  ) +
  scale_color_manual(
    values = cities_rural,
    name = "乡村",
    guide = guide_legend(override.aes = list(size = c(3,5,7,9)))
  ) +
  # 比例符号尺度
  scale_size_continuous(
    range = c(1, 10),
    name = "提及频率"
  ) +
  # 可选:调整图例位置
  theme(legend.position = "right")

内容的提问来源于stack exchange,提问作者Victoria Johnson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 20:27:05