Rでのポリゴンのプロットを高速化する方法は?


24

北米の国境をいくつかの変数を表すラスターイメージ上にプロットし、Rを使用してプロットの上に等高線を重ねたいと思います。ベースグラフィックスとラティスを使用してこれを行うことに成功しましたが、遅すぎる!私はまだggplot2でこれを行っていませんが、速度の点でより良くなるとは思いません。

gribファイルから作成されたnetcdfファイルにデータがあります。今のところ、私はからRDATAファイルで使用可能だったカナダ、米国、メキシコ、のために国境をダウンロードGADM SpatialPolygonsDataFrameがオブジェクトとしてRに読み込みます。

コードは次のとおりです。

# Load packages
library(raster)
#library(ncdf) # If you cannot install ncdf4
library(ncdf4)

# Read in the file, get the 13th layer
# fn <- 'path_to_file'
r <- raster(fn, band=13)

# Set the projection and extent
p4 <- "+proj=lcc +lat_1=50.0 +lat_2=50.0 +units=km +x_0=32.46341 +y_0=32.46341 +lon_0=-107 +lat_0=1.0"
projection(r) <- CRS(p4)
extent(r) <- c(-5648.71, 5680.72, 1481.40, 10430.62)

# Get the country borders
# This will download the RData files to your working directory
can<-getData('GADM', country="CAN", level=1)
usa<-getData('GADM', country="USA", level=1)
mex<-getData('GADM', country="MEX", level=1)

# Project to model grid
can_p <- spTransform(can, CRS(p4))
usa_p <- spTransform(usa, CRS(p4))
mex_p <- spTransform(mex, CRS(p4))

### USING BASE GRAPHICS
par(mar=c(0,0,0,0))
# Plot the raster
bins <- 100
plot(r, axes=FALSE, box=FALSE, legend=FALSE,
     col=rev( rainbow(bins,start=0,end=1) ),
     breaks=seq(4500,6000,length.out=bins))
plot(r, legend.only=TRUE, col=rev( rainbow(bins,start=0,end=1)),
     legend.width=0.5, legend.shrink=0.75, 
     breaks=seq(4500,6000,length.out=bins),
     axis.args=list(at=seq(4500,6000,length.out=11),
                labels=seq(4500,6000,length.out=11),
                cex.axis=0.5),
     legend.args=list(text='Height (m)', side=4, font=2, 
                      line=2, cex=0.8))
# Plot the borders
# These are so slow!!
plot(can_p, add=TRUE, border='white', lwd=2)
plot(usa_p, add=TRUE, border='white', lwd=2)
plot(mex_p, add=TRUE, border='white', lwd=2)
# Add the contours
contour(r, add=TRUE, nlevel=5)

### USING LATTICE
library(rasterVis)

# Some settings for our themes
myTheme <- RdBuTheme()
myTheme$axis.line$col<-"transparent"
myTheme$add.line$alpha <- 1
myTheme2 <- myTheme
myTheme2$regions$col <- 'transparent'
myTheme2$add.text$cex <- 0.7
myTheme2$add.line$lwd <- 1
myTheme2$add.line$alpha <- 0.8

# Get JUST the contour lines
contours <- contourplot(r, margin=FALSE, scales=list(draw=FALSE),
                        par.settings=myTheme2, pretty=TRUE, key=NULL, cuts=5,
                        labels=TRUE)

# Plot the colour
levels <- levelplot(r, contour=FALSE, margin=FALSE, scales=list(draw=FALSE),
                    par.settings = myTheme, cuts=100)

# Plot!
levels +  
  layer(sp.polygons(can_p, col='green', lwd=2)) +
  layer(sp.polygons(usa_p, col='green', lwd=2)) +
  layer(sp.polygons(mex_p, col='green', lwd=2)) +
  contours

ポリゴンのプロットを高速化する方法はありますか?私が取り組んでいるシステムでは、プロットに数分かかります。最終的には、検査のためにこれらのプロットを簡単に生成する関数を作成したいと考えています。これらのマップの多くをプロットするので、プロットの速度を上げたいと思います。

ありがとう!


そのようなアイデアですが、ポリゴンジオメトリフィールドにインデックスを作成できますか?
レーダーの下

