Rを使ってシェープファイルから白地図を描く

## shapefileを入手する

以下のような場所からライセンス的にも使い勝手の良いシェープファイルが入手できる。

- [国土数値情報　行政区域データの詳細](http://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N03-v2_3.html)
- [政府統計の総合窓口](https://www.e-stat.go.jp/)
  - 「地図で見る > 境界データダウンロード」から検索してダウンロード
  - 例では「境界データ > 小地域 > 国勢調査 > 2015年 > 小地域（町丁・字等別） > 世界測地系緯度経度・Shape形式 > 新潟県」と辿ってダウンロードしたファイルを使用している。

今回はe-statのものを利用した。以下では、シェープファイルが`shp`ディレクトリ以下に展開してあることを想定している。

## 必要パッケージ

`sf`と開発版の`ggplot2`を使う。`ggplot2`開発版には`sf`オブジェクトのための`geom_sf`等が入っている。

```r:入っていなければインストール
devtools::install_github("tidyverse/ggplot2")
install.packages("sf")
install.packages("dplyr") # 記事後半の領域結合で使った
```

```r:パッケージ読み込み
library(ggplot2)
library(sf)
library(dplyr)
```

## シェープファイル読み込み

```r
map <- read_sf("shp/h27ka15103.shp") # 中央区のシェープファイル
```

## プロット

`geom_sf`だけで最低限の描画ができる。

```r
ggplot(map) + geom_sf()
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/109348/ef5f8378-878f-f144-802b-118bde3c243f.png)

余分なものは以下のように削除する。

```r
ggplot(map) + 
  geom_sf(fill = NA) +   # 塗りつぶしの削除
  coord_sf(datum = NA) + # グリッドの削除
  theme_void()           # 軸・背景色の削除
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/109348/6abd3197-e31f-43e5-ca9a-ddddc264bc28.png)

## その他の操作

### 領域を結合したい

`st_union`で結合してしまうと`ggplot`に渡せなくなってしまうので`sf`オブジェクトに再度変換して...とか思ってたら@yutannihilationさんに良い方法を教えて頂いた。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">こういうときはsummarise()が便利かもしれません。 <a href="https://t.co/qBmx0928QS">https://t.co/qBmx0928QS</a></p>&mdash; Hiroaki Yutani (@yutannihilation) <a href="https://twitter.com/yutannihilation/status/966877577833955328?ref_src=twsrc%5Etfw">2018年2月23日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

`summarize`に渡すだけでポリゴン部分は結合されるので、適当にダミーの集計項目を渡してやれば良い。

```r
map %>% summarize("") %>% 
  ggplot() + 
  geom_sf(fill = NA) + 
  coord_sf(datum = NA) +
  theme_void()
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/109348/4a287ba4-2d83-8282-b36f-faf646752bdf.png)

たとえば`group_by`と組み合わせて県域データを市区町村別にまとめるなんてこともできる。

```r
map2 <- read_sf("shp/h27ka15.shp") # 新潟県全域のデータ

map2 %>%
  group_by(CITY_NAME) %>%
  summarize("") %>%
  ggplot() + 
  geom_sf(fill = NA) + 
  coord_sf(datum = NA) +
  theme_void()
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/109348/2ea5afb0-5eb6-5245-0a3d-10a79cfbadac.png)

### svgで出力したい

`ggsave`で`device="svg"`を指定すればsvgできれいに出力できる。(`svglite`のインストールが必要な場合がある。)

```r
p <- ggplot(map) +  # オブジェクトに格納
  geom_sf(fill = NA) +   # 塗りつぶしの削除
  coord_sf(datum = NA) + # グリッドの削除
  theme_void()           # 軸・背景色の削除

# install.packages("svglite")
ggsave(p, filename = "niigata.svg", device = "svg")
```

### 市名とかを書き込みたい

今回使用した県域のデータ`h27ka15.shp`では`CITY_NAME`に市名が格納されている。

`geom_sf`を使ってテキストも書けると楽なんだけど、多分実装されない(cf. [stat_sf(geom = "text") · Issue #2111 · tidyverse/ggplot2](https://github.com/tidyverse/ggplot2/issues/2111))ので、x座標とy座標を抽出して`geom_text`に渡してやる。

もしデータ内に既に代表になりそうな点の情報が含まれていれば(そういう場合は多い)、それを使用して

```r
geom_text(aes(x = x座標, y = y座標, label = 書き込みたいラベル列))
```

などとやってやればよいが(※さらに環境によっては`family=`でフォントを指定しないと文字化けする場合がある)、入っていない場合、あるいは例えば領域の結合などの操作を行った場合には自分で書き込み位置を指定しなければならない。今回は書き込み位置は領域の重心とする。重心の計算は`st_centroid`で、計算結果からの座標値抽出は`st_coordinates`で行う。

以下に県域データを市単位でまとめ、市名を書き込む例を示す。

```r
map2 %>%
  group_by(CITY_NAME) %>% # 市名でグルーピング
  summarize("") %>% # グループ単位で領域結合
  mutate( # 重心計算と座標値の抽出
    centroid = st_centroid(geometry),
    x = st_coordinates(centroid)[, 1],
    y = st_coordinates(centroid)[, 2]
  ) %>%
  ggplot() +
  geom_sf(fill = NA) + 
  geom_text(aes(x = x, y = y, label = CITY_NAME),
            family = "Osaka", size = 2) + # mac向けフォント指定
  coord_sf(datum = NA) + 
  theme_void()
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/109348/feb5e548-6af1-9022-17ac-aedc06c8733c.png)