web-dev-qa-db-ja.com

gbufferを使用してRの(地理)空間ポイントをバッファリングする

データセット内のポイントを半径100kmでバッファリングしようとしています。パッケージgBufferの関数rgeosを使用しています。これが私がこれまでに持っているものです:

head( sampledf )
#  postalcode      lat       lon       city province
#1     A0A0A0 47.05564 -53.20198     Gander       NL
#4     A0A1C0 47.31741 -52.81218 St. John's       NL

coordinates( sampledf ) <- c( "lon", "lat" )
proj4string( sampledf ) <- CRS( "+proj=longlat +datum=WGS84" )
distInMeters <- 1000
pc100km <- gBuffer( sampledf, width=100*distInMeters, byid=TRUE )

次の警告が表示されます。

GBuffer(sampledf、width = 100 * distInMeters、byid = TRUE)の場合:空間オブジェクトは投影されません。 GEOSは平面座標を期待しています

私が理解/読んだことから、データセットの座標参照系(CRS)、特に射影を「地理的」から「射影」に変更する必要があります。これを変更する方法がわかりません。これらはすべてカナダの住所です、私が付け加えるかもしれません。したがって、NAD83を選択するのは自然な予測のように思えますが、間違っている可能性があります。

任意/すべての助けをいただければ幸いです。

12
vathymut

もう少し掘り下げてみると、「投影された」座標参照系の使用は次のように簡単であることがわかります。

# To get Statscan CRS, see here:
# http://spatialreference.org/ref/epsg/3347/
pc <- spTransform( sampledf, CRS( "+init=epsg:3347" ) ) 

STATSCAN(カナダの住所に適しています)で使用されるEPSG3347は、ランベルト正角円錐図法を使用します。 NAD83は不適切であることに注意してください。これは、「予測された」CRSではなく「地理的な」CRSです。ポイントをバッファリングするには

pc100km <- gBuffer( pc, width=100*distm, byid=TRUE )
# Add data, and write to shapefile
pc100km <- SpatialPolygonsDataFrame( pc100km, data=pc100km@data )
writeOGR( pc100km, "pc100km", "pc100km", driver="ESRI Shapefile" ) 
20
vathymut

@MichaelChiricoが指摘したように、usergeos::gBuffer()にデータを投影する場合は注意が必要です。私は測地線の専門家ではありませんが、このESRIの記事( 測地線バッファリングについて )から理解できる限り、gBufferを投影して適用すると、実際に生成することを意味しますEuclidean =バッファとは対照的に測地線バッファ。ユークリッドバッファは、投影された座標系によって導入された歪みの影響を受けます。これらの歪みは、分析に広いバッファーが含まれている場合、特に広い範囲の緯度の範囲が広い場合は、心配する必要があるかもしれません(カナダが良い候補だと思います)。

しばらく前に同じ問題に遭遇し、質問をgis.stackexchangeに向けました- Rのユークリッドおよび測地線バッファリング 。私が提案したRコードと与えられた答えは、ここでもこの質問に関連していると思います。

主なアイデアは、geosphere::destPoint()を利用することです。詳細とより高速な代替手段については、上記のgis.stackexchangeリンクを参照してください。これがあなたの2つのポイントに適用された私の古い試みです:

library(geosphere)
library(sp)

pts <- data.frame(lon = c(-53.20198, -52.81218),
                  lat = c(47.05564, 47.31741))
pts
#>         lon      lat
#> 1 -53.20198 47.05564
#> 2 -52.81218 47.31741

make_GeodesicBuffer <- function(pts, width) {

  # A) Construct buffers as points at given distance and bearing ---------------

  dg <- seq(from = 0, to = 360, by = 5)

  # Construct equidistant points defining circle shapes (the "buffer points")
  buff.XY <- geosphere::destPoint(p = pts, 
                                  b = rep(dg, each = length(pts)), 
                                  d = width)

  # B) Make SpatialPolygons -------------------------------------------------

  # Group (split) "buffer points" by id
  buff.XY <- as.data.frame(buff.XY)
  id  <- rep(1:dim(pts)[1], times = length(dg))
  lst <- split(buff.XY, id)

  # Make SpatialPolygons out of the list of coordinates
  poly   <- lapply(lst, sp::Polygon, hole = FALSE)
  polys  <- lapply(list(poly), sp::Polygons, ID = NA)
  spolys <- sp::SpatialPolygons(Srl = polys, 
                                proj4string = CRS("+proj=longlat +ellps=WGS84 +datum=WGS84"))
  # Disaggregate (split in unique polygons)
  spolys <- sp::disaggregate(spolys)
  return(spolys)
}

pts_buf_100km <- make_GeodesicBuffer(as.matrix(pts), width = 100*10^3)

# Make a kml file and check the results on Google Earth
library(plotKML)
#> plotKML version 0.5-9 (2019-01-04)
#> URL: http://plotkml.r-forge.r-project.org/
kml(pts_buf_100km, file.name = "pts_buf_100km.kml")
#> KML file opened for writing...
#> Writing to KML...
#> Closing  pts_buf_100km.kml

2019-02-11に reprexパッケージ (v0.2.1)によって作成されました

enter image description here


そして、おもちゃで関数をパッケージにラップしました geobuffer

次に例を示します。

# install.packages("devtools") # if you do not have devtools, then install it
devtools::install_github("valentinitnelav/geobuffer")
library(geobuffer)

pts <- data.frame(lon = c(-53.20198, -52.81218),
                  lat = c(47.05564, 47.31741))

pts_buf_100km <- geobuffer_pts(xy = pts, dist_m = 100*10^3)

2019-02-11に reprexパッケージ (v0.2.1)によって作成されました

他の人はより良い解決策を思い付くかもしれませんが、今のところ、これは私の問題に対してうまく機能し、うまくいけば他の問題も解決できるでしょう。

3
Valentin