@ Burton449申し訳ありませんが、ポリゴン、投影などを含むRのマッピング関連のものは
初めてです

2
プロットウィンドウ以外のデバイスにプロットすることもできます。プロット関数をpdfまたはjpeg(関連する引数付き)でラップし、これらの形式のいずれかを出力します。これはかなり速いことがわかりました。
ジェフリーエヴァンス

@JeffreyEvansうわー、うん。私はそれを考慮しませんでした。3つの形状ファイルのプロットウィンドウへのプロットには約60秒かかりましたが、ファイルへのプロットには14秒しかかかりませんでした。目の前のタスクにはまだ遅すぎますが、以下の回答のいくつかの方法と組み合わせると便利な場合があります。ありがとう!
ialm

回答:


30

Rの形状ファイルから国境をプロットする速度を上げる3つの方法を見つけましここここからインスピレーションとコードを見つけまし

(1)形状ファイルから座標を抽出して、ポリゴンの経度と緯度を取得できます。次に、最初の列に経度を、2番目の列に緯度を含むデータフレームにそれらを配置できます。さまざまな形状がNAで区切られています。

(2)シェイプファイルからいくつかのポリゴンを削除できます。シェイプファイルは非常に詳細ですが、いくつかのシェイプは重要ではない小さな島です(とにかく私のプロットでは)。より大きなポリゴンを維持するために、ポリゴンエリアの最小しきい値を設定できます。

(3)Douglas-Peukerアルゴリズムを使用して、形状のジオメトリを単純化できます。ポリゴンシェイプのエッジは、元のファイルでは非常に複雑なので、単純化できます。幸いなことに、rgeosこれを実装するパッケージがあります。

セットアップ:

# Load packages
library(rgdal)
library(raster)
library(sp)
library(rgeos)

# Load the shape files
can<-getData('GADM', country="CAN", level=0)
usa<-getData('GADM', country="USA", level=0)
mex<-getData('GADM', country="MEX", level=0)

方法1:形状ファイルからデータフレームに座標を抽出し、ラインをプロットする

主な欠点は、投影などのオブジェクトをSpatialPolygonsDataFrameオブジェクトとして保持する場合と比較すると、ここで情報が失われることです。ただし、spオブジェクトに戻して投影情報を追加し直すことができますが、元のデータをプロットするよりも高速です。

多くの形状があるため、このコードは元のファイルで非常にゆっくり実行され、結果のデータフレームは最大200万行の長さであることに注意してください。

コード:

# Convert the polygons into data frames so we can make lines
poly2df <- function(poly) {
  # Convert the polygons into data frames so we can make lines
  # Number of regions
  n_regions <- length(poly@polygons)

  # Get the coords into a data frame
  poly_df <- c()
  for(i in 1:n_regions) {
    # Number of polygons for first region
    n_poly <- length(poly@polygons[[i]]@Polygons)
    print(paste("There are",n_poly,"polygons"))
    # Create progress bar
    pb <- txtProgressBar(min = 0, max = n_poly, style = 3)
    for(j in 1:n_poly) {
      poly_df <- rbind(poly_df, NA, 
                       poly@polygons[[i]]@Polygons[[j]]@coords)
      # Update progress bar
      setTxtProgressBar(pb, j)
    }
    close(pb)
    print(paste("Finished region",i,"of",n_regions))
  }
  poly_df <- data.frame(poly_df)
  names(poly_df) <- c('lon','lat')
  return(poly_df)
}

方法2:小さなポリゴンを削除する

非常に重要ではない多くの小さな島があります。ポリゴンのエリアの分位点のいくつかをチェックすると、それらの多くが非常に小さいことがわかります。カナダのプロットでは、1000個以上のポリゴンから100個以上のポリゴンにプロットしました。

カナダのポリゴンのサイズの分位点:

          0%          25%          50%          75%         100% 
4.335000e-10 8.780845e-06 2.666822e-05 1.800103e-04 2.104909e+02 

コード:

