如何用ggplot2与newggscale实现城乡双组比例符号渐变色映射
使用ggplot2和newggscale制作带多组渐变比例符号的地图问题
需求说明
- 用R的ggplot2和newggscale包制作地图,为城市(Urban)和乡村(Rural)位置添加比例符号,符号颜色随COUNT数值渐变:
- 城市:蓝色系渐变,COUNT越低颜色越浅,越高越深
- 乡村:红色系渐变,COUNT越低颜色越浅,越高越深
初始实现问题
在使用new_scale_color()/new_scale_fill()管理多组渐变色时遇到两个问题:
- 出现两个DMA图例
- 城乡位置未按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个对应COUNT大小的比例符号图例
- 1个包含城市蓝色渐变、乡村红色渐变的颜色图例
- 实际:
- 出现两个DMA图例
- 城乡点未按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
相关产品推荐
相关产品推荐

