如何在R语言中使用tmap为地图多边形添加对应数量的多点?
R语言tmap绘制带内部点的区域地图解决方案
问题描述
作为R语言地图绘制新手,使用tmap处理里约健康区域shp文件,现有数据框如下:
data <- data.frame(COD_AP_SMS = c("AP 1.0", "AP 2.1", "AP 2.2", "AP 3.1", "AP 3.2", "AP 3.3", "AP 4.0", "AP 5.1", "AP 5.2", "AP 5.3"), n = c(11, 21, 6, 32, 15, 32, 27, 26, 19, 18))
需求:
- 每个
COD_AP_SMS对应的多边形用不同颜色区分 - 每个多边形内生成对应
n数量的点(如AP 1.0区域内生成11个点)
现有代码使用tm_dots("n")仅控制点的大小,无法生成对应数量的点,当前效果为区域颜色区分但点不符合需求,期望效果是每个区域内均匀分布对应数量的点。
现有代码:
ap <- read_sf("shp/Limites AP.shp") plot(ap) ap <- full_join(ap, tb, by = "COD_AP_SMS") # 调整边界框 bbox_new <- st_bbox(ap) # 当前边界框 xrange <- bbox_new$xmax - bbox_new$xmin # x轴范围 yrange <- bbox_new$ymax - bbox_new$ymin # y轴范围 bbox_new[3] <- bbox_new[3] + (0.25 * xrange) # 扩展右侧边界 bbox_new[4] <- bbox_new[4] + (0.2 * yrange) # 扩展顶部边界 bbox_new <- bbox_new %>% # 转换为sf多边形 st_as_sfc() tm_shape(ap, bbox = bbox_new)+ tm_fill("COD_AP_SMS", auto.palette.mapping=FALSE, title="AP")+ tm_dots("n", size = 2) + tm_compass(position = c("left", "top"))+ tm_scale_bar(position = c("left", "top"))+ tm_borders(alpha=1, lwd = 1, col = "black")+ tm_legend(legend.format = list(text.separator= "a")) + tm_layout(legend.position = c("right", "top"), frame = FALSE)
解决方案
核心是先为每个多边形生成对应数量的随机点,再用tmap分层绘制多边形和点:
1. 生成区域内的点集
使用sf包的st_sample函数,对每个区域生成指定数量的随机点:
library(sf) library(tmap) library(dplyr) # 读取并合并数据 ap <- read_sf("shp/Limites AP.shp") data <- data.frame(COD_AP_SMS = c("AP 1.0", "AP 2.1", "AP 2.2", "AP 3.1", "AP 3.2", "AP 3.3", "AP 4.0", "AP 5.1", "AP 5.2", "AP 5.3"), n = c(11, 21, 6, 32, 15, 32, 27, 26, 19, 18)) ap <- ap %>% inner_join(data, by = "COD_AP_SMS") # 生成每个区域内的随机点 points_list <- lapply(1:nrow(ap), function(i) { st_sample(ap[i, ], size = ap$n[i]) %>% st_sf() %>% mutate(COD_AP_SMS = ap$COD_AP_SMS[i]) }) all_points <- do.call(rbind, points_list)
2. 绘制符合需求的地图
分层绘制多边形、边界和点,同时优化地图元素:
# 保留原有边界框设置 bbox_new <- st_bbox(ap) xrange <- bbox_new$xmax - bbox_new$xmin yrange <- bbox_new$ymax - bbox_new$ymin bbox_new[3] <- bbox_new[3] + (0.25 * xrange) bbox_new[4] <- bbox_new[4] + (0.2 * yrange) bbox_new <- st_as_sfc(bbox_new) # 绘制地图 tm_shape(ap, bbox = bbox_new) + tm_fill("COD_AP_SMS", auto.palette.mapping = FALSE, title = "健康区域(AP)", palette = "Set3") + # 用Set3调色板增强区分度 tm_borders(alpha = 1, lwd = 1, col = "black") + tm_shape(all_points) + tm_dots(size = 0.5, col = "white", alpha = 0.8) + # 白色点与彩色区域形成对比 tm_compass(position = c("left", "top"), type = "4star", size = 2, color = "black") + tm_scale_bar(position = c("left", "top"), width = 0.2, text.size = 0.8, color.dark = "black", color.light = "white") + tm_text("COD_AP_SMS", size = 0.7, col = "black", just = "center") + # 添加区域标签 tm_layout( legend.position = c("right", "top"), frame = FALSE, legend.title.size = 1, legend.text.size = 0.8, main.title = "里约健康区域及对应点数分布", main.title.size = 1.2, main.title.position = "center" )
优化建议
- 标签优化:如果区域标签重叠,可调整
size参数或使用tm_text的auto.placement = TRUE自动避让。 - 颜色优化:若默认调色板区分度不足,可使用
palette = RColorBrewer::brewer.pal(10, "Paired")自定义调色板。 - 比例尺与指南针:将指南针和比例尺位置错开(如指南针在左上,比例尺在左下),避免重叠;调整
size和text.size适配地图整体尺寸。 - 点样式:可根据需求修改点的颜色(如与区域颜色一致)或形状(
shape = 16为实心圆)。
内容的提问来源于stack exchange,提问作者Lana Meijinhos
相关产品推荐
相关产品推荐

