如何在ggplot中为两个geom_sf图层设置不同的scale_fill_gradientn?
解决地图可视化中极值点干扰的问题
问题背景
现有数据集包含10个国家的Count数值,其中美国的Count(3000000)远高于其他国家,导致地图可视化时其余国家的点过小且颜色近乎白色。需求明确:
- 非美国国家保留原有的Blues 3色系填充和大小映射逻辑
- 美国单独用红色填充,大小与第二大的巴西(Count=300000)保持一致
解决方案
核心思路是拆分数据集,分两个图层绘制:非美国图层沿用原有颜色和大小映射,美国图层直接指定固定红色,并将其Count值替换为巴西的数值以匹配大小,无需额外使用ggnewscale包。
完整可运行代码
library(tidyverse) library(sf) library(giscoR) # 原始数据集 temp <- data.frame(Country = c("United States", "Brazil", "Mexico", "Canada", "Argentina", "Chile", "Peru", "Guatemala", 'Ecuador', "United Kingdom"), Count = c(3000000, 300000, 250000, 135000, 100000, 99000, 98000, 47000, 40000, 39000)) # 获取国家地理数据及中心点 all_countries <- gisco_get_countries() symbol_pos <- st_centroid(all_countries, of_largest_polygon = TRUE) # 合并数据并拆分 temp2 <- temp %>% left_join(symbol_pos, by=c("Country" = "NAME_ENGL")) %>% arrange(desc(Count)) # 拆分数据集:非美国组 + 修改后的美国组(匹配巴西的Count值) non_usa <- temp2 %>% filter(Country != "United States") usa_data <- temp2 %>% filter(Country == "United States") %>% mutate(Count = temp2$Count[temp2$Country == "Brazil"]) # 绘制地图 ggplot() + # 底图:所有国家轮廓 geom_sf(data = all_countries, fill = "white") + # 非美国国家图层:沿用原有颜色和大小映射 geom_sf(data = non_usa, pch = 21, mapping = aes(size = Count, geometry = geometry, fill = Count)) + # 大小比例尺设置 scale_size(range = c(1, 20), guide = guide_legend(direction = "horizontal", nrow = 1, label.position = "bottom")) + # 填充色比例尺设置 scale_fill_gradientn(colours = hcl.colors(10, "Blues 3", rev = TRUE, alpha = 0.9)) + # 美国图层:固定红色填充,使用修改后的Count匹配巴西大小 geom_sf(data = usa_data, pch = 21, mapping = aes(size = Count, geometry = geometry), fill = "red", alpha = 0.9) + # 图例优化 guides(fill = guide_legend(title = ""), size = guide_legend(title = "Count")) + theme_void() + theme(legend.position = "bottom")
关键说明
- 美国图层的
fill直接设为固定值red,而非映射到变量,因此不会与前一个图层的填充比例尺冲突,无需额外加载ggnewscale - 通过修改美国的
Count值为巴西的数值,确保其大小与巴西一致,同时不破坏其他国家的大小映射逻辑 - 图例仅展示非美国国家的颜色和大小规则,避免极值干扰图例可读性
内容的提问来源于stack exchange,提问作者Jacob
相关产品推荐
相关产品推荐

