最終更新:2026-03-30
rayshader
パッケージを使って日本全体の人口分布を3Dビジュアライゼーションとして表現する。stars::st_rasterize()
を使用する。ベクター形式のヘックスデータを直接ラスターグリッドに変換できる。参考コード:https://github.com/andrea-io/RayshaderPortraits/tree/main/Japan
| データ | 説明 |
|---|---|
| Kontur Population(日本) | 400m解像度の人口データ(GeoPackage形式) |
| 項目 | 仕様 |
|---|---|
| ファイル形式 | GeoPackage (.gpkg) |
| 空間解像度 | 400m(H3解像度8) |
| 座標参照システム | EPSG:3857(Pseudo-Mercator) |
| 集計基準年 | 2023年 |
| カバレッジ | 世界全域 |
kontur_population_JP_20231101.gpkg(45.8MB)をダウンロードして作業フォルダに配置する。library(sf) # ベクターデータの入出力・空間演算
library(stars) # ラスターデータの操作(st_rasterize を提供)
library(ggplot2) # データの可視化・地図描画
library(MetBrewer) # 美術館にインスパイアされたカラーパレット
library(colorspace) # 色彩ユーティリティ(swatchplot を提供)
library(rgl) # rayshader が内部で使う3Dグラフィクスバックエンド
library(rayshader) # heightmap の3Dレンダリング
# Kontur Population(日本)の GeoPackage を読み込む
JP <- sf::st_read("kontur_population_JP_20231101.gpkg", quiet = TRUE)
# データが正しく読み込まれたかを概観プロットで確認する
JP |>
ggplot2::ggplot() +
geom_sf(color = NA, fill = "steelblue", alpha = 0.4) +
labs(
title = "Kontur Population: Japan",
caption = "Source: Kontur Population 2023"
) +
theme_void()
# データ全体のバウンディングボックスを取得する
bb <- sf::st_bbox(JP)
# 地図の幅と高さをメートル単位で計測するためのコーナーポイントを作成する
bottom_left <- sf::st_point(c(bb[["xmin"]], bb[["ymin"]])) |>
sf::st_sfc(crs = sf::st_crs(JP)) # 左下コーナー
bottom_right <- sf::st_point(c(bb[["xmax"]], bb[["ymin"]])) |>
sf::st_sfc(crs = sf::st_crs(JP)) # 右下コーナー
top_left <- sf::st_point(c(bb[["xmin"]], bb[["ymax"]])) |>
sf::st_sfc(crs = sf::st_crs(JP)) # 左上コーナー
# 東西方向の距離(地図の幅)を計測する
width <- sf::st_distance(bottom_left, bottom_right)
# 南北方向の距離(地図の高さ)を計測する
height <- sf::st_distance(bottom_left, top_left)
cat("Map width :", round(as.numeric(width) / 1000, 1), "km\n")
## Map width : 3458.1 km
cat("Map height:", round(as.numeric(height) / 1000, 1), "km\n")
## Map height: 3382.3 km
# 出力画像が歪まないようにアスペクト比を計算する
# 長辺を 1 とし、短辺をそれに対する比率で表す
if (width > height) {
w_ratio <- 1
h_ratio <- height / width
} else {
h_ratio <- 1
w_ratio <- width / height
}
cat("w_ratio:", round(as.numeric(w_ratio), 4), "\n")
## w_ratio: 1
cat("h_ratio:", round(as.numeric(h_ratio), 4), "\n")
## h_ratio: 0.9781
rayshader
が扱える行列(matrix)形式にする。# 長辺のピクセル数を設定する(source.R では 5000;HTMLプレビュー用に 1200 を使用)
size <- 1200
# アスペクト比に基づいて各軸のピクセル数を計算する
nx <- floor(size * as.numeric(w_ratio)) # 列数(東西方向)
ny <- floor(size * as.numeric(h_ratio)) # 行数(南北方向)
cat("Raster size:", nx, "x", ny, "pixels\n")
## Raster size: 1200 x 1173 pixels
# stars::st_rasterize でヘックスベクターデータを規則格子ラスターに変換する
# nx / ny が解像度を決める;セル内の人口値は合計される
JP_rast <- stars::st_rasterize(JP, nx = nx, ny = ny)
# rayshader が処理できる通常の行列(matrix)に変換する
# nrow = nx:画像の列数=行列の行方向に対応する
mat <- matrix(JP_rast$population, nrow = nx, ncol = ny)
# データなし(NA)のセルを 0 に置換する
# rayshader は NA を平坦な地面として描画するために 0 が必要
mat[is.na(mat)] <- 0
cat("Matrix size:", nrow(mat), "rows x", ncol(mat), "cols\n")
## Matrix size: 1200 rows x 1173 cols
# MetBrewer の "Morgenstern" パレットを使用する(暖かみのあるピンク・紫系)
color <- MetBrewer::met.brewer(name = "Morgenstern")
# 256色に拡張し、低い値(人口が少ないエリア)の色域を広げる
# bias > 1 にすると低値側の色幅が広がり、高値のピークが際立つ
tx <- grDevices::colorRampPalette(color, bias = 1.5)(256)
# ベースパレット(8色)をスウォッチで確認する
colorspace::swatchplot(color)
rayshader
はパストレーシング(光線の経路を物理的に追跡する手法)によって高品質な画像を生成する。plot_3d()
でシーンを構築し、render_highquality()
で画像として書き出す。# ヘッドレスの rgl デバイスに3Dシーンを構築する
mat |>
rayshader::height_shade(texture = tx) |>
rayshader::plot_3d(
heightmap = mat,
zscale = 20, # 高さの強調係数(source.R の値)
solid = FALSE, # 底面(ソリッド)を非表示にしてピークのみ表示する
shadowdepth = 0, # 表面下の影の深さ
windowsize = c(nx, ny) # ウィンドウを出力解像度に合わせる
)
# カメラ位置を設定する(source.R の値をそのまま使用)
# theta:垂直軸まわりの回転角(6 = ほぼ正面)
# phi :仰角(40 = やや高い視点)
# zoom :ズーム倍率(1 未満 = ズームアウト)
rayshader::render_camera(theta = 6, phi = 40, zoom = 0.57)
# パストレーシングによる高品質レンダリングを実行する(source.R のライティング設定)
# lightdirection = 120 : 南東方向から光を当てる
# lightcolor[1] : パレットの color[4] を使った暖色系の光
# lightcolor[2] = "white": 上方からの寒色系の補助光
# samples = 100 : 出版品質にするには 450 に増やす(時間がかかる)
rayshader::render_highquality(
filename = "output/japan_population_3d.png",
interactive = FALSE,
lightdirection = 120,
lightaltitude = c(20, 80),
lightcolor = c(color[4], "white"),
lightintensity = c(900, 150),
samples = 100, # source.R の最終レンダーは 450
width = nx,
height = ny
)
# レンダリング済みの PNG を HTML ドキュメント内に埋め込む
knitr::include_graphics("output/japan_population_3d.png")
Spencer Schien (2021) “High Quality Rayshader Visuals” https://spencerschien.info/post/data_viz_how_to/high_quality_rayshader_visuals/
andrea-io (2022) “RayshaderPortraits” https://github.com/andrea-io/RayshaderPortraits
Kontur Population Data https://www.kontur.io/portfolio/population-dataset/
HDX Japan Population Data https://data.humdata.org/organization/kontur