如何在ggplot中用颜色混合表示北卡州地图的多颜色平局?
北卡州县域颜色可视化需求与解决方案
1. 单一颜色分配地图
先为每个县随机分配单一颜色并生成地图,代码如下:
library(sf) library(dplyr) library(ggplot2) nc <- st_read(system.file("gpkg/nc.gpkg", package = "sf"), quiet = TRUE) %>% st_transform(st_crs(4326)) %>% st_cast("POLYGON") set.seed(123) colors <- c("red", "blue", "green", "yellow", "purple", "orange") favorite_color <- sample(colors, nrow(nc), replace = TRUE) my_df <- data.frame(NAME = nc$NAME, favorite_color) nc_merged <- merge(nc, my_df, by = "NAME", all.x = TRUE) ggplot(data = nc_merged) + geom_sf(aes(fill = favorite_color)) + scale_fill_manual(values = colors) + theme_minimal() + labs(title = "Favorite Color by County", fill = "Favorite Color")

2. 平局县设为白色的地图
制作允许县拥有多种偏好颜色的地图,平局县设为白色,代码如下:
set.seed(123) colors <- c("red", "blue", "green", "yellow", "purple", "orange") favorite_color <- replicate(nrow(nc), { sample_size <- sample(1:3, 1) sample(colors, sample_size, replace = FALSE) }) my_df <- data.frame(NAME = nc$NAME, favorite_color = sapply(favorite_color, function(x) paste(x, collapse = ", "))) my_df$favorite_color[sapply(favorite_color, length) > 1] <- NA nc_merged <- merge(nc, my_df, by = "NAME", all.x = TRUE) ggplot(data = nc_merged) + geom_sf(aes(fill = favorite_color)) + scale_fill_manual(values = c(colors, "white"), na.value = "white") + theme_minimal() + labs(title = "Favorite Color by County (with Ties)", fill = "Favorite Color")

核心问题
对于存在颜色平局(如2种或3种颜色)的县,能否将这些颜色混合生成新颜色?即无平局的县使用单一颜色,平局县使用混合后的颜色?
尝试的ggpattern方案(效果不佳)
初次尝试
用ggpattern实现但可读性极差:
set.seed(123) colors <- c("red", "blue", "green", "yellow", "purple", "orange") favorite_color <- replicate(nrow(nc), { sample_size <- sample(1:3, 1) sample(colors, sample_size, replace = FALSE) }) my_df <- data.frame(NAME = nc$NAME, favorite_color = sapply(favorite_color, function(x) paste(x, collapse = ", "))) unique_patterns <- unique(my_df$favorite_color) pattern_colors <- setNames(rainbow(length(unique_patterns)), unique_patterns) nc_merged <- merge(nc, my_df, by = "NAME", all.x = TRUE) ggplot(data = nc_merged) + geom_sf_pattern(aes(fill = favorite_color, pattern_fill = favorite_color), pattern = "stripe", color = "black", size = 0.2) + scale_fill_manual(values = pattern_colors) + scale_pattern_fill_manual(values = pattern_colors) + theme_minimal() + labs(title = "Favorite Color by County (with Patterns for Ties)", fill = "Favorite Color")

改进后尝试
调整后效果仍不理想:
library(ggpattern) set.seed(123) colors <- c("red", "blue", "green", "yellow", "purple", "orange") favorite_color <- replicate(nrow(nc), { sample_size <- sample(1:3, 1) sample(colors, sample_size, replace = FALSE) }) my_df <- data.frame( NAME = nc$NAME, stringsAsFactors = FALSE ) for(i in 1:3) { my_df[[paste0("color", i)]] <- sapply(favorite_color, function(x) if(length(x) >= i) x[i] else NA) } my_df$color_count <- sapply(favorite_color, length) nc_merged <- merge(nc, my_df, by = "NAME", all.x = TRUE) nc_merged$pattern <- ifelse(nc_merged$color_count == 2, "stripe", "crosshatch") ggplot() + # Layer for counties with a single color geom_sf(data = subset(nc_merged, color_count == 1), aes(fill = color1), color = "white") + # Layer for counties with two colors geom_sf_pattern(data = subset(nc_merged, color_count == 2), aes(fill = color1, pattern_fill = color2), pattern = "stripe", pattern_angle = 45, color = "white", pattern_density = 0.5, pattern_spacing = 0.01, pattern_key_scale_factor = 0.6) + # Layer for counties with three colors geom_sf_pattern(data = subset(nc_merged, color_count == 3), aes(fill = color1, pattern_fill = color2), pattern = "crosshatch", pattern_angle = 45, color = "white", pattern_density = 0.5, pattern_spacing = 0.01, pattern_key_scale_factor = 0.6) + geom_sf_pattern(data = subset(nc_merged, color_count == 3), aes(pattern_fill = color3), pattern = "crosshatch", pattern_angle = 135, color = NA, pattern_density = 0.5, pattern_spacing = 0.01) + scale_fill_identity() + theme_minimal() + labs(title = "Favorite Color by County (with Patterns for Ties)")

可行解决方案:颜色混合(RGB平均值法)
通过将颜色转换为RGB数值,对平局的颜色取平均值生成混合色,具体代码如下:
library(sf) library(dplyr) library(ggplot2) # 加载数据 nc <- st_read(system.file("gpkg/nc.gpkg", package = "sf"), quiet = TRUE) %>% st_transform(st_crs(4326)) %>% st_cast("POLYGON") set.seed(123) colors <- c("red", "blue", "green", "yellow", "purple", "orange") favorite_color <- replicate(nrow(nc), { sample_size <- sample(1:3, 1) sample(colors, sample_size, replace = FALSE) }) # 定义函数:将颜色列表转换为混合RGB色 mix_colors <- function(color_list) { if(length(color_list) == 1) return(color_list) # 转换为RGB矩阵并归一化到0-1范围 rgb_matrix <- sapply(color_list, function(col) col2rgb(col) / 255) # 计算各通道平均值 avg_rgb <- apply(rgb_matrix, 1, mean) # 转换回十六进制颜色 rgb(avg_rgb[1], avg_rgb[2], avg_rgb[3]) } # 生成混合色列 my_df <- data.frame( NAME = nc$NAME, mixed_color = sapply(favorite_color, mix_colors), original_colors = sapply(favorite_color, function(x) paste(x, collapse = ", ")) ) nc_merged <- merge(nc, my_df, by = "NAME", all.x = TRUE) # 绘制地图 ggplot(data = nc_merged) + geom_sf(aes(fill = mixed_color), color = "white") + scale_fill_identity(name = "Color Combination", labels = nc_merged$original_colors, guide = "legend") + theme_minimal() + labs(title = "Favorite Color by County (Mixed Colors for Ties)")
该方案通过RGB通道平均值生成混合色,既保留了平局县的颜色信息,又保证了地图的可读性,图例可展示每个县的原始颜色组合。
内容的提问来源于stack exchange,提问作者stats_noob
相关产品推荐
相关产品推荐

