วิธีคำนวณรูปหลายเหลี่ยม centroids ใน R (สำหรับรูปร่างที่ไม่ต่อเนื่องกัน)


41

ฉันใช้เวลาเล็กน้อยในการหาคำตอบสำหรับคำถามนี้ ไม่ชัดเจนในทันทีจากการค้นหาของ Googleดังนั้นคิดว่าอาจมีประโยชน์ในการโพสต์คำตอบที่นี่ นอกจากนี้ยังมีคำถามเพิ่มเติมเกี่ยวกับรูปหลายเหลี่ยมไม่ต่อเนื่องกัน

คำตอบง่าย ๆ ทันที: ใช้คำสั่ง:

centroids <- getSpPPolygonsLabptSlots(polys)

(ซึ่งพบได้ในคำอธิบายคลาสของคลาสข้อมูล SpatialPolygonsDataFrame R สำหรับแพ็คเกจอวกาศที่ครอบคลุมใน R, sp )

ดูเหมือนว่าจะทำสิ่งเดียวกัน

cents <- SpatialPointsDataFrame(coords=cents, data=sids@data, proj4string=CRS("+proj=longlat +ellps=clrk66"))

ในรหัสต่อไปนี้ซึ่งควรทำซ้ำในการติดตั้ง R ใด ๆ (ลองใช้!)

#Rcentroids
install.packages("GISTools")
library(GISTools)
sids <- readShapePoly(system.file("shapes/sids.shp", package="maptools")[1], 
                      proj4string=CRS("+proj=longlat +ellps=clrk66"))
class(sids)
plot(sids)
writeSpatialShape(sids, "sids")
cents <- coordinates(sids)
cents <- SpatialPointsDataFrame(coords=cents, data=sids@data, 
                  proj4string=CRS("+proj=longlat +ellps=clrk66"))
points(cents, col = "Blue")
writeSpatialShape(cents, "cents")

centroids <- getSpPPolygonsLabptSlots(sids)
points(centroids, pch = 3, col = "Red")

ตำแหน่งที่เซ็นต์ (สีน้ำเงิน) และเซนทรอยด์ (สีแดง) เป็นเซนทรอยด์ที่เหมือนกัน (นี่ควรพล็อตควรปรากฏขึ้นหลังจากที่คุณเรียกใช้รหัส):

centroids คำนวณโดย R

จนถึงตอนนี้ดีมาก แต่เมื่อคุณคำนวณรูปหลายเหลี่ยม centroids ใน QGIS (เมนู: เวกเตอร์ | เรขาคณิต | รูปหลายเหลี่ยม Centroids) ผลลัพธ์ที่แตกต่างกันเล็กน้อยสำหรับรูปหลายเหลี่ยมที่ไม่ต่อเนื่องกัน:

QGIS สร้างรูปหลายเหลี่ยม

ดังนั้นคำถามนี้คือ 3 สิ่ง:

  1. คำตอบที่ง่ายและรวดเร็ว
  2. คำเตือนสำหรับผู้ที่ใช้ R เพื่อคำนวณ centroids สำหรับรูปหลายเหลี่ยมที่ไม่ต่อเนื่องกัน
  3. คำถามเกี่ยวกับวิธีการที่ควรทำใน R เพื่ออธิบายรูปหลายเหลี่ยมแบบหลายส่วน (ไม่ต่อเนื่อง)

ฉันจำเป็นต้องรู้ฉันจะอ้างอิงฟังก์ชัน centroid ที่อธิบายไว้ข้างต้นได้อย่างไร ขอบคุณ
Santiago Fernandez

ยินดีต้อนรับสู่ GIS StackExchange! ในฐานะที่เป็นผู้ใช้ใหม่โปรดใช้ทัวร์ สิ่งนี้ดูเหมือนจะเป็นคำถามใหม่แทนที่จะตอบคำถามนี้ กรุณาโพสต์เป็นคำถามใหม่
smiller

คำตอบ:


56

ประการแรกฉันไม่สามารถหาเอกสารใด ๆ ที่บอกว่าcoordinatesหรือgetSpPPolygonsLabptSlotsคืนเซนทรอยด์ที่ศูนย์กลางของมวล ในความเป็นจริงฟังก์ชั่นหลังตอนนี้ปรากฏขึ้นเป็น 'เลิก' และควรออกคำเตือน

สิ่งที่คุณต้องการในการคำนวณเซนทรอยด์เป็นศูนย์กลางของคุณลักษณะคือgCentroidฟังก์ชั่นจากrgeosแพ็คเกจ การทำhelp.search("centroid")จะได้พบสิ่งนี้

trueCentroids = gCentroid(sids,byid=TRUE)
plot(sids)
points(coordinates(sids),pch=1)
points(trueCentroids,pch=2)

ควรแสดงความแตกต่างและเหมือนกับ Qgis centroids


3
จากข้อมูลของ Roger Bivand ผู้พัฒนาแพ็คเกจอวกาศจำนวนหนึ่งของ R กล่าวว่า: "ใช่เอกสารประกอบการเรียนที่" Polygons-class "ไม่ได้ระบุว่าเป็นเช่นนี้เพราะประเด็นอื่น ๆ อาจถูกแทรกเป็นจุดฉลาก ตัวสร้างเริ่มต้นใช้เซนทรอยด์ของวงแหวนที่ไม่ใช่รูที่ใหญ่ที่สุดในวัตถุรูปหลายเหลี่ยม " - อธิบายไม่ติดกัน stat.ethz.ch/pipermail/r-help/2009-February/187436.html ยืนยันแล้ว: gCentroid (sids, byid = TRUE) สามารถแก้ปัญหาได้อย่างแน่นอน
RobinLovelace

