r sf package centroid within polygon
我需要为多边形添加标签,我通常使用质心,但是质心不会落在多边形内。我发现了这个问题 Calculate Centroid WITHIN / INSIDE a SpatialPolygon 但我使用的是 sf 包。
下面是玩具数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | rm(list = ls(all = TRUE)) #start with empty workspace library(sf) library(tidyverse) library(ggrepel) pol <- st_polygon(list(rbind(c(144, 655),c(115, 666) ,c(97, 660),c(86, 640) ,c(83, 610),c(97, 583) ,c(154, 578),c(140, 560) ,c(72, 566),c(59, 600) ,c(65, 634),c(86, 678) ,c(145, 678),c(144, 655)))) %>% st_sfc() a = data.frame(NAME ="A") st_geometry(a) = pol a <- a %>% mutate(lon = map_dbl(geometry, ~st_centroid(.x)[[1]]), lat = map_dbl(geometry, ~st_centroid(.x)[[2]])) ggplot() + geom_sf(data = a, fill ="orange") + geom_label_repel(data = a, aes(x = lon, y = lat, label = NAME)) |
导致以下
简单的答案是将
1 2 3 4 5 6 7 | a2 <- a %>% mutate(lon = map_dbl(geometry, ~st_point_on_surface(.x)[[1]]), lat = map_dbl(geometry, ~st_point_on_surface(.x)[[2]])) ggplot() + ggplot2::geom_sf(data = a2, fill ="orange") + geom_label_repel(data = a2, aes(x = lon, y = lat, label = NAME)) |
或者
如果多边形的质心在多边形内,则使用它,否则,在多边形内找到一个点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | st_centroid_within_poly <- function (poly) { # check if centroid is in polygon centroid <- poly %>% st_centroid() in_poly <- st_within(centroid, poly, sparse = F)[[1]] # if it is, return that centroid if (in_poly) return(centroid) # if not, calculate a point on the surface and return that centroid_in_poly <- st_point_on_surface(poly) return(centroid_in_poly) } a3 <- a %>% mutate(lon = map_dbl(geometry, ~st_centroid_within_poly(.x)[[1]]), lat = map_dbl(geometry, ~st_centroid_within_poly(.x)[[2]])) ggplot() + ggplot2::geom_sf(data = a3, fill ="orange") + geom_label_repel(data = a3, aes(x = lon, y = lat, label = NAME)) |
扩展 Mitch 的答案,因为上面提供的
要在多个多边形上使用,请使用:
1 2 3 4 5 6 7 8 9 10 11 | st_centroid_within_poly <- function (poly) { # check if centroid is in polygon ctrd <- st_centroid(poly, of_largest_polygon = TRUE) in_poly <- diag(st_within(ctrd, poly, sparse = F)) # replace geometries that are not within polygon with st_point_on_surface() st_geometry(ctrd[!in_poly,]) <- st_geometry(st_point_on_surface(poly[!in_poly,])) ctrd } |