ggplot2による地理データの可視化

R
作者

伊東宏樹

公開

2024年8月21日

Rのsfパッケージとggplot2パッケージを利用して、地理データを可視化してみます。

準備

sfパッケージとggplot2パッケージを読み込みます。

library(sf)
## Linking to GEOS 3.11.0, GDAL 3.5.3, PROJ 9.1.0; sf_use_s2() is TRUE
library(ggplot2)
jp_font <- "IPAexGothic"

データ

可視化するデータとして、国土数値情報の行政区域データから石川県の2024年のデータ(N03-20240101_17_GML.zip)を使用します。ZIPファイルをダウンロードして、展開されたファイルのうち、GeoJSON形式のファイル(N03-20240101_17.geojson)をst_read関数で読み込みます。

data_file <- file.path("data", "N03-20240101_17.geojson")
data <- st_read(data_file)

読み込んだデータを確認します。

print(data)
## Simple feature collection with 1710 features and 6 fields
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: 136.242 ymin: 36.06723 xmax: 137.3653 ymax: 37.85791
## Geodetic CRS:  WGS 84
## First 10 features:
##    N03_001 N03_002 N03_003 N03_004 N03_005 N03_007
## 1   石川県    <NA>    <NA>  金沢市    <NA>   17201
## 2   石川県    <NA>    <NA>  金沢市    <NA>   17201
## 3   石川県    <NA>    <NA>  金沢市    <NA>   17201
## 4   石川県    <NA>    <NA>  金沢市    <NA>   17201
## 5   石川県    <NA>    <NA>  金沢市    <NA>   17201
## 6   石川県    <NA>    <NA>  金沢市    <NA>   17201
## 7   石川県    <NA>    <NA>  金沢市    <NA>   17201
## 8   石川県    <NA>    <NA>  金沢市    <NA>   17201
## 9   石川県    <NA>    <NA>  七尾市    <NA>   17202
## 10  石川県    <NA>    <NA>  七尾市    <NA>   17202
##                          geometry
## 1  POLYGON ((136.6133 36.49857...
## 2  POLYGON ((136.5991 36.62053...
## 3  POLYGON ((136.5967 36.61824...
## 4  POLYGON ((136.5974 36.6189,...
## 5  POLYGON ((136.5958 36.61709...
## 6  POLYGON ((136.5943 36.61553...
## 7  POLYGON ((136.5952 36.61667...
## 8  POLYGON ((136.5992 36.62078...
## 9  POLYGON ((136.8624 37.08288...
## 10 POLYGON ((136.9981 37.11807...

各列は以下のようになっています。

  • N03_01: 都道府県名
  • N03_02: 北海道の振興局名(石川県にはない)
  • N03_03: 郡名
  • N03_04: 市区町村名
  • N03_05: 政令指定都市の行政区名(これも石川県にはない)
  • N03_07: 全国地方公共団体コード
  • geometry: ジオメトリデータ

ggplot2による可視化

geom_sf関数で可視化します。

ggplot(data) +
  geom_sf()

経線を整理し、テーマをtheme_bwにして、シンプルにします。

ggplot(data) +
  geom_sf() +
  scale_x_continuous(breaks = seq(136.5, 137.5, 0.5)) +
  theme_bw()

あるいは、theme_voidを指定して、地図だけにしてもいいかもしれません。

ggplot(data) +
  geom_sf() +
  theme_void()

市町村ごとに塗りつぶしてみます。凡例の市区町村名が地方公共団体コード順に並ぶように、factor型のname列を追加しています。

name_code <- as.data.frame(data) |>
  dplyr::select(N03_004, N03_007) |>
  dplyr::distinct()
data |>
  dplyr::mutate(name = factor(N03_004,
                              levels = name_code$N03_004)) |>
ggplot() +
  geom_sf(aes(fill = name)) +
  scale_x_continuous(breaks = seq(136.5, 137.5, 0.5)) +
  guides(fill = guide_legend(title = "市町村",
                             ncol = 2)) +
  theme_bw(base_family = jp_font)

しかし、19色もあると色の区別がつけにくいですし、そもそも色に意味はないので、地図上に直接市区町村名(といっても石川県の場合は市町名ですが)を書き込むようにします。

まず、ひとつの市区町村でも複数のポリゴンで構成されているものがありますので、st_union関数をつかってまとめます。また、市区町村名のフィールド名をわかりやすいようにnameにかえています。このように変換したデータをdata2にいれておきます。

data2 <- data |>
  dplyr::group_by(N03_004) |>
  dplyr::summarise(geometry = st_union(geometry)) |>
  dplyr::ungroup() |>
  dplyr::rename(name = N03_004)

geom_sf_text関数で市区町村名を表示します。座標ラベルが表示されるようになるので、labs(x = NULL, y = NULL)で消しています。

ggplot(data2) +
  geom_sf() +
  geom_sf_text(aes(label = name), size = 2.5, family = "IPAexGothic") +
  scale_x_continuous(breaks = seq(136.5, 137.5, 0.5)) +
  labs(x = NULL, y = NULL) +
  theme_bw(base_family = jp_font)
## Warning in st_point_on_surface.sfc(sf::st_zm(x)): st_point_on_surface may not
## give correct results for longitude/latitude data

“st_point_on_surface may not give correct results for longitude/latitude data”という警告が出ますので、本来は座標系を平面直角座標系とかにしておくのがよいのかもしれませんが、とりあえずうまく表示されているので、このままにします。

コロプレス図

次に、各市町の人口データをあわせてコロプレス図を作図してみます。人口データは、e-stat都道府県・市区町村のすがた(社会・人口統計体系)から、石川県内の市町を指定して、総人口データを文字コードUTF-8のCSVファイルとしてダウンロードしました。ファイルの中身は以下のようになっています。

"表題:","都道府県・市区町村のすがた(社会・人口統計体系)"
"公開日:","2024年06月21日"

"調査年","地域","/項目","A1101_総人口【人】"
"2020年度","石川県 金沢市","","463254"
"2020年度","石川県 七尾市","","50300"
"2020年度","石川県 小松市","","106216"
"2020年度","石川県 輪島市","","24608"
(後略)

このデータをread_csv関数で読みこんで、2020年度のものだけ残しました。地域名(name)は、data2nameと整合するように、都道府県名とその後の空白を除いておきます。

library(readr)
library(stringr)

pop_data_file <- file.path("data", "FEI_CITY_240820142223.csv")
pop_data <- read_csv(pop_data_file, skip = 4,
                     col_types = "cc_n",
                     col_names = c("year", "name", "population")) |>
  dplyr::mutate(name = str_sub(name, str_locate(name, " ")[1] + 1)) |>
  dplyr::filter(year == "2020年度")

data2に人口データを結合し、コロプレス図を表示します。人口をあらわす色のスケールですが、通常のスケールですと金沢市とそれ以外という具合になってしまいますので、対数スケールに変換しています。

data2 |>
  dplyr::left_join(pop_data, by = "name") |>
ggplot() +
  geom_sf(aes(fill = population)) +
  geom_sf_text(aes(label = name), size = 2.5, family = jp_font) +
  scale_x_continuous(breaks = seq(136.5, 137.5, 0.5)) +
  scale_fill_gradient(name = "人口",
                      low = "skyblue",
                      high = "red",
                      transform = "log",
                      limits = c(5e+3, 5e+5),
                      breaks = c(5e+3, 1e+4, 5e+4, 1e+5, 5e+5),
                      labels = c("5000", "1万", "5万",
                                 "10万", "50万")) +
  labs(x = NULL, y = NULL) +
  theme_bw(base_family = jp_font)