# Get the main polygons, will determine by area.
getSmallPolys <- function(poly, minarea=0.01) {
  # Get the areas
  areas <- lapply(poly@polygons, 
                  function(x) sapply(x@Polygons, function(y) y@area))

  # Quick summary of the areas
  print(quantile(unlist(areas)))

  # Which are the big polygons?
  bigpolys <- lapply(areas, function(x) which(x > minarea))
  length(unlist(bigpolys))

  # Get only the big polygons and extract them
  for(i in 1:length(bigpolys)){
    if(length(bigpolys[[i]]) >= 1 && bigpolys[[i]] >= 1){
      poly@polygons[[i]]@Polygons <- poly@polygons[[i]]@Polygons[bigpolys[[i]]]
      poly@polygons[[i]]@plotOrder <- 1:length(poly@polygons[[i]]@Polygons)
    }
  }
  return(poly)
}

方法3:多角形の形状の単純化

パッケージのgSimplify関数を使用して、ポリゴンシェイプの頂点の数を減らすことができrgeosます

コード:

can <- getData('GADM', country="CAN", level=0)
can <- gSimplify(can, tol=0.01, topologyPreserve=TRUE)

いくつかのベンチマーク:

経過時間を使用しsystem.timeて、プロット時間のベンチマークを行いました。これらは、国をプロットするときであり、等高線やその他の余分なものはありません。spオブジェクトについては、plot関数を使用しました。データフレームオブジェクトの場合、plot関数with type='l'および関数を使用しましたlines

元のカナダ、アメリカ、メキシコのポリゴンをプロットする:

73.009秒

方法1を使用する:

2.449秒

方法2を使用する:

17.660秒

方法3を使用する:

16.695秒

方法2 + 1を使用:

1.729秒

方法2 + 3を使用:

0.445秒

方法2 + 3 + 1を使用:

0.172秒

その他のコメント:

方法2 + 3を組み合わせることで、ポリゴンの描画が十分に高速化されるようです。メソッド2 + 3 + 1を使用するspと、オブジェクトの優れたプロパティが失われるという問題が発生し、主な問題は投影の適用です。データフレームオブジェクトを投影するために何かを一緒にハッキングしましたが、実行はかなり遅くなります。方法2 + 3を使用すると、方法2 + 3 + 1を使用することで問題が解決するまで、十分なスピードアップが得られると思います。


3
+1を書くと、間違いなく将来の読者が役に立つと思うでしょう。
SlowLearner

3

誰もがspではなくsf(空間機能)パッケージへの移行を検討する必要があります。大幅に高速(この場合は60分の1)で使いやすくなっています。以下は、shpを読み取り、ggplot2を介してプロットする例です。

注:githubの最新ビルドからggplot2を再インストールする必要があります(以下を参照)

library(rgdal)
library(sp)
library(sf)
library(plyr)
devtools::install_github("tidyverse/ggplot2")
library(ggplot2)

# Load the shape files
can<-getData('GADM', country="CAN", level=0)
td <- file.path(tempdir(), "rgdal_examples"); dir.create(td)
st_write(st_as_sf(can),file.path(td,'can.shp'))


ptm <- proc.time()
  can = readOGR(dsn=td, layer="can")
  can@data$id = rownames(can@data)
  can.points = fortify(can, region="id")
  can.df = join(can.points, can@data, by="id")
  ggplot(can.df) +  geom_polygon(aes(long,lat,group=group,fill='NAME_ENGLISH'))
proc.time() - ptm

user  system elapsed 
683.344   0.980 684.51 

ptm <- proc.time()
  can2 = st_read(file.path(td,'can.shp'))  
  ggplot(can2)+geom_sf( aes(fill = 'NAME_ENGLISH' )) 
proc.time() - ptm

user  system elapsed 
11.340   0.096  11.433 

0

GADMデータは、海岸線の非常に高い空間解像度を持っています。不要な場合は、より一般化されたデータセットを使用できます。ialmのアプローチは非常に興味深いですが、単純な代替方法は、「maptools」に付属する「wrld_simpl」データを使用することです

library(maptools)
data(wrld_simpl)
plot(wrld_simpl)

データセットには、その地域の国内の境界(州や州など)の境界が含まれているため、データセットの形状を保持したかったのです。そうでなければ、マップデータパッケージのマップを使用することになります。
ialm
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.