備忘ログ

チラシの裏的備忘録&メモ

国土地理院のシェープファイルからRで使いやすいデータを作ってggplot2で都道府県レベルの日本地図を描くメモ

国土地理院の公開している日本の行政区域のシェープファイルをつかってRで使いやすい塩梅の都道府県レベルのデータにして{ggplot2}で日本地図(都道府県レベル)を描画する。

以前書いたこれ

indenkun.hatenablog.com

がだめになったので代替案的な。

シェープファイルをいい塩梅のレベルに単純化する過程が少し時間を要するので実行するのには注意が必要。簡単に地図を描くだけなら既存のデータを使ったほうがよいと思う。ただ、国土地理院シェープファイルからRで使いやすいデータを作れるようになっておくと、いつも使っていたパッケージ内に格納されていたデータが使えなくなったり、使っていたデータの公開が終了したりと不意に今まで使っていた方法がだめになったときのつぶしが効くので良いと思う。

やっていることはシェープファイルを読むの書き方をちょっと変えている感じ(だと思っている)。

国土地理院国土数値情報ダウンロードのページの行政区域データから最新版データ(令和3年はN03-20210101.zip)をダウンロードする。

ダウンロードしたzipファイルを作業ディレクトリにおいておく。

使うライブラリはシェープファイルの読み込みに{kokudosuuchi}を、シェープファイルの簡略化と市町村レベルの行政区域を都道府県レベルにするために{rmapshaper}、データハンドリングのために{tidyverse}(実際に使うのは{dplyr){purrr}{stringr}{ggplot2}だが一括で読んだほうが楽ちんな気がする)を読み込んでおく。

jmapオブジェクトにシェープファイルを読み込んで、特に今回は必要性にやや乏しいが、translateKSJData()で見やすいデータにしておく。

library(tidyverse)
## -- Attaching packages --------------------------------------- tidyverse 1.3.1 --

## v ggplot2 3.3.5     v purrr   0.3.4
## v tibble  3.1.4     v dplyr   1.0.7
## v tidyr   1.1.3     v stringr 1.4.0
## v readr   2.0.1     v forcats 0.5.1

## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
library(kokudosuuchi)
library(rmapshaper)
## Registered S3 method overwritten by 'geojsonlint':
##   method         from 
##   print.location dplyr
jmap <- readKSJData("N03-20210101_GML.zip") %>% 
  translateKSJData()
## Warning: Failed to translate these codes in 行政区域コード: 03216, 04216, 11246,
## 12239, 40231

このjmapはリスト形式のデータになっておりシェープデータはリストの1番目に格納されているので取り出しておく。

jmap <- jmap[[1]]

都道府県名だとあとで条件づけて処理する時に使いにくいので都道府県コード(自治コードの上2桁)を取り出し、数値にしておく(01なら1になるように)。

jmap <- jmap %>% 
  mutate(都道府県コード = as.numeric(str_sub(行政区域コード_code, 1, 2)))

jmapデータは市区町村レベルになっているので都道府県レベルにしたいので都道府県レベルで外側にしてその中で分割されている線をms_dissolve()を使って消す(集計する)。

このとき各都道府県ごとにmap()つかって処理して最後にくっつけてデータとするように処理する。都道府県コードと都道府県名はデータ内から取り出してデータにつけておく。直接jmap <- ms_dissolve(jmap, field = "都道府県コード", copy_fields = "都道府県名")でも集計できそうだが自分の貧弱(メモリ8G)な環境だとRが落ちる。

jmap <- 1:47 %>% 
  map(function(x){
    jmap %>% 
      filter(都道府県コード == x) %>% 
      ms_dissolve(copy_fields = c("都道府県コード", "都道府県名"))
  }) %>% 
  reduce(rbind)

ここでできたjmapは簡便に取り扱いうには精緻なデータすぎて重たいのでms_simplify()を使って単純化する。

純化する時に、jmapオブジェクトをそのまま処理させようとすると重たくてRが落ちるので北海道、本州、四国、九州・沖縄の4分割して単純化してそれを結合してデータとする。都道府県ごとに単純化処理すると都道府県感に変な隙間ができてしまうので、くっついている本州なんかは一緒に処理する。

ちなみにデータは1/100程度に単純化するようにしている。もう少し小さくしても良いかもしれないが、更に単純化するのは簡単だが大きくすることは難しいので大きめに持っておく。

最後に、japanオブジェクトに結合しておく(別にもとのjmapに上書きしてもいいとは思う)。

HOKKAIDOU <- jmap %>% 
  filter(都道府県コード == 1) %>% 
  ms_simplify(keep = 0.01, keep_shapes = TRUE)

HONSHU <- jmap %>% 
  filter(都道府県コード %in% 2:35) %>% 
  ms_simplify(keep = 0.01, keep_shapes = TRUE)

SHIKOKU <- jmap %>% 
  filter(都道府県コード %in% 36:39) %>% 
  ms_simplify(keep = 0.01, keep_shapes = TRUE)

KYUSHU <- jmap %>% 
  filter(都道府県コード %in% 40:47) %>% 
  ms_simplify(keep = 0.01, keep_shapes = TRUE)

japan <- rbind(HOKKAIDOU, HONSHU, SHIKOKU, KYUSHU)

これで都道府県レベルの日本地図データができたのでこれで{ggplot2}で描画する。

japan %>% 
  ggplot() +
  geom_sf()

f:id:indenkun:20210923185653p:plain

こんな感じになる。

ちょっと重たいし、必要精度よりも精緻すぎるのであれば、このjapanデータはすでに軽くなっているので直接ms_simplfy()でデータをさらに単純化できる。試しに1/10にしてみる。

japan %>% 
  ms_simplify(keep = 0.1, keep_shapes = TRUE) %>% 
  ggplot() +
  geom_sf()

f:id:indenkun:20210923185639p:plain

あまり見た目変わらない印象。

完全に白地図にしたいのであれば地図の色をfill = "white"をつかって白に塗ってテーマはtheme_void()を使うといいかもしれない。ついでにデータを更に1/100にしてみる。

japan %>% 
  ms_simplify(keep = 0.01, keep_shapes = TRUE) %>% 
  ggplot() +
  geom_sf(fill = "white") +
  theme_void()

f:id:indenkun:20210923185716p:plain