2015年12月18日金曜日

Rで複数のシェープファイルを結合する

地図で可視化する際の行政界のシェープは、統計局のものをよく利用させてもらっています。↓以下参考。

e-Stat(統計局)で公開されているShapeファイルを、Rで表示する - Rプログラミングの小ネタ

統計局で公開されているシェープは比較的小さい単位に分かれています。例えば、福岡市だと、区単位(東区、博多区、中央区、南区、西区、城南区、早良区)の7つのシェープに分かれています。

こういうのをまとめて1つにしたい時ってありますよね。

QGISのようなGUIのあるGISソフトでやる方法もありますが、数が多くなるとしんどい。ということで、Rのスクリプトでシェープの結合をする方法を紹介します。

ざっくり言うと、readShapePolyで読み込んで、spRbindで結合させるだけなんですけどね。

でも、そう簡単にはいかない時があるんですよね。というのも、ポリゴンのIDがかぶっているとspRbindでエラーが出てしまう。例えば、東区のシェープの中のあるポリゴンに「1」というIDが付いていて、博多区のシェープの中のあるポリゴンにも「1」というIDが付いていると、この2つを結合させようとする際にエラーになってしまいます。

なので、東区のポリゴンはのIDは、"1.1", "1.2", "1.3", ...、博多区のポリゴンのIDは"2.1", "2.2", "2.3", ... みたいにリネームしたあとに、結合させましょうというのが、↓このスクリプトのポイントでございます。

library(maptools)
 
# シェープのファイル名を取得
shape_files <- list.files(path="shape_folder", pattern=".*\\.shp", full.names=T)
 
# 緯度経度、世界測地系
pj <- CRS("+proj=longlat +datum=WGS84")
 
# ポリゴンのIDが重複しないように前処理したあと、
# リストに格納しておく
shape_list <- list() # 空のリストを用意
 
for ( i in 1:length(shape_files) ) {
  # シェープの読み込み
  shp <-readShapePoly(shape_files[i], proj4string=pj)
 
  # id文字列のベクトルを作る
  ids <- paste(i, 1:length(shp@polygons), sep=".")
 
  # polygonsのIDを変更する
  for ( j in 1:length(shp@polygons) ) {
    shp@polygons[[j]]@ID <- ids[j]
  }
 
  # dataの行名もそれに対応して変更する
  row.names(shp@data) <- ids
 
  # リストに追加する
  shape_list <- c(shape_list, shp)
}
 
# リストに格納してある、シェープを結合する
merged <- shape_list[[1]]
for ( i in 2:length(shape_list) ) {
  merged <- spRbind(merged, shape_list[[i]])
}
 
# シェープの書き出し
writePolyShape(merged, "merge.shp")


↓あとは、おまけみたいなもんです。

ちゃんとくっついているかplotしてみます。ifelseでごちゃごちゃ書いているのは、区ごとに色分けするためです。

ややこしいのが海の部分で、ここを同じ色で塗りたいのですが、区によってMOJIの属性(通常は町丁目名が入っている)に「博多湾」と入っていたり、「博多港」と入っていたり、「水面」と入っていたり、NULLが入っていたりする。博多湾とか博多港は分かるけど、「水面」ってなんだよ。

あと、地図に文字をプロットするようなときには、文字が大きいと重なっちゃうし、小さいとつぶれてしまうことがよくあるので、PDFに出力するとベクタとして書き出せるので吉です。

library(RColorBrewer)
cols <- brewer.pal(8, "Pastel2")
 
merged$col <- ifelse ( merged$MOJI=="博多湾" |
                       merged$MOJI=="博多港" |
                       merged$MOJI=="水面"   |
                       is.na(merged$MOJI)       , cols[1],
              ifelse ( merged$CSS_NAME=="東区"  , cols[2],
              ifelse ( merged$CSS_NAME=="博多区", cols[3],
              ifelse ( merged$CSS_NAME=="中央区", cols[4],
              ifelse ( merged$CSS_NAME=="南区"  , cols[5],
              ifelse ( merged$CSS_NAME=="西区"  , cols[6],
              ifelse ( merged$CSS_NAME=="城南区", cols[7],
              ifelse ( merged$CSS_NAME=="早良区", cols[8], "NG" ))))))))
 
pdf("out.pdf", family="Japan1GothicBBB", width=11.69, height=16.54)
plot(merged, col=merged$col, lwd=0.1)
text(merged$X_CODE, merged$Y_CODE, merged$MOJI, cex=0.1)
dev.off()


↓こんな感じで表示されます。

福岡市の行政界地図

↓PDFファイル自体も置いておきますね。

福岡市の行政界地図(PDFファイル)