Rのcartographyパッケージで主題図の作成

#  cartographyパッケージ
R上で主題図の作成ができるcartographyパッケージを紹介します。
地図製作者やRユーザーが直感的に作業できるように設計されているそうで、操作はかなり簡単です。
QGISで主題図を作成すると作業過程が残せないので、R上で主題図が作成できるこのパッケージは非常に便利だと思います。

※使いやすさの観点から標準のplot準拠で作られているので、ggplot2との連携ができない点に注意。


# 使い方
## cartographyのインストール
通常のパッケージ同様、`install.packages("cartography", dependencies = TRUE)`でインストールできます。
ただしUbuntuの場合には、以下のライブラリを事前にシステムにインストールしておく必要があります。

```bash
sudo apt install libgeos-dev libudunits2-dev libgdal-dev
```

## データの準備
今回は[国土数値情報　人口集中地区データ](http://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-A16-v2_3.html)のうち、平成 27年度の東京都部分のデータを用います。
手順に従いデータをダウンロードした後、zipを解凍して「A16-15_13_DID.geojson」を作業ディレクトリに移動します。
cartographyは`sf`クラスに対応しているので、`st_read`でデータを読み込みます。
また緯度経度のままだと実行できても警告が出るので、JGD 2011の9系に投影変換しておきます（[参考1](https://r-spatial.github.io/sf/reference/st_transform.html)、[参考2](http://www.epsg-registry.org/)）。

```R
library(sf) # ベクタの読み込み用
library(cartography)

map.original <- st_read("A16-15_13_DID.geojson")
# shpをインポートする場合
map.original <- st_read("A16-15_13_DID.shp")

map <- st_transform(map.original, crs = 6677) # 投影変換
```
※今回のデータの場合、shpで読み込むと属性名が別のものになるので注意。

## シンボルの描画
cartographyではベースとなるポリゴンを`plot(st_geometry(map))`で描画し、それにレイヤを重ねることで主題図を作成していきます（`plot`に対する`lines`や`points`と同じ）。
基本的には、`x`に対象となるsfオブジェクトを、`var`にシンボルとして描画する属性を指定します。

### 階級区分図(Choropleth)
階級区分図は以下のコマンドで描画できます。

```R
plot(st_geometry(map))
choroLayer(x = map, var = "人口", method = "equal", nclass = 8)
```
分類方法は`method`で指定でき、"sd", "equal", "quantile", "fisher-jenks","q6","geom", "arith", "em", "msd"から選べます。

![choro.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/397fdc0e-303d-8061-adcb-46ae9c85cba1.png)

分割数が可変の場合は`nclass`で分割数を指定できます。


### 類型図(Typology)
類型図は以下のコマンドで描画できます。

```R
plot(st_geometry(map))
typoLayer(x = map, var = "市町村名称")
```
![typo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/9beaac40-f598-3335-05e0-d2543e91aa15.png)

類型数が多すぎるため、凡例がはみ出してしまっています。


### 比例シンボル図(Proportional Symbols)
比例シンボル図は以下のコマンドで描画できます。

```R
plot(st_geometry(map))
propSymbolsLayer(x = map, var = "人口")
```
![prop.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/16abd585-e5d9-19df-cd31-4a29c0e85b42.png)


### 階級区分×比例シンボル図(Proportional Symbols)
階級区分の色分けと比例シンボルを組み合わせた図は以下のコマンドで描画できます。

```R
plot(st_geometry(map))
propSymbolsChoroLayer(x = map, var = "人口", var2 = "面積")
```
`var`に比例シンボルに使う属性を、`var2`に階級区分に使う属性を指定します。

![choro_prop.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/931ba68c-8a5a-a453-ed99-1706c66e77df.png)

凡例がかぶってしまっていますが、直し方は後述します。


### 類型×比例シンボル図(Proportional Symbols)
類型の色分けと比例シンボルを組み合わせた図は以下のコマンドで描画できます。

```R
plot(st_geometry(map))
propSymbolsTypoLayer(x = map, var = "人口", var2 = "市町村名称")
```
`var`に比例シンボルに使う属性を、`var2`に類型区分に使う属性を指定します。

![typo_prop.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/a18b1cf7-c201-ee5a-5906-be59d4b6748f.png)




### ラベルの描画
ラベルの追加には、`labelLayer`関数を使います。

```R
plot(st_geometry(map))
choroLayer(x = map, var = "人口", method = "equal", nclass = 8)
labelLayer(x = map, txt = "市町村名称")
```
`txt`にラベルとして使いたい属性を指定します。

![label.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/a78590cb-9f25-d57c-186e-ae839663807a.png)


### ベースマップをOpenStreetMapに
`getTiles`を使うことで、背景にOpenStreetMapを使用できます。

```R
tiles <- getTiles(x = map, type = "osm")
tilesLayer(tiles)
plot(st_geometry(map), col = NA, border = "black", add = TRUE) # 塗りつぶしをしない
propSymbolsLayer(x = map, var = "人口")
```
`type`は、"osm", "hotstyle", "hikebike", "osmgrayscale", "stamenbw", "stamenwatercolor", "cartodark", "cartolight", "opentopomap"から選べます。

![osm.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/c50728d8-c395-0052-cb92-612315d01fca.png)
下は"cartolight"の例。
![cartod.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/b0faa79f-ddb3-e68a-a644-045dd3c538a4.png)

## レイアウトの変更
### 色の変更
比例シンボルの色は`col`パラメータで変更できます。

```R
plot(st_geometry(map))
propSymbolsLayer(x = map, var = "人口", col = "green")
```

![prop_col.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/c34cb53e-edd0-8133-a588-c6d24104c78a.png)

階級区分図の色は`col`にカラーパレットを指定することで変更可能です。cartographyに入っている、`carto.pal`が便利です。
![cartopal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/01fbcb57-9c3a-6d3e-1bb2-e3dbd66e36ed.png)
https://github.com/rstudio/cheatsheets/blob/master/cartography.pdf より

```R
plot(st_geometry(map))
choroLayer(x = map, var = "人口", method = "equal", nclass = 8, col = carto.pal("red.pal", 8)) # 赤系パレットに変更
```

![choro_col.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/9f4fd75b-26a7-fcf7-5b22-6297889eb0f7.png)

組み合わせパレットを使う場合

```R
plot(st_geometry(map))
choroLayer(x = map, var = "人口", method = "equal", nclass = 8, col = carto.pal(pal1 = "blue.pal", n1 = 4, pal2 = "red.pal", n2 = 4))
```

![choro_col2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/eb570980-300a-d53f-0756-46aaef2843fc.png)

類型図も同様に色を変更できます。

```R
plot(st_geometry(map))
typoLayer(x = map, var = "市町村名称", col = carto.pal("multi.pal"))
```

![typo_col.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/0f23528a-e43c-fcbc-fae3-84fe17c26016.png)


### 凡例の編集
凡例の位置やタイトルは、`legend.pos`や`legend.title.txt `を変更することで変更できます。

```R
plot(st_geometry(map))
propSymbolsChoroLayer(x = map, var = "人口", var2 = "面積", legend.var.pos = "bottomleft", legend.var.title.txt = "Pop", legend.var2.pos = "bottomright", legend.var2.title.txt = "Area")
```
![choro_prop_leg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/8e370604-728a-71a8-de97-e67c10742ff0.png)

ただし今回の類型図のように、あまりにも凡例が大きいときには収めるのが難しそうです。
その場合には、`legend.pos`に`"n"`を指定して凡例を消したあと、`legendTypo`（`legendChoro `、`legendCirclesSymbols`）を使って再度描画すればできるかも？


### 方位記号等の追加
方位記号の追加は`north`で行います。

```R
plot(st_geometry(map))
choroLayer(x = map, var = "人口", method = "equal", nclass = 8)
north(pos = "topright")
```

![arrow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/331dd103-e260-9f18-24e8-87287cb0d0b6.png)

スケールの追加は`barscale`で行います。

```R
plot(st_geometry(map))
choroLayer(x = map, var = "人口", method = "equal", nclass = 8)
barscale(size = 20)
```
スケールの大きさは`size`で指定します。単位はkmで、緯度経度のままだとうまく描画されません。

![scale.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/545ad2bc-1806-4b5c-bba8-d3c7c685168b.png)


### 全体のレイアウト
方位記号、スケール含めて、`layoutLayer`で全体のレイアウトを指定できます。

```R
plot(st_geometry(map))
choroLayer(x = map, var = "人口", method = "equal", nclass = 4, legend.pos = "topleft")
layoutLayer(title = "DIDの人口", sources = "Data from http://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-A16-v2_3.html", author = "ocean_f", scale = 20, north = TRUE, frame = TRUE)
```
![full_lay.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/54efc688-398a-2a1f-6d99-6890e3cd4824.png)


## レイアウト例
以上を使ってレイアウトをすると以下のようになります。ファイルに保存する際には通常のplotと同様、デバイスを起動させて出力します。
実際は描画範囲のコントロールもできるようですが、ここでは省略しています。

```R
png("example.png", width = 780, height = 600)
tiles <- getTiles(x = map, type = "cartolight")
tilesLayer(tiles)
plot(st_geometry(map), add = TRUE)
propSymbolsChoroLayer(x = map, var = "人口", var2 = "面積", col = carto.pal(pal1 = "blue.pal", n1 = 4, pal2 = "red.pal", n2 = 4), legend.var.pos = "left", legend.var.title.txt = "人口（人）", legend.var2.pos = "topleft", legend.var2.title.txt = "面積（km2）")
labelLayer(x = map, txt = "市町村名称")
layoutLayer(title = "DIDの人口と面積", sources = "Data from http://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-A16-v2_3.html", author = "ocean_f", scale = 20, north = TRUE, frame = TRUE)
dev.off()
```
![example.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535720/d79c4540-b68c-1b4c-39d9-48bbe9532bea.png)



# 参考・備考
より詳しい使い方は、[cartographyのvignette](https://cran.r-project.org/web/packages/cartography/vignettes/cartography.html)と[cartographyのcheat sheet](https://github.com/rstudio/cheatsheets/blob/master/cartography.pdf)、[cartographyのReference manual](https://cran.r-project.org/web/packages/cartography/cartography.pdf)を参照してください。他のシンボルの描画もできるうえ、かなり細かくパラメータ設定ができます。

ggplot2でも主題図の作成はできて、より汎用性が高いですが、色分けやラベルの追加にはそれなりの慣れが必要です。
簡単に主題図を作りたいときにはこのパッケージが非常に便利だと思います。