基于四色定理实现地图非相邻区域自动四色填充的技术咨询
基于四色定理实现地图非相邻区域自动四色填充的技术咨询
嘿,这个问题问得太贴合实际需求了——四色定理的落地应用确实是地图可视化里的经典痛点!你遇到的报错很正常,因为直接按State_Name作为分类变量的话,ggplot会默认给每个不同的邦/地区分配独立颜色,但你只有4种,自然不够用。要实现四色填充,核心得基于空间相邻关系来分配颜色,而不是按类别来,咱们一步步来搞定:
第一步:先获取区域的相邻关系
首先得让程序知道哪些区域是互相接壤的,这是四色填充的基础。用sf包的st_touches()函数就能轻松拿到这个关系:
library(sf) library(ggplot2) library(RColorBrewer) # 计算每个区域的相邻矩阵(sparse=FALSE返回完整矩阵,方便后续处理) adj_matrix <- st_touches(india_state_dist, sparse = FALSE)
这个矩阵里,adj_matrix[i,j]为TRUE就表示第i个区域和第j个区域是相邻的。
第二步:用贪心算法分配颜色
四色定理告诉我们,任何平面地图都能用4种颜色填满且相邻区域颜色不同,而贪心算法就能完美实现这个逻辑——逐个给区域分配第一个不被邻居使用的颜色就行。咱们写个简单的函数来做这件事:
assign_colors <- function(adj_matrix, num_colors = 4) { n_regions <- nrow(adj_matrix) color_assignment <- rep(NA, n_regions) # 先给第一个区域分配第一种颜色 color_assignment[1] <- 1 # 遍历剩下的区域,逐个分配可用颜色 for (i in 2:n_regions) { # 拿到当前区域所有已分配颜色的邻居的颜色 neighbor_colors <- color_assignment[adj_matrix[i, ]] neighbor_colors <- neighbor_colors[!is.na(neighbor_colors)] # 挑第一个没被邻居用的颜色 available_colors <- setdiff(1:num_colors, neighbor_colors) color_assignment[i] <- available_colors[1] } return(color_assignment) } # 给你的地图区域分配颜色ID color_ids <- assign_colors(adj_matrix) # 加载你想用的4种颜色 colors <- brewer.pal(4, "Set1")
第三步:用分配好的颜色画图
现在直接用分配的color_ids作为填充变量就行,再也不会报颜色不够的错了:
ggplot() + geom_sf(data = india_state_dist, aes(fill = factor(color_ids))) + scale_fill_manual(values = colors, name = "Color") + theme_minimal()
小提示
如果你的地图里有一些“飞地”(比如和主体不接壤的小块区域),或者你想把共享一个点的区域也算作相邻,可以把st_touches()换成st_intersects(),不过一般地图可视化里用st_touches()(共享边界才算相邻)就足够啦。
备注:内容来源于stack exchange,提问作者Damitr
相关产品推荐
相关产品推荐

