Clip đối tượng không gian vào hộp giới hạn trong R


13

Đưa ra một đối tượng Không gian trong R, làm cách nào để cắt tất cả các phần tử của nó nằm trong một khung giới hạn?

Có hai điều tôi muốn làm (lý tưởng nhất là tôi biết cách làm cả hai, nhưng đó là một giải pháp chấp nhận được cho vấn đề hiện tại của tôi - hạn chế một hình đa giác ở Hoa Kỳ lục địa).

  1. Thả từng phần tử không đầy đủ trong hộp giới hạn. Điều này có vẻ như bbox()<-là cách hợp lý, nhưng không có phương pháp như vậy tồn tại.

  2. Thực hiện một thao tác clip thực sự, sao cho các phần tử không cực nhỏ (ví dụ: đa giác, đường thẳng) bị cắt ở ranh giới . sp::bboxthiếu một phương thức gán, vì vậy cách duy nhất tôi nghĩ ra là sử dụng overhoặc gContains/ gCrosseskết hợp với một đối tượng SpatialPolygons chứa một hộp có tọa độ của hộp giới hạn mới. Sau đó, khi cắt một đối tượng đa giác, bạn phải tìm ra cái nào được chứa so với chữ thập và thay đổi tọa độ của các đa giác đó để chúng không vượt quá hộp. Hoặc một cái gì đó như gIntersection. Nhưng chắc chắn có một cách đơn giản hơn?

Mặc dù tôi biết rằng có nhiều vấn đề với các hộp giới hạn và lớp phủ không gian cho đa giác xác định vùng quan tâm thường được ưa thích hơn, trong nhiều trường hợp, các hộp giới hạn hoạt động tốt và đơn giản hơn.


Nói rõ hơn, nếu đối tượng Không gian của bạn được mở rộng (Đa giác hoặc Đường) bạn muốn cắt nó sao cho nó chỉ trả về phần của nó nằm trong phạm vi nhất định của bạn? Tôi không nghĩ có một cách đơn giản hơn.
Spainedman

@Spacesman Làm rõ rằng tôi quan tâm đến cả hai nhưng phiên bản đơn giản hơn sẽ đủ cho câu hỏi hiện tại.
Ari B. Friedman

Bạn đã thực hiện giải pháp cho (2) bằng cách sử dụng rgeos chưa? Có vẻ như bạn đã cố gắng ít nhất. Bạn có thể cho chúng tôi giải pháp đó và một ví dụ để ít nhất chúng tôi có một cái gì đó để so sánh với 'sự đơn giản' không? Bởi vì, thành thật mà nói, điều đó có vẻ khá đơn giản.
Spainedman

@Spacesman Mọi thứ đều đơn giản; chỉ mất thời gian .... :-) Tôi đã thử nó gIntersectionError in RGEOSBinTopoFunc(spgeom1, spgeom2, byid, id, "rgeos_intersection") : TopologyException: no outgoing dirEdge found at 3 2.5 không có thời gian để gỡ lỗi ngày hôm nay; đã viết lên một phiên bản cẩu thả và sẽ sửa chữa trong tương lai.
Ari B. Friedman

Câu trả lời:


11

Tôi đã tạo ra một chức năng nhỏ cho mục đích này và nó đã được những người khác sử dụng với những đánh giá tốt!

gClip <- function(shp, bb){
  if(class(bb) == "matrix") b_poly <- as(extent(as.vector(t(bb))), "SpatialPolygons")
  else b_poly <- as(extent(bb), "SpatialPolygons")
  gIntersection(shp, b_poly, byid = TRUE)
}

Điều này sẽ giải quyết vấn đề của bạn. Giải thích thêm tại đây: http://robinlovelace.net/r/2014/07/29/clipping-with-r.html

Đa giác giả b_polyđược tạo ra không có chuỗi proj4, dẫn đến " Cảnh báo: spgeom1 và spgeom2 có các chuỗi proj4 khác nhau ", nhưng điều này là vô hại.


Tôi đã sp, maptools, rgdal, và rgeosnạp. Tôi nhận được Error in .class1(object) : could not find function "extent"vấn đề phiên bản R / gói có lẽ?
gregmacfarlane

