Recorte el objeto espacial al cuadro delimitador en R


13

Dado un objeto espacial en R, ¿cómo recorto todos sus elementos para que queden dentro de un cuadro delimitador?

Hay dos cosas que me gustaría hacer (idealmente, sabría cómo hacer ambas cosas, pero cualquiera de las dos es una solución aceptable para mi problema actual: restringir un archivo de forma poligonal a los Estados Unidos continentales).

  1. Coloque cada elemento que no esté completamente dentro del cuadro delimitador. Esto parece bbox()<-ser la forma lógica, pero no existe tal método.

  2. Realice una operación de recorte verdadera, de modo que los elementos no infinitesimales (por ejemplo, polígonos, líneas) se corten en el límite . sp::bboxcarece de un método de asignación, por lo que la única forma en que se me ocurre sería usar overo gContains/ gCrossesjunto con un objeto SpatialPolygons que contiene un cuadro con las nuevas coordenadas del cuadro delimitador. Luego, al recortar un objeto de polígono, tendría que averiguar cuáles están contenidos frente a la cruz, y alterar las coordenadas de esos polígonos para que no excedan el cuadro. O algo asi gIntersection. ¿Pero seguramente hay una manera más simple?

Si bien sé que hay muchos problemas con los cuadros delimitadores , y que una superposición espacial a un polígono que define la región de interés suele ser preferible, en muchas situaciones, los cuadros delimitadores funcionan bien y son más simples.


Para ser claros, si su objeto espacial está extendido (polígonos o líneas), ¿desea cortarlo de modo que solo devuelva el fragmento que está dentro de su extensión dada? No creo que haya una manera más simple.
Spacedman

@Spacedman Aclaró que estoy interesado en ambos, pero la versión más simple sería suficiente para la presente pregunta.
Ari B. Friedman

¿Ya ha implementado la solución para (2) usar rgeos? Parece que al menos lo has intentado. ¿Podría darnos esa solución y un ejemplo para que al menos tengamos algo con lo que compararnos por la "simplicidad"? Porque, para ser sincero, eso parece bastante simple.
Spacedman

@Spacedman Todo es simple; solo toma tiempo .... :-) Lo probé gIntersectiony se me ocurrió Error in RGEOSBinTopoFunc(spgeom1, spgeom2, byid, id, "rgeos_intersection") : TopologyException: no outgoing dirEdge found at 3 2.5 No hay tiempo para depurar hoy; escribió una versión descuidada y la arreglará en el futuro.
Ari B. Friedman

Respuestas:


11

¡He creado una pequeña función para este mismo propósito y ha sido utilizada por otros con buenas críticas!

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)
}

Esto debería solucionar tu problema. Más explicación está aquí: http://robinlovelace.net/r/2014/07/29/clipping-with-r.html

El polígono ficticio b_polyque se crea no tiene una cadena proj4, lo que da como resultado " Advertencia: spgeom1 y spgeom2 tienen diferentes cadenas proj4 ", pero esto es inofensivo.


He sp, maptools, rgdal, y rgeoscargado. ¿Tengo un Error in .class1(object) : could not find function "extent"problema con la versión R / paquete tal vez?
gregmacfarlane

Tenga library(raster)en cuenta la línea en mi tutorial: robinlovelace.net/r/2014/07/29/clipping-with-r.html ¡ cuéntanos cómo te va! Salud.
RobinLovelace

Esto produce un mensaje de advertencia para mí: spgeom1 y spgeom2 tienen diferentes cadenas proj4. Agregar proj4string (b_poly) <- proj4string (shp) debería resolverlo?
Matifou

7

Aquí hay una versión límite descuidada (suficiente para satisfacer mis necesidades a tiempo para la mini-fecha límite mañana :-)):

#' 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),]
}

recorte de bbox

Si necesita el cuadro delimitador para proyectar, la versión aquí agrega un interpolateargumento, de modo que el cuadro proyectado resultante sea curvo.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.