如何为ggplot分面地图设置不同的scale_fill_gradient高端颜色?
问题
使用ggplot()和geom_sf()绘制分面地图,通过value变量用scale_fill_gradient2()为地图单元着色,按group变量分面。当前单渐变填充正常,但希望按分面设置渐变高端的颜色(Group A高值为红色,Group B高值为绿色)。已在数据框中添加color_high列,但无法将该列颜色值应用到填充渐变中,求实现方法。
附可运行的单渐变填充代码:
library(sf) library(tidyverse) theme_set(theme_bw()) library(giscoR) ger_fedstates <- gisco_get_nuts(nuts_level = 1, resolution = 10, country = "Germany", year = 2021) dat <- read.table(text = "state value group Sachsen 10 a Sachsen 1 b Bayern 3 a Bayern 30 b Rheinland-Pfalz 50 a Rheinland-Pfalz 50 b Saarland 70 a Saarland 70 b Schleswig-Holstein 9 a Schleswig-Holstein 90 b Niedersachsen 100 a Niedersachsen 100 b Nordrhein-Westfalen 80 a Nordrhein-Westfalen 80 b Baden-Württemberg 60 a Baden-Württemberg 60 b Brandenburg 40 a Brandenburg 40 b Mecklenburg-Vorpommern 20 a Mecklenburg-Vorpommern 20 b Bremen 40 a Bremen 40 b Hamburg 60 a Hamburg 60 b Hessen 15 a Hessen 15 b Berlin 10 a Berlin 10 b Thüringen 80 a Thüringen 80 b Sachsen-Anhalt 20 a Sachsen-Anhalt 20 b", header = T) %>% mutate(color_high = case_when(group=="a"~"red", group=="b"~"green")) plot_df <- full_join(ger_fedstates, dat, by=c("NUTS_NAME" = "state")) plot_df %>% ggplot() + geom_sf(aes(fill = value)) + theme(axis.text.x = element_blank(), axis.text.y = element_blank(), axis.line.x = element_blank(), axis.line.y = element_blank(), legend.position = "right", legend.title.align = 0) + scale_fill_gradient2(low = "grey40", mid = "white", high = "#0000ff", # 这里希望用color_high列的值 midpoint=50, guide = "colourbar", aesthetics = "fill") + facet_wrap(~group, labeller = labeller(group=c(a="Group A", b="Group B", c="Group C")))
预期效果:Group A高值显示红色,Group B高值显示绿色。
解决方案
单一的scale_fill_gradient2无法直接实现分面动态渐变颜色,因为它是全局生效的。以下提供两种可行实现方式:
方法1:自定义调色逻辑(无需额外包)
核心思路是按group归一化value,结合color_high列的颜色构建渐变映射,适合需要统一颜色条的场景:
library(sf) library(tidyverse) theme_set(theme_bw()) library(giscoR) ger_fedstates <- gisco_get_nuts(nuts_level = 1, resolution = 10, country = "Germany", year = 2021) dat <- read.table(text = "state value group Sachsen 10 a Sachsen 1 b Bayern 3 a Bayern 30 b Rheinland-Pfalz 50 a Rheinland-Pfalz 50 b Saarland 70 a Saarland 70 b Schleswig-Holstein 9 a Schleswig-Holstein 90 b Niedersachsen 100 a Niedersachsen 100 b Nordrhein-Westfalen 80 a Nordrhein-Westfalen 80 b Baden-Württemberg 60 a Baden-Württemberg 60 b Brandenburg 40 a Brandenburg 40 b Mecklenburg-Vorpommern 20 a Mecklenburg-Vorpommern 20 b Bremen 40 a Bremen 40 b Hamburg 60 a Hamburg 60 b Hessen 15 a Hessen 15 b Berlin 10 a Berlin 10 b Thüringen 80 a Thüringen 80 b Sachsen-Anhalt 20 a Sachsen-Anhalt 20 b", header = T) %>% mutate(color_high = case_when(group=="a"~"red", group=="b"~"green")) %>% # 按group归一化value,将每个组的value映射到0-1区间 group_by(group) %>% mutate(norm_value = scales::rescale(value, to = c(0,1))) %>% ungroup() plot_df <- full_join(ger_fedstates, dat, by=c("NUTS_NAME" = "state")) plot_df %>% ggplot() + geom_sf(aes(fill = norm_value, color = color_high)) + # 基础渐变:从深灰到白色 scale_fill_gradient2(low = "grey40", mid = "white", high = "white", midpoint = 0.5, guide = "none") + # 用color_high的颜色作为渐变终点,通过alpha映射归一化后的value scale_color_identity(aesthetics = c("fill"), guide = "colourbar", breaks = c(0, 0.5, 1), labels = c(min(plot_df$value), 50, max(plot_df$value))) + theme(axis.text.x = element_blank(), axis.text.y = element_blank(), axis.line.x = element_blank(), axis.line.y = element_blank(), legend.position = "right", legend.title.align = 0) + labs(fill = "Value") + facet_wrap(~group, labeller = labeller(group=c(a="Group A", b="Group B", c="Group C")))
方法2:使用ggnewscale实现分面独立刻度
如果需要每个分面保留独立的颜色条,可以用ggnewscale为每个group设置单独的填充刻度:
library(sf) library(tidyverse) theme_set(theme_bw()) library(giscoR) library(ggnewscale) ger_fedstates <- gisco_get_nuts(nuts_level = 1, resolution = 10, country = "Germany", year = 2021) dat <- read.table(text = "state value group Sachsen 10 a Sachsen 1 b Bayern 3 a Bayern 30 b Rheinland-Pfalz 50 a Rheinland-Pfalz 50 b Saarland 70 a Saarland 70 b Schleswig-Holstein 9 a Schleswig-Holstein 90 b Niedersachsen 100 a Niedersachsen 100 b Nordrhein-Westfalen 80 a Nordrhein-Westfalen 80 b Baden-Württemberg 60 a Baden-Württemberg 60 b Brandenburg 40 a Brandenburg 40 b Mecklenburg-Vorpommern 20 a Mecklenburg-Vorpommern 20 b Bremen 40 a Bremen 40 b Hamburg 60 a Hamburg 60 b Hessen 15 a Hessen 15 b Berlin 10 a Berlin 10 b Thüringen 80 a Thüringen 80 b Sachsen-Anhalt 20 a Sachsen-Anhalt 20 b", header = T) %>% mutate(color_high = case_when(group=="a"~"red", group=="b"~"green")) plot_df <- full_join(ger_fedstates, dat, by=c("NUTS_NAME" = "state")) ggplot() + # 绘制Group A的地图及对应渐变刻度 geom_sf(data = filter(plot_df, group == "a"), aes(fill = value)) + scale_fill_gradient2(low = "grey40", mid = "white", high = "red", midpoint = 50, name = "Group A Value") + # 开启新的填充刻度上下文 new_scale_fill() + # 绘制Group B的地图及对应渐变刻度 geom_sf(data = filter(plot_df, group == "b"), aes(fill = value)) + scale_fill_gradient2(low = "grey40", mid = "white", high = "green", midpoint = 50, name = "Group B Value") + theme(axis.text.x = element_blank(), axis.text.y = element_blank(), axis.line.x = element_blank(), axis.line.y = element_blank(), legend.position = "right", legend.title.align = 0) + facet_wrap(~group, labeller = labeller(group=c(a="Group A", b="Group B", c="Group C")))
内容的提问来源于stack exchange,提问作者Ivo
相关产品推荐
相关产品推荐