Lưu ý dòng library(raster)trong hướng dẫn của tôi: robinlovelace.net/r/2014/07/29/clipping-with-r.html cho chúng tôi biết làm thế nào bạn nhận được trên! Chúc mừng.
RobinLigsace

Điều này tạo ra một thông điệp cảnh báo cho tôi: spgeom1 và spgeom2 có các chuỗi proj4 khác nhau. Thêm proj4opes (b_poly) <- proj4opes (shp) có giải quyết được không?
Matifou

7

Đây là phiên bản ranh giới cẩu thả (đủ để đáp ứng nhu cầu của tôi kịp thời hạn chót vào ngày mai :-)):

#' Convert a bounding box to a SpatialPolygons object
#' Bounding box is first created (in lat/lon) then projected if specified
#' @param bbox Bounding box: a 2x2 numerical matrix of lat/lon coordinates
#' @param proj4stringFrom Projection string for the current bbox coordinates (defaults to lat/lon, WGS84)
#' @param proj4stringTo Projection string, or NULL to not project
#' @seealso \code{\link{clipToExtent}} which uses the output of this to clip to a bounding box
#' @return A SpatialPolygons object of the bounding box
#' @example 
#' bb <- matrix(c(3,2,5,4),nrow=2)
#' rownames(bb) <- c("lon","lat")
#' colnames(bb) <- c('min','max')
as.SpatialPolygons.bbox <- function( bbox, proj4stringFrom=CRS("+proj=longlat +datum=WGS84"), proj4stringTo=NULL ) {
  # Create unprojected bbox as spatial object
  bboxMat <- rbind( c(bbox['lon','min'],bbox['lat','min']), c(bbox['lon','min'],bbox['lat','max']), c(bbox['lon','max'],bbox['lat','max']), c(bbox['lon','max'],bbox['lat','min']), c(bbox['lon','min'],bbox['lat','min']) ) # clockwise, 5 points to close it
  bboxSP <- SpatialPolygons( list(Polygons(list(Polygon(bboxMat)),"bbox")), proj4string=proj4stringFrom  )
  if(!is.null(proj4stringTo)) {
    bboxSP <- spTransform( bboxSP, proj4stringTo )
  }
  bboxSP
}


#' Restrict to extent of a polygon
#' Currently does the sloppy thing and returns any object that has any area inside the extent polygon
#' @param sp Spatial object
#' @param extent a SpatialPolygons object - any part of sp not within a polygon will be discarded
#' @seealso \code{\link{as.SpatialPolygons.bbox}} to create a SP from a bbox
#' @return A spatial object of the same type
#' @example
#' set.seed(1)
#' P4S.latlon <- CRS("+proj=longlat +datum=WGS84")
#' ply <- SpatialPolygons(list(Polygons(list(Polygon(cbind(c(2,4,4,1,2),c(2,3,5,4,2)))), "s1"),Polygons(list(Polygon(cbind(c(5,4,2,5),c(2,3,2,2)))), "s2")), proj4string=P4S.latlon)
#' pnt <- SpatialPoints( matrix(rnorm(100),ncol=2)+2, proj4string=P4S.latlon )
#' # Make bounding box as Spatial Polygon
#' bb <- matrix(c(3,2,5,4),nrow=2)
#' rownames(bb) <- c("lon","lat")
#' colnames(bb) <- c('min','max')
#' bbSP <- as.SpatialPolygons.bbox(bb, proj4stringTo=P4S.latlon )
#' # Clip to extent
#' plyClip <- clipToExtent( ply, bbSP )
#' pntClip <- clipToExtent( pnt, bbSP )
#' # Plot
#' plot( ply )
#' plot( pnt, add=TRUE )
#' plot( bbSP, add=TRUE, border="blue" )
#' plot( plyClip, add=TRUE, border="red")
#' plot( pntClip, add=TRUE, col="red", pch="o")
clipToExtent <- function( sp, extent ) {
    require(rgeos)
    keep <- gContains( extent, sp,byid=TRUE ) | gOverlaps( extent, sp,byid=TRUE )
    stopifnot( ncol(keep)==1 )
    sp[drop(keep),]
}

cắt hộp

Nếu bạn cần hộp giới hạn để chiếu, phiên bản ở đây sẽ thêm một interpolateđối số, để hộp được chiếu kết quả bị cong.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.