如何基于两列数据为美国各州分区域实现自定义渐变填充?
问题描述
需要为美国各州的县级地图分区域上色:以州质心为界,州质心上方的县基于Qt列数值使用绿色系配色,州质心下方的县基于Apo列数值使用蓝色系配色。现有代码仅显示蓝色系,无法实现分区域的双色系需求。
解决方案
方案1:使用ggnewscale实现独立填充比例尺
该方案让Apo和Qt两个变量各自使用独立的颜色映射,无需缩放数值,逻辑更清晰:
步骤1:安装并加载依赖包
install.packages("ggnewscale") # 未安装时执行 library(tidyverse) library(usmap) library(RColorBrewer) library(ggnewscale)
步骤2:整理数据(简化原处理逻辑)
# 原始数据集 read.table(text = "State Apo Qt NJ 1 10 MO 2 20 SD 3 30 NY 4 40 FL 5 50 OK 6 60 NE 7 70 KY 8 80 ME 9 90 CA 10 100 NC 11 110 MA 12 120 CT 13 140", header = T, stringsAsFactor = F) -> ex1 # 转换为长格式,保留州名、变量类型和对应数值 ex1 %>% pivot_longer(-State, names_to = "var", values_to = "val") -> ex_long # 获取县级地图数据,标记每个县对应的变量类型(Apo/Qt) usc <- usmap::us_map(regions = "counties") us_state <- usmap::us_map() usc %>% group_by(full, county) %>% mutate(county_y_center = mean(range(y))) %>% group_by(full) %>% mutate(state_y_center = mean(range(y))) %>% # 根据质心位置标记变量类型 mutate(var = ifelse(state_y_center > county_y_center, "Apo", "Qt")) %>% # 关联原始数据集的数值 left_join(ex_long, by = c("abbr" = "State", "var" = "var")) -> usc_data
步骤3:分区域绘图
# 定义配色:Qt用绿色系,Apo用蓝色系 qt_palette <- colorRampPalette(brewer.pal(3, "Greens"))(10) apo_palette <- colorRampPalette(brewer.pal(3, "Blues"))(10) ggplot() + # 绘制Qt区域(质心上方的县) geom_polygon(data = usc_data %>% filter(var == "Qt"), aes(x = x, y = y, group = group, fill = val), color = NA) + # 设置Qt的颜色比例尺 scale_fill_gradientn(name = "Qt 值", colors = qt_palette, guide = guide_colorbar(barwidth = 0.8, barheight = 18)) + # 启用新的填充比例尺,用于Apo区域 new_scale_fill() + # 绘制Apo区域(质心下方的县) geom_polygon(data = usc_data %>% filter(var == "Apo"), aes(x = x, y = y, group = group, fill = val), color = NA) + # 设置Apo的颜色比例尺 scale_fill_gradientn(name = "Apo 值", colors = apo_palette, guide = guide_colorbar(barwidth = 0.8, barheight = 18)) + # 添加州边界 geom_polygon(data = us_state, aes(x = x, y = y, group = group), fill = NA, color = "black") + theme_void() + theme(legend.position = "right")
方案2:修正原代码逻辑(无需额外包)
如果不想引入新包,可调整数值缩放和比例尺设置,解决原代码的颜色覆盖问题:
# 原数据处理部分保持不变,直接修改绘图代码 mcolor <- c(colorRampPalette(brewer.pal(3, "Greens"))(3), colorRampPalette(brewer.pal(3, "Blues"))(3)) ggplot() + geom_polygon(data = usc_map_ex %>% filter(is.na(Apo)), aes(x,y, group = group, fill = Qt, color = "")) + # 调整Apo的缩放倍数,让数值范围与Qt不重叠 geom_polygon(data = usc_map_ex %>% filter(is.na(Qt)), aes(x,y, group = group, fill = Apo * 5, color = "")) + geom_polygon(data = us, aes(x,y, group = group), fill = NA, color = "black") + scale_colour_manual(values = 'transparent', guide = "none") + scale_fill_gradientn( name = "数值", breaks = c(10, 70, 140, 5, 25, 65), labels = c("Qt:10", "Qt:70", "Qt:140", "Apo:1", "Apo:5", "Apo:13"), # 对应颜色的位置:前3个绿色映射Qt范围,后3个蓝色映射Apo范围 values = c(0, 0.5, 1, 0, 0.5, 1) / 1, limits = c(0, 140), colors = mcolor, guide = guide_colorbar(barwidth = 0.8, barheight = 18) ) + theme_void()
方案对比
- 方案1:逻辑清晰,两个变量独立配色,支持分开显示图例,适合需要明确区分两类数值的场景
- 方案2:无需额外依赖包,但需手动调整数值缩放,图例合并为一个,适合只需要统一视觉呈现的场景
内容的提问来源于stack exchange,提问作者M--
相关产品推荐
相关产品推荐

