R语言空间分析:根据点到质心距离设置点位绘制大小
需求说明
我是R语言与空间分析初学者,需要实现空间可视化效果:绘制德累斯顿(属性编码SN_L = 14、RS = 14612)县域质心30km缓冲区范围内的所有监测站点点位,点位大小和站点到县域质心的距离负相关——距质心越近点位尺寸越大,用距离倒数映射点位大小。
已完成的基础代码
目前已经实现基础版地图:点位尺寸统一,按是否落在缓冲区分色,代码如下:
### 计算县域质心 counties_trans$centroid <- st_centroid(counties_trans$geometry) #------------------------------------------------------------------------------# ### 生成质心30km缓冲区 counties_trans$buff <- st_buffer(counties_trans$centroid, 30000) #------------------------------------------------------------------------------# ### 提取研究范围:德累斯顿所在的萨克森州区域 # 定义州边界范围框 box = c(xmin = 703301, ymin = 5562792, xmax = 921778, ymax = 5733351) saxony <- st_crop(counties_trans, box) # 提取德累斯顿质心30km缓冲区范围内的站点 a <- st_intersection(saxony$buff[which(saxony$RS == "14612")], poll_st_trans$geometry) # 提取30km缓冲区外的所有站点 c <- st_difference(poll_st_trans$geometry, saxony$buff[which(saxony$RS == "14612")]) # 提取萨克森州范围内、30km缓冲区外的站点 d <- st_intersection(c, saxony$geometry[which(saxony$SN_L == "14")]) #------------------------------------------------------------------------------# ### 绘制基础地图 # 绘制萨克森州县域边界 plot(saxony$geometry[which(saxony$SN_L == "14")], reset = FALSE) # 绘制德累斯顿质心 plot(saxony$centroid[which(saxony$RS == "14612")], add = TRUE, pch = 20) # 绘制30km缓冲区边界 plot(saxony$buff[which(saxony$RS == "14612")], add = TRUE) # 绘制州内缓冲区外的站点 plot(d, add = TRUE, pch = 24, col = 'grey') # 绘制缓冲区内的站点(此处点位大小设置失效) plot(a, add = TRUE, pch = 17, col = 'royalblue3', cex = dist) # 绘制萨克森州外的其他区域 plot(saxony$geometry[which(saxony$SN_L != "14")], add = TRUE, col = 'grey')
已经通过如下代码计算缓冲区内各站点到德累斯顿质心的距离:
dist <- st_distance(a, saxony$centroid[which(saxony$RS == "14612")])
遇到的问题
尝试在base R的plot函数中传入cex = dist、在ggplot2的geom_sf图层传入size = dist设置点位大小,两种方式都只显示整块蓝色矩形,无法得到按距离映射大小的点位效果,异常效果如下:
解决方法
错误原因
出图异常核心是两个问题:
st_distance()返回值是带units单位属性的二维矩阵,不是普通一维数值向量,直接传给绘图参数无法被正确解析- 需求是距离越近点位越大,直接用原始距离映射的话,距离越远数值越大、点位尺寸越大,和需求逻辑完全相反
具体修正步骤
第一步:处理距离值
计算完距离后,先把距离转为普通数值,再做倒数缩放,把值映射到适合点位大小的区间:
# 去除单位属性和矩阵结构,转为普通数值向量 dist <- as.numeric(dist) # 计算距离倒数,缩放到合适的cex取值区间,避免点过大或过小 # 方法1:手动缩放 point_cex <- (1/dist) * max(dist) * 0.8 # 方法2:用scales包归一化,固定cex范围在0.6~2.5,效果更可控 # point_cex <- scales::rescale(1/dist, to = c(0.6, 2.5))
第二步:修正base R绘图代码
base R的plot.sf()方法对sf对象绘图时,不支持直接传入和要素等长的cex向量,需要提取站点坐标后用points()函数单独绘制点位:
# 提取缓冲区内站点的平面坐标 a_coords <- st_coordinates(a) # 替换原代码中plot(a, ...)的部分 points( x = a_coords[,1], y = a_coords[,2], pch = 17, col = 'royalblue3', cex = point_cex )
可选:ggplot2版本正确写法
如果用ggplot2绘制,需要把点位大小作为属性列加入sf对象,在aes()内部做属性映射,不要把外部向量直接传给size参数:
library(ggplot2) # 将计算好的点位大小写入站点sf对象 a$point_size <- point_cex ggplot() + # 绘制萨克森州县域边界 geom_sf(data = saxony[saxony$SN_L == "14",], fill = NA, linewidth = 0.3) + # 绘制萨克森州外的邻接区域 geom_sf(data = saxony[saxony$SN_L != "14",], fill = "grey90", color = NA) + # 绘制30km缓冲区边界 geom_sf(data = saxony$buff[saxony$RS == "14612"], fill = NA, linetype = "dashed", linewidth = 0.5) + # 绘制缓冲区外的州内站点 geom_sf(data = d, pch = 24, col = "grey50", fill = "grey80", size = 1.5) + # 绘制缓冲区内的站点,映射size属性 geom_sf(data = a, pch = 17, col = "royalblue3", aes(size = point_size)) + # 绘制德累斯顿质心 geom_sf(data = saxony$centroid[saxony$RS == "14612"], pch = 20, size = 2) + # 隐藏size图例 scale_size_continuous(guide = "none") + theme_minimal()
内容的提问来源于stack exchange,提问作者Stefano Ceolotto
相关产品推荐
相关产品推荐