ใช้งานไม่ได้สำหรับฉัน ... แม้ว่าการใช้ gCentroid (รูปหลายเหลี่ยม, byid = TRUE) Centroid ของฉันอยู่ระหว่างสองรูปหลายเหลี่ยม .. ดังนั้นฉันคิดว่าสิ่งเหล่านั้นจะถือว่าเป็นรูปหลายเหลี่ยมหลายส่วน? ฉันจะแยกพวกมันออกจากกันได้อย่างไร คะแนน (พิกัด (SC.tracks), pch = 16, col = "blue", cex = 0.4) อย่างไรก็ตามการผลิตไม่ได้ผลิต centroid จากรูปหลายเหลี่ยม ... ขอบคุณ!
maycca

ลิงก์ไปที่ stat.ethz.ch ไม่ทำงานอีกต่อไป เพียงเพื่อความสมบูรณ์ฉันเกือบจะแน่ใจว่าคำตอบในขณะนี้สามารถพบได้ที่นี่: r.789695.n4.nabble.com/…
Exocom

8

นี่คือวิธีการใช้เอสเอฟ ตามที่ฉันแสดงผลลัพธ์จาก sf :: st_centroid และ rgeos :: gCentroid เหมือนกัน

library(sf)
library(ggplot2)

# I transform to utm because st_centroid is not recommended for use on long/lat 
nc <- st_read(system.file('shape/nc.shp', package = "sf")) %>% 
  st_transform(32617)

# using rgeos
sp_cent <- gCentroid(as(nc, "Spatial"), byid = TRUE)

# using sf
sf_cent <- st_centroid(nc)

# plot both together to confirm that they are equivalent
ggplot() + 
  geom_sf(data = nc, fill = 'white') +
  geom_sf(data = sp_cent %>% st_as_sf, color = 'blue') + 
  geom_sf(data = sf_cent, color = 'red') 

ป้อนคำอธิบายรูปภาพที่นี่


3

สิ่งที่ฉันทำเพื่อเอาชนะปัญหานี้คือการสร้างฟังก์ชั่นที่ลบบัฟเฟอร์รูปหลายเหลี่ยมจนกว่ามันจะมีขนาดเล็กพอที่จะคาดหวังรูปหลายเหลี่ยมนูน ฟังก์ชั่นการใช้งานคือcentroid(polygon)

#' find the center of mass / furthest away from any boundary
#' 
#' Takes as input a spatial polygon
#' @param pol One or more polygons as input
#' @param ultimate optional Boolean, TRUE = find polygon furthest away from centroid. False = ordinary centroid

require(rgeos)
require(sp)

centroid <- function(pol,ultimate=TRUE,iterations=5,initial_width_step=10){
  if (ultimate){
    new_pol <- pol
    # For every polygon do this:
    for (i in 1:length(pol)){
      width <- -initial_width_step
      area <- gArea(pol[i,])
      centr <- pol[i,]
      wasNull <- FALSE
      for (j in 1:iterations){
        if (!wasNull){ # stop when buffer polygon was alread too small
          centr_new <- gBuffer(centr,width=width)
          # if the buffer has a negative size:
          substract_width <- width/20
          while (is.null(centr_new)){ #gradually decrease the buffer size until it has positive area
            width <- width-substract_width
            centr_new <- gBuffer(centr,width=width)
            wasNull <- TRUE
          }
          # if (!(is.null(centr_new))){
          #   plot(centr_new,add=T)
          # }
          new_area <- gArea(centr_new)
          #linear regression:
          slope <- (new_area-area)/width
          #aiming at quarter of the area for the new polygon
          width <- (area/4-area)/slope
          #preparing for next step:
          area <- new_area
          centr<- centr_new
        }
      }
      #take the biggest polygon in case of multiple polygons:
      d <- disaggregate(centr)
      if (length(d)>1){
        biggest_area <- gArea(d[1,])
        which_pol <- 1                             
        for (k in 2:length(d)){
          if (gArea(d[k,]) > biggest_area){
            biggest_area <- gArea(d[k,])
            which_pol <- k
          }
        }
        centr <- d[which_pol,]
      }
      #add to class polygons:
      new_pol@polygons[[i]] <- remove.holes(new_pol@polygons[[i]])
      new_pol@polygons[[i]]@Polygons[[1]]@coords <- centr@polygons[[1]]@Polygons[[1]]@coords
    }
    centroids <- gCentroid(new_pol,byid=TRUE)
  }else{
    centroids <- gCentroid(pol,byid=TRUE)  
  }  
  return(centroids)
}

#Given an object of class Polygons, returns
#a similar object with no holes


remove.holes <- function(Poly){
  # remove holes
  is.hole <- lapply(Poly@Polygons,function(P)P@hole)
  is.hole <- unlist(is.hole)
  polys <- Poly@Polygons[!is.hole]
  Poly <- Polygons(polys,ID=Poly@ID)
  # remove 'islands'
  max_area <- largest_area(Poly)
  is.sub <- lapply(Poly@Polygons,function(P)P@area<max_area)  
  is.sub <- unlist(is.sub)
  polys <- Poly@Polygons[!is.sub]
  Poly <- Polygons(polys,ID=Poly@ID)
  Poly
}
largest_area <- function(Poly){
  total_polygons <- length(Poly@Polygons)
  max_area <- 0
  for (i in 1:total_polygons){
    max_area <- max(max_area,Poly@Polygons[[i]]@area)
  }
  max_area
}

ช้า แต่ให้ผลลัพธ์ที่ดีมาก มันมีศูนย์กลางอยู่ที่ดีและให้ผลลัพธ์ที่ดีสำหรับการจัดวางฉลาก
Bastien
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.