Clip Oggetto spaziale nella casella di delimitazione in R


13

Dato un oggetto Spaziale in R, come posso ritagliare tutti i suoi elementi in un riquadro di selezione?

Ci sono due cose che mi piacerebbe fare (idealmente saprei fare entrambe le cose, ma una delle due è una soluzione accettabile al mio problema attuale: limitare un file di forma poligonale agli Stati Uniti continentali).

  1. Rilascia ogni elemento non completamente all'interno del rettangolo di selezione. Questo sembra bbox()<-essere il modo logico, ma non esiste un tale metodo.

  2. Esegui una vera operazione di ritaglio, in modo tale che elementi non infinitesimali (ad esempio poligoni, linee) vengano tagliati al limite . sp::bboxmanca un metodo di assegnazione, quindi l'unico modo che ho escogitato sarebbe usare overo gContains/ gCrossesin combinazione con un oggetto SpatialPolygons contenente una casella con le coordinate della nuova casella di delimitazione. Quindi, quando si ritaglia un oggetto poligonale, è necessario capire quali sono contenuti rispetto a croce e modificare le coordinate di quei poligoni in modo che non superino la casella. O qualcosa del genere gIntersection. Ma sicuramente c'è un modo più semplice?

Mentre so che ci sono molti problemi con i riquadri di delimitazione e che una sovrapposizione spaziale a un poligono che definisce la regione di interesse è generalmente preferibile, in molte situazioni, i riquadri di delimitazione funzionano bene e sono più semplici.


Per essere chiari, se il tuo oggetto spaziale viene esteso (poligoni o linee) vuoi tagliarlo in modo tale da restituire solo la parte di esso che è all'interno della tua estensione? Non penso che ci sia un modo più semplice.
Spaziale

@Spacedman Chiarito che sono interessato ad entrambi, ma la versione più semplice sarebbe sufficiente per la domanda attuale.
Ari B. Friedman,

Hai già implementato la soluzione per (2) usare rgeos? Sembra che tu abbia almeno provato. Potresti darci quella soluzione e un esempio per cui almeno abbiamo qualcosa da confrontare per "semplicità"? Perché, a dire il vero, sembra abbastanza semplice.
Spaziale

@Spacedman È tutto semplice; vuole solo tempo .... :-) ho provato con gIntersectione si avvicinò con Error in RGEOSBinTopoFunc(spgeom1, spgeom2, byid, id, "rgeos_intersection") : TopologyException: no outgoing dirEdge found at 3 2.5 Non c'è tempo per eseguire il debug di oggi; ha scritto una versione sciatta e risolverà in futuro.
Ari B. Friedman,

Risposte:


11

Ho creato una piccola funzione proprio per questo ed è stata utilizzata da altri con buone recensioni!

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

Questo dovrebbe risolvere il tuo problema. Ulteriori spiegazioni sono qui: http://robinlovelace.net/r/2014/07/29/clipping-with-r.html

Il poligono fittizio b_polycreato non ha una stringa proj4, che si traduce in " Avvertenza: spgeom1 e spgeom2 hanno stringhe proj4 diverse ", ma questo è innocuo.


Ho sp, maptools, rgdal, e rgeoscaricato. Ottengo Error in .class1(object) : could not find function "extent"forse il problema con la versione R / pacchetto?
Gregregacarlane,

Nota la linea library(raster)nel mio tutorial: robinlovelace.net/r/2014/07/29/clipping-with-r.html facci sapere come vai avanti! Saluti.
RobinLovelace,

Questo produce un messaggio di avviso per me: spgeom1 e spgeom2 hanno stringhe proj4 diverse. L'aggiunta di proj4string (b_poly) <- proj4string (shp) dovrebbe risolverlo?
Matifou

7

Ecco una versione al limite sciatta (sufficiente per soddisfare le mie esigenze in tempo per la mini-scadenza di domani :-)):

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

ritaglio di bbox

Se è necessario proiettare il riquadro di delimitazione, la versione qui aggiunge un interpolateargomento, in modo che il riquadro proiettato risultante sia curvo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.