如何为ggplot分面地图的每个分面设置对应政党渐变配色?
问题:为每个政党分面地图设置对应渐变配色
需求说明
我用ggplot绘制欧洲社会调查(ESS)的政党偏好数据,要给每个政党做单独的分面地图,每个分面用对应政党的颜色,颜色越深代表得票越多。
数据结构
head(party_votes_summary) # A tibble: 5 × 7 # Groups: NUTS_NAME [5] NUTS_NAME all_votes total_votes geometry percentage_votes geometry.y <chr> <fct> <int> <MULTIPOLYGON [m]> <dbl> <MULTIPOLYGON [m]> 1 Centro (IT) Forza Italia 18 (((4358646 2346312, 4371… 0.0111 (((4358646 2346312, 4371… 2 Isole Fratelli d'… 0 (((4787072 1652570, 4774… NA EMPTY 3 Nord-Est Altro 34 (((4510729 2621661, 4527… 0.0209 (((4510729 2621661, 4527… 4 Nord-Ovest Forza Italia 37 (((4386364 2524813, 4371… 0.0228 (((4386364 2524813, 4371… 5 Sud Fratelli d'… 16 (((4945372 2007501, 4997… 0.00984 (((4945372 2007501, 4997… # ℹ 1 more variable: NUTS_ID <chr>
当前代码
ggplot(party_votes_summary) + geom_sf(aes(fill = total_votes, geometry = geometry), color = "black") + facet_wrap(~ all_votes, labeller = labeller(all_votes = c( "Partido Democratico (PD)" = "Partido Democratico", "Sinistra Ecologia e Libertà (SEL)" = "Sinistra Ecologia e Libertà", "Popolo delle Libertà (PdL)" = "Popolo delle Libertà" ))) + labs(title = "Summary of Votes per Party per Region", fill = "Party") + theme(axis.text.x = element_blank(), axis.text.y = element_blank(), axis.ticks = element_blank())+ scale_fill_distiller(palette = "Blues", direction = 1)
尝试修改后的代码及报错
修改后的代码:
ggplot(party_votes_summary) + geom_sf(aes(fill = total_votes, geometry = geometry), color = "black") + facet_wrap(~ all_votes, labeller = labeller(all_votes = c( "Partido Democratico (PD)" = "Partido Democratico", "Sinistra Ecologia e Libertà (SEL)" = "Sinistra Ecologia e Libertà", "Popolo delle Libertà (PdL)" = "Popolo delle Libertà" ))) + labs(title = "Summary of Votes per Party per Region", fill = "Party") + theme(axis.text.x = element_blank(), axis.text.y = element_blank(), axis.ticks = element_blank())+ scale_fill_manual(values = party_palette)
报错信息:
Error in
scale_fill_manual():
! Continuous values supplied to discrete scale.
ℹ Example values: 261, 261, 261, 261, and 261
尝试过的颜色向量
party_colours <- c("Movimento 5 Stelle" = "#EED924", "Lega" = "#008000", "Partido Democratico (PD)" = "#DC143C", "Forza Italia" = "#0087DC", "Fratelli d'Italia" = "darkblue", "SVP-PATT"="#8a8a8a", "+ Europa" = "darkgreen", "Altro"="whitesmoke", "Sinistra Ecologia e Libertà (SEL)"="palegreen2", "Liberi e Uguali" = "darkred", "Popolo delle Libertà (PdL)" = "#0099DC", "La Destra" = "royalblue") party_palette <- c( "Movimento 5 Stelle" = scale_fill_brewer(palette = "OrRd"), "Lega" = scale_fill_brewer(palette = "Greens"), "Partido Democratico (PD)" = scale_fill_brewer(palette = "Reds"), "Forza Italia" = scale_fill_brewer(palette = "Blues"), "Fratelli d'Italia" = scale_fill_brewer(palette = "Blues"), "SVP-PATT" = scale_fill_brewer(palette = "Greys"), "+ Europa" = scale_fill_brewer(palette = "Greens"), "Altro" = scale_fill_brewer(palette = "Greys"), "Sinistra Ecologia e Libertà (SEL)" = scale_fill_brewer(palette = "Greens"), "Liberi e Uguali" = scale_fill_brewer(palette = "Reds"), "Popolo delle Libertà (PdL)" = scale_fill_brewer(palette = "Blues"), "La Destra" = scale_fill_brewer(palette = "Blues"))
解决方案
核心问题是total_votes是连续变量,不能用离散的scale_fill_manual,且ggplot默认不支持为每个分面单独设置渐变配色。以下提供两种可行方法:
方法1:用ggh4x实现分面专属渐变配色
- 安装并加载依赖包:
install.packages("ggh4x") library(ggh4x) library(dplyr) library(purrr) library(scales)
- 预处理数据,为每个政党的得票做归一化并映射到对应渐变色:
# 定义每个政党的渐变色区间(浅-主色-深) party_pal_map <- list( "Movimento 5 Stelle" = gradient_n_pal(c("#FFFFE0", "#EED924", "#D4A017"))(seq(0,1,length.out=100)), "Lega" = gradient_n_pal(c("#E8F5E9", "#008000", "#005000"))(seq(0,1,length.out=100)), "Partido Democratico (PD)" = gradient_n_pal(c("#FFEBEE", "#DC143C", "#990011"))(seq(0,1,length.out=100)), "Forza Italia" = gradient_n_pal(c("#E3F2FD", "#0087DC", "#005A9E"))(seq(0,1,length.out=100)), "Fratelli d'Italia" = gradient_n_pal(c("#E3F2FD", "darkblue", "#003366"))(seq(0,1,length.out=100)), "SVP-PATT" = gradient_n_pal(c("#F5F5F5", "#8a8a8a", "#555555"))(seq(0,1,length.out=100)), "+ Europa" = gradient_n_pal(c("#E8F5E9", "darkgreen", "#004D00"))(seq(0,1,length.out=100)), "Altro" = gradient_n_pal(c("#FFFFFF", "whitesmoke", "#CCCCCC"))(seq(0,1,length.out=100)), "Sinistra Ecologia e Libertà (SEL)" = gradient_n_pal(c("#E8F5E9", "palegreen2", "#66BB6A"))(seq(0,1,length.out=100)), "Liberi e Uguali" = gradient_n_pal(c("#FFEBEE", "darkred", "#880000"))(seq(0,1,length.out=100)), "Popolo delle Libertà (PdL)" = gradient_n_pal(c("#E3F2FD", "#0099DC", "#006699"))(seq(0,1,length.out=100)), "La Destra" = gradient_n_pal(c("#E3F2FD", "royalblue", "#0047AB"))(seq(0,1,length.out=100)) ) # 归一化得票并匹配颜色 party_votes_summary <- party_votes_summary %>% group_by(all_votes) %>% mutate(norm_votes = rescale(total_votes, to = c(0,1))) %>% ungroup() %>% mutate(fill_col = map2_chr(all_votes, norm_votes, ~ party_pal_map[[.x]][round(.y*99)+1]))
- 绘制分面地图:
ggplot(party_votes_summary) + geom_sf(aes(fill = fill_col, geometry = geometry), color = "black") + facet_wrap2(~ all_votes, labeller = labeller(all_votes = c( "Partido Democratico (PD)" = "Partido Democratico", "Sinistra Ecologia e Libertà (SEL)" = "Sinistra Ecologia e Libertà", "Popolo delle Libertà (PdL)" = "Popolo delle Libertà" ))) + labs(title = "Summary of Votes per Party per Region") + theme(axis.text.x = element_blank(), axis.text.y = element_blank(), axis.ticks = element_blank(), legend.position = "none") + scale_fill_identity()
方法2:拆分数据逐个绘图再拼接
- 安装并加载依赖包:
install.packages(c("purrr", "patchwork")) library(purrr) library(patchwork) library(scales)
- 定义单个政党的绘图函数:
plot_party <- function(party_data, party_name) { # 获取政党主色并生成渐变调色板 main_col <- party_colours[[party_name]] pal <- gradient_n_pal(c(lighten(main_col, 0.5), main_col, darken(main_col, 0.5)))(seq(0,1,length.out=100)) ggplot(party_data) + geom_sf(aes(fill = total_votes, geometry = geometry), color = "black") + scale_fill_gradientn(colours = pal, na.value = "white") + labs(title = party_name, fill = "得票数") + theme(axis.text.x = element_blank(), axis.text.y = element_blank(), axis.ticks = element_blank(), plot.title = element_text(size=10)) }
- 拆分数据并拼接所有图表:
# 按政党拆分数据 party_list <- split(party_votes_summary, party_votes_summary$all_votes) # 生成每个政党的地图 plots <- imap(party_list, plot_party) # 拼接成统一布局 wrap_plots(plots, ncol=3) + plot_annotation(title = "Summary of Votes per Party per Region")
内容的提问来源于stack exchange,提问作者Teresa Petra
相关产品推荐
相关产品推荐

