Recortar objeto espacial para a caixa delimitadora em R


13

Dado um objeto espacial em R, como recorte todos os seus elementos para ficarem dentro de uma caixa delimitadora?

Há duas coisas que eu gostaria de fazer (idealmente, eu sei como fazer as duas coisas, mas também é uma solução aceitável para o meu problema atual - restringir um arquivo de forma de polígono aos EUA continentais).

  1. Solte cada elemento não totalmente dentro da caixa delimitadora. Parece que esse bbox()<-seria o caminho lógico, mas não existe esse método.

  2. Faça uma verdadeira operação de clipe, de modo que elementos não-infinitesimais (por exemplo, polígonos, linhas) sejam cortados no limite . sp::bboxcomo não possui um método de atribuição, a única maneira que eu inventei seria usar overou gContains/ gCrossesem conjunto com um objeto SpatialPolygons contendo uma caixa com as novas coordenadas da caixa delimitadora. Então, ao recortar um objeto de polígono, você terá que descobrir quais estão contidos versus cruzados e alterar as coordenadas desses polígonos para que não excedam a caixa. Ou algo assim gIntersection. Mas certamente há uma maneira mais simples?

Embora eu saiba que existem muitos problemas com caixas delimitadoras e que uma sobreposição espacial de um polígono que define a região de interesse é geralmente preferível, em muitas situações, as caixas delimitadoras funcionam bem e são mais simples.


Só para esclarecer, se o seu objeto espacial é estendido (polígonos ou linhas), você deseja cortá-lo de forma que ele retorne apenas a parte dele que está dentro da sua extensão especificada? Eu não acho que exista uma maneira mais simples.
Spacedman

@ Spacedman Esclareceu que estou interessado em ambos, mas a versão mais simples seria suficiente para a presente pergunta.
Ari B. Friedman

Você já implementou a solução para (2) usando rgeos? Parece que você pelo menos tentou. Você poderia nos dar essa solução e um exemplo para que, pelo menos, tenhamos algo a comparar com a "simplicidade"? Porque, para ser sincero, isso parece bem simples.
Spacedman

@ Spacedman Tudo é simples; leva tempo ... :-) Eu tentei gIntersectione criei Error in RGEOSBinTopoFunc(spgeom1, spgeom2, byid, id, "rgeos_intersection") : TopologyException: no outgoing dirEdge found at 3 2.5 Sem tempo para depurar hoje; escreveu uma versão desleixada e será corrigida no futuro.
Ari B. Friedman

Respostas:


11

Criei uma pequena função para esse fim e foi usada por outras pessoas com boas 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)
}

Isso deve resolver seu problema. Mais explicações estão aqui: http://robinlovelace.net/r/2014/07/29/clipping-with-r.html

O polígono fictício b_polycriado não possui uma seqüência de proj4, o que resulta em " Aviso: spgeom1 e spgeom2 possuem seqüências de proj4 diferentes ", mas isso é inofensivo.


Eu sp, maptools, rgdal, e rgeoscarregado. Error in .class1(object) : could not find function "extent"Talvez eu receba um problema de versão do R / pacote?
Gregmacfarlane

Observe a linha library(raster)no meu tutorial: robinlovelace.net/r/2014/07/29/clipping-with-r.html deixe-nos saber como você se sai! Felicidades.
RobinLovelace

Isso produz uma mensagem de aviso para mim: spgeom1 e spgeom2 têm diferentes seqüências de projeção. Adicionando proj4string (b_poly) <- proj4string (shp) deve resolver isso?
Matifou

7

Aqui está uma versão limite desleixada (suficiente para atender às minhas necessidades a tempo do mini-prazo amanhã :-)):

#' 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 bbox

Se você precisar da caixa delimitadora para projetar, a versão aqui adiciona um interpolateargumento, para que a caixa projetada resultante seja curvada.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.