Rで地図描き(簡易版)
2026-06-27
再現可能で,使い回せて,そのまま論文に使えるレベルの地図を,無料で描こう。
描画に優れたRを活用し,こんな感じの地図を自在に作れるようになるのが,本ページの目標です。
https://scrapbox.io/files/6a38a76f2ba3627f4ec6c18e.png
本ページが想定するのはRの取り扱いにある程度は慣れているくらいの初心者が日本の河川で行われる調査地点図を作成することです。
Rで地図を描く方法を解説する記事はたくさんありますが,この記事では,拡大しても海岸線等が過度に単純化されないデータを用いること,河川データの取り扱い方法を示すこと,論文でよく見るレベルの地図の作成に絞ることに留意しています。
とりあえず地図を描いてみるだけなら読み飛ばしても構わないところは
この形式
になっています。
間違いや改善点,要望などあれば大貫までご連絡ください。
0. 地図データの準備
まずは以下をダウンロードしてください。
これらは3つのrdsファイル(R Data File)です。Rにインポートして,日本国内の地図を描くのに使います。
ポリゴンは色と太さをもつ枠で囲ってあって中が塗りつぶされるオブジェクト,ラインは色と太さをもつ線のみのオブジェクト,くらいに理解しておけば大丈夫です。
いずれもオープンデータと公開データベースを基に,可視化および作図の利便性を目的として大貫が加工したものです。
ダウンロードしたらRのワーキングディレクトリ(か保存用のディレクトリ)に置いてください。
prefs.rds,rivers.rds:
国土交通省「国土数値情報(行政区域データ:N03,2024年版)」および「国土数値情報(河川データ:W05)」を加工。国土数値情報は国土数値情報利用規約(CC BY 4.0 互換)に準拠しています。本データを利用・再配布する際は上記出典を必ず明記してください。
lakes.rds:
Global HydroLab「HydroLAKES database v1.0 (Messager et al., 2016)」を加工。HydroLAKESは学術・研究目的での利用が認められています。論文等で本データを使用する際は原著論文(Messager et al., 2016)の引用を推奨します。
Messager, M. L., Lehner, B., Grill, G., Nedeva, I., & Schmitt, O. (2016). Estimating the volume and age of water stored in global lakes using a geo-statistical approach. Nature communications, 7(1), 13603. https://doi.org/10.1038/ncomms13603 データの仕様は以下の通りです。R環境(readRDS())でそのまま読み込んで利用できます。
データ形式: Rオブジェクト形式(RDS形式,xz 圧縮済)
座標参照系(CRS): 地理座標系(JGD2011 / EPSG:6668)※国土数値情報の標準仕様に準拠
加工の詳細は本ページ末尾 Appendixのbuild_basemap.Rを参照してください。
本ページで活用しているもの以外にもさまざまな公開地図データがあります。解像度は低いけれど,日本だけでなく東アジア全体あるいは全球的な地図の表示に適したデータもあります。人口等の統計データ,標高・水深等の地形データが含まれるものもあります。Rでの地図描きに慣れてきたら,お気に入りの地図データを探して,あるいは自分で加工・作成して,描画してみてください。
0. R packageの準備
次にRを開きます。必要なR packageをインストール・読み込みしておきます。
code: R
install.packages(tidyverse) # データ加工・可視化
install.packages(sf) # 空間データの操作・描画
install.packages(sfheaders) # ポリゴン形状の簡略化・穴埋め
install.packages(ggspatial) # スケールバー・北矢印の追加
install.packages(ggrepel) # 地名ラベルの重なりを自動回避
library(tidyverse)
library(sf)
library(sfheaders)
library(ggspatial)
library(ggrepel)
R(とRstudioかPositron)のインストールがまだの方はそちらを先にしてください。公式の方法に従うのがよいですが,まったく不慣れだと難しい可能性もあります。大貫の知る限り,矢内さんのページにある解説資料が最も懇切丁寧に和文でインストール方法を説明しています。 1. 地図データの読み込みと簡単な描画
先ほどダウンロードしたrdsファイルを読み込みます。riversが少し重たいはずです。
code: R
prefs <- readRDS("YOUR/PATH/TO/prefs.rds")
rivers <- readRDS("YOUR/PATH/TO/rivers.rds")
lakes <- readRDS("YOUR/PATH/TO/lakes.rds")
YOUR/PATH/TO/の意味や読み込み方法がわからない場合は,コードとエラーをコピペして「これらのrdsファイルをRに読み込みたいんだけどどうしたらいいの」などとAIに聞いてください。
読み込んだデータを確認します。
code: R
head(prefs)
code: console
Simple feature collection with 6 features and 1 field
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: 139.1648 ymin: 36.79133 xmax: 148.8928 ymax: 45.55563
Geodetic CRS: JGD2011
N03_001 geom
1 北海道 MULTIPOLYGON (((139.4995 42...
2 宮城県 MULTIPOLYGON (((141.6251 38...
3 山形県 MULTIPOLYGON (((140.5471 38...
4 岩手県 MULTIPOLYGON (((141.9789 39...
5 福島県 MULTIPOLYGON (((141.0227 37...
6 秋田県 MULTIPOLYGON (((139.9684 40...
code: R
head(rivers)
code: console
Simple feature collection with 6 features and 5 fields
Geometry type: LINESTRING
Dimension: XY
Bounding box: xmin: 134.4329 ymin: 33.78832 xmax: 134.5591 ymax: 34.04588
Geodetic CRS: JGD2011
# A tibble: 6 × 6
W05_001 W05_002 W05_003 W05_004 geometry N03_001
<chr> <chr> <chr> <chr> <LINESTRING °> <chr> 1 360007 3600070000 0 名称不明 (134.5591 33.96548, 134.559 33.9656… 徳島県
2 880807 8808070000 0 名称不明 (134.4592 34.01741, 134.4592 34.017… 徳島県
3 880807 8808070000 0 名称不明 (134.4351 34.03207, 134.4352 34.032… 徳島県
4 880807 8808070000 0 名称不明 (134.4329 34.0361, 134.433 34.03628… 徳島県
5 360007 3600070000 0 名称不明 (134.5016 33.97083, 134.5018 33.971… 徳島県
6 880806 8808060000 0 名称不明 (134.4349 33.79021, 134.435 33.7901… 徳島県
code: R
head(lakes)
code: console
Simple feature collection with 6 features and 3 fields
Geometry type: POLYGON
Dimension: XY
Bounding box: xmin: 135.861 ymin: 34.98012 xmax: 144.572 ymax: 44.37376
Geodetic CRS: JGD2011
# A tibble: 6 × 4
Hylak_id Lake_name Lake_area geometry
<int> <chr> <dbl> <POLYGON °> 1 1346 Inawashiro ko 103. ((140.088 37.5331, 140.08…
2 1361 Kasumigaura 168. ((140.3101 36.16177, 140.…
3 1381 Biwa 673. ((136.1664 35.51434, 136.…
4 14298 Shumarinaiko 20.7 ((142.1882 44.37376, 142.…
5 14315 NA 32.1 ((144.208 44.00791, 144.2…
6 14336 NA 18.7 ((144.5582 43.60513, 144.…
どのデータもSimple feature collectionであることがわかります。Simple featureというのは現実世界の地物(地表に存在するあらゆる自然物・人工物)をコンピュータ上で表現するための国際規格です。
試しにprefsだけ描画してみます。
code: R
ggplot() +
geom_sf(data = prefs, fill = "gray", color = "black", linewidth = 0.1) +
theme_bw()
こんなものができるはずです。
https://scrapbox.io/files/6a38a77b2ba3627f4ec6c1a9.png
Rで地図を描く場合,拡張性から考えて,グラフなどを重ね書きで自在に描画できるggplot2のエコシステムを活用するのが一番だと思います。記法がちょっと特殊ですが,ggplot()でパネルを用意し,+でオブジェクトや設定を書き連ねていきます。ここではgeom_sf()でsimple featureであるprefsを描画させています。theme_bw()はggplot2でのグラフ描画の一番素朴なおまかせ設定だと思っていてください。fillは塗りつぶしの色,colorは枠線の色,linewidthは枠線の幅です。これらは必要に応じて色々と変更できます。ググるなどして試してみてください。
ちなみに,都道府県の境目がいらない場合は以下のようにします。
code: R
ggplot() +
geom_sf(data = prefs |> st_union() |> sf_remove_holes(), fill = "gray", color = "black", linewidth = 0.1) +
theme_bw()
https://scrapbox.io/files/6a38a77e2ba3627f4ec6c1b2.png
|>はRにおけるパイプと呼ばれる記法です。前の関数の処理結果を次の関数にそのまま渡すのに使います。つまり,A |> B() |> C()はC(B(A))と同一です。あるオブジェクトを複数の関数で処理したいときに便利です。いまはsf_remove_holes(st_union(prefs))を実行し,それをgeom_sf()のdataとしてインプットしています。st_union()とsf_remove_holes()が具体的に何をしているのか気になるかもしれませんが,その説明はこのページの範疇を超えます。AIに聞くか,調べてみてください。うまくポリゴンを融合させるおまじないだと思っておけばとりあえずOKです。
2. 注目するところを拡大する
日本全体の高解像度な図が欲しいケースはおそらく少数派で,多くの場合は注目する地域の拡大図が必要でしょう。本ページのデータはそのような要求に耐えるよう,解像度高めに作ってあります。
例として,琵琶湖の周りだけ拡大してみます。coord_sf(xlim=c(xmin, xmax), ylim=c(ymin, ymax))として,描画される範囲を限定します。x,yは経度,緯度です。
code: R
# 都道府県の境目あり
ggplot() +
geom_sf(data = prefs, fill = "gray", color = "black", linewidth = 0.1) +
coord_sf(xlim = c(135, 136.8), ylim = c(34.1, 36.1))+
theme_bw()
# 都道府県の境目なし
ggplot() +
geom_sf(data = prefs |> st_union() |> sf_remove_holes(), fill = "gray", color = "black", linewidth = 0.1) +
coord_sf(xlim = c(135, 136.8), ylim = c(34.1, 36.1))+
theme_bw()
https://scrapbox.io/files/6a38a7822ba3627f4ec6c1bd.pnghttps://scrapbox.io/files/6a38a7852ba3627f4ec6c1c6.png
3. 湖沼を描画する
琵琶湖がないと違和感がすごいので,geom_sf(data = lakes)を使って琵琶湖も入れてみます。
code: R
# 都道府県の境目あり
ggplot() +
geom_sf(data = prefs, fill = "gray", color = "black", linewidth = 0.1) +
geom_sf(data = lakes |> filter(Lake_name == "Biwa"), color = NA, fill = "white")+
coord_sf(xlim = c(135, 136.8), ylim = c(34.1, 36.1))+
theme_bw()
# 都道府県の境目なし
ggplot() +
geom_sf(data = prefs |> st_union() |> sf_remove_holes(), fill = "gray", color = "black", linewidth = 0.1) +
geom_sf(data = lakes |> filter(Lake_name == "Biwa"), color = NA, fill = "white")+
coord_sf(xlim = c(135, 136.8), ylim = c(34.1, 36.1))+
theme_bw()
以下のようになるはずです。
https://scrapbox.io/files/6a38a7892ba3627f4ec6c1cc.pnghttps://scrapbox.io/files/6a38a78d2ba3627f4ec6c1da.png
1. でみたように,lakes内のLake_nameには湖の名称が入っています。この情報からfilter()を使って描画するポリゴンを絞り込んでいます。geom_sf(data = lakes)のcolor = NAは枠線なしということです。確かに琵琶湖に枠線はついていません。
ひとつ注意です。ggplotは最初のコードから順番に描画します。今回は陸地の上に湖沼を描画してほしいので,まず陸地(prefs)を描画してから湖沼(lakes)を描画するように注意します。
逆にすると先に湖沼が描画された上から陸地が描画されてしまうので,湖沼が見えなくなります。
code: R
# 悪い例
# 都道府県の境目あり
ggplot() +
geom_sf(data = lakes |> filter(Lake_name == "Biwa"), color = NA, fill = "white")+
geom_sf(data = prefs, fill = "gray", color = "black", linewidth = 0.1) +
coord_sf(xlim = c(135, 136.8), ylim = c(34.1, 36.1))+
theme_bw()
https://scrapbox.io/files/6a38a7822ba3627f4ec6c1bd.png
4. 河川を描画する
淡水生物を対象とした研究だと,しばしば地図に河川が欲しくなります。河川はriversを用いて描画できます。
ただし,riversには非常に多くの河川が包含されているので,普通にプロットすると膨大な時間がかかります。必要な河川だけに絞って描画するのが大切です。
琵琶湖は淀川水系ですから,ここでは淀川を描画して海と琵琶湖を繋げてみます。1. でみたように,riversのW05_004には河川名が入っています。これを使って絞り込みます。
code: R
# 都道府県の境目あり
ggplot() +
geom_sf(data = prefs, fill = "gray", color = "black", linewidth = 0.1) +
geom_sf(data = lakes |> filter(Lake_name == "Biwa"), color = NA, fill = "white")+
geom_sf(data = rivers |> filter(W05_004 == "淀川"), color = "white", fill = NA, linewidth = 0.8)+
coord_sf(xlim = c(135, 136.8), ylim = c(34.1, 36.1))+
theme_bw()
https://scrapbox.io/files/6a38a78c2ba3627f4ec6c1d5.png
琵琶湖と海が繋がらないのは,riversの中で滋賀と京都を流れる部分は「淀川」ではないからです。繋げるために「瀬田川」と「宇治川」を追加します。
W05_004 == "瀬田川" | W05_004 == "宇治川" | W05_004 == "淀川" のように「または」で連結してもいいのですが,コードの可読性を上げるためW05_004 %in% c("瀬田川", "宇治川", "淀川")とします。
code: R
# 都道府県の境目あり
ggplot() +
geom_sf(data = prefs, fill = "gray", color = "black", linewidth = 0.1) +
geom_sf(data = lakes |> filter(Lake_name == "Biwa"), color = NA, fill = "white")+
geom_sf(data = rivers |> filter(W05_004 %in% c("瀬田川", "宇治川", "淀川")), color = "white", fill = NA, linewidth = 0.8)+
coord_sf(xlim = c(135, 136.8), ylim = c(34.1, 36.1))+
theme_bw()
https://scrapbox.io/files/6a38a7912ba3627f4ec6c1e2.png
これで琵琶湖と海がつながりました。
しかし,よく見ると福井と兵庫に余計な河川が描画されています。これが何か,確認してみます。1. でみたように,riversにはN03_001に都道府県の情報が入っています。絞り込んだ河川データに何県の河川が含まれているのか,一覧にしてみます。
code: R
rivers |>
filter(W05_004 %in% c("瀬田川", "宇治川", "淀川")) |>
st_drop_geometry() |>
distinct(W05_004, N03_001) |>
arrange(W05_004, N03_001)
code: console
# A tibble: 18 × 2
W05_004 N03_001
<chr> <chr>
1 宇治川 京都府
2 宇治川 兵庫県
3 宇治川 大阪府
4 宇治川 島根県
5 宇治川 高知県
6 淀川 兵庫県
7 淀川 大阪府
8 淀川 宮城県
9 淀川 山形県
10 淀川 岡山県
11 淀川 福井県
12 淀川 秋田県
13 淀川 鹿児島県
14 瀬田川 京都府
15 瀬田川 和歌山県
16 瀬田川 山口県
17 瀬田川 愛媛県
18 瀬田川 滋賀県
同じ名前の川がいろんな都道府県にあり,福井県と兵庫県の「淀川」,兵庫県の「宇治川」が含まれてしまっているらしいことがわかります。実際,川の名前を調べる地図で河川の名前を検索してみると,地図で表示されているのは福井県の淀川と兵庫県の宇治川です。 今ほしいのは滋賀県の瀬田川,京都府の宇治川,大阪府の淀川だけです。したがって,こうしてみます。
code: R
yodo_river <- rivers |>
filter(W05_004 %in% c("瀬田川", "宇治川", "淀川")) |>
filter(N03_001 %in% c("滋賀県", "京都府", "大阪府"))
# 都道府県の境目あり
ggplot() +
geom_sf(data = prefs, fill = "gray", color = "black", linewidth = 0.1) +
geom_sf(data = lakes |> filter(Lake_name == "Biwa"), color = NA, fill = "white")+
geom_sf(data = yodo_river, color = "white", fill = NA, linewidth = 0.8)+
coord_sf(xlim = c(135, 136.8), ylim = c(34.1, 36.1))+
theme_bw()
# 都道府県の境目なし
ggplot() +
geom_sf(data = prefs |> st_union() |> sf_remove_holes(), fill = "gray", color = "black", linewidth = 0.1) +
geom_sf(data = lakes |> filter(Lake_name == "Biwa"), color = NA, fill = "white")+
geom_sf(data = yodo_river, color = "white", fill = NA, linewidth = 0.8)+
coord_sf(xlim = c(135, 136.8), ylim = c(34.1, 36.1))+
theme_bw()
https://scrapbox.io/files/6a38a7962ba3627f4ec6c1eb.pnghttps://scrapbox.io/files/6a38a7952ba3627f4ec6c1e8.png
riversの中で条件を満たすものだけをyodo_riverオブジェクトに格納し,これをgeom_sf()で配置しました。これで不要な河川は消えたようです。このように必要な河川だけをうまく絞り込む必要があります。
5. スケールバーと北矢印を描画する
緯度経度があれば距離・方位の情報は含まれていますが,論文の場合,その地域に不慣れな読者もいるでしょうから,これらの情報はあった方がよいです。Rなら情報の追加はとても簡単に済みます。
code: R
# 都道府県の境目あり
ggplot() +
geom_sf(data = prefs, fill = "gray", color = "black", linewidth = 0.1) +
geom_sf(data = lakes |> filter(Lake_name == "Biwa"), color = NA, fill = "white")+
geom_sf(data = yodo_river, color = "white", fill = NA, linewidth = 0.8)+
coord_sf(xlim = c(135, 136.8), ylim = c(34.1, 36.1))+
annotation_scale(location = "tl", pad_y = unit(1.8, "cm"))+
annotation_north_arrow(location = "tl", style = north_arrow_fancy_orienteering())+
theme_bw()
# 都道府県の境目なし
ggplot() +
geom_sf(data = prefs |> st_union() |> sf_remove_holes(), fill = "gray", color = "black", linewidth = 0.1) +
geom_sf(data = lakes |> filter(Lake_name == "Biwa"), color = NA, fill = "white")+
geom_sf(data = yodo_river, color = "white", fill = NA, linewidth = 0.8)+
coord_sf(xlim = c(135, 136.8), ylim = c(34.1, 36.1))+
annotation_scale(location = "tl", pad_y = unit(1.8, "cm"))+
annotation_north_arrow(location = "tl", style = north_arrow_fancy_orienteering())+
theme_bw()
https://scrapbox.io/files/6a38a79b2ba3627f4ec6c1f6.pnghttps://scrapbox.io/files/6a38a79a2ba3627f4ec6c1f3.png
annotation_scale()がスケールバーを,annotation_north_arrow()が北矢印を描画します。location = "tl"はパネルの左上(top left)を基準に配置せよという指示です(同様にして右下 bottom right "br"などの指定も可能です)。スケールバーと北矢印の位置が被るのを避けるため,annotation_scale()の方ではpad_y = unit(1.8, "cm")として,y軸方向に少し余白を設けています(padding)。annotation_north_arrow()のstyle = north_arrow_fancy_orienteering()は北矢印を適度なスタイルにしてくれます。
この方法は一例です。他の方法もあるでしょうし,この方法でもっと細かく調整することも可能です。AIに聞いたり調べたりして色々試してみてください。なお,ある程度広範囲の地図(たとえば本州全体より広域)の場合,地図の表示方法によってスケールバーとのズレが大きくなるので,緯度経度があれば十分なこともあります。
6. 採集地点を描画する
論文の地図ではよく採集地点を示します。
例として,琵琶湖に注ぐ和邇川の河口付近(35.156390807343556, 135.93637590609583)と淀川の城北ワンド(34.73179318698498, 135.5378193714233)で何かを採集したことにし,この地点を地図に追加します。
code: R
# 地点データ
sites <- data.frame(
Locality = c("Wani River", "Shirokita Wando"),
lat = c(35.156390807343556, 34.73179318698498),
lon = c(135.93637590609583, 135.5378193714233)
) |>
st_as_sf(coords = c("lon", "lat"), crs = 6668)
# 都道府県の境目あり
ggplot() +
geom_sf(data = prefs, fill = "gray", color = "black", linewidth = 0.1) +
geom_sf(data = lakes |> filter(Lake_name == "Biwa"), color = NA, fill = "white")+
geom_sf(data = yodo_river, color = "white", fill = NA, linewidth = 0.8)+
geom_sf(data = sites, shape = 21, size = 2, stroke = 0.5, color = "black", fill = "firebrick")+
geom_text_repel(data = sites, aes(label = Locality, geometry = geometry), stat = "sf_coordinates", size = 3)+
coord_sf(xlim = c(135, 136.8), ylim = c(34.1, 36.1))+
annotation_scale(location = "tl", pad_y = unit(1.8, "cm"))+
annotation_north_arrow(location = "tl", style = north_arrow_fancy_orienteering())+
theme_bw()+
theme(axis.title = element_blank())
# 都道府県の境目なし
ggplot() +
geom_sf(data = prefs |> st_union() |> sf_remove_holes(), fill = "gray", color = "black", linewidth = 0.1) +
geom_sf(data = lakes |> filter(Lake_name == "Biwa"), color = NA, fill = "white")+
geom_sf(data = yodo_river, color = "white", fill = NA, linewidth = 0.8)+
geom_sf(data = sites, shape = 21, size = 2, stroke = 0.5, color = "black", fill = "firebrick")+
geom_text_repel(data = sites, aes(label = Locality, geometry = geometry), stat = "sf_coordinates", size = 3)+
coord_sf(xlim = c(135, 136.8), ylim = c(34.1, 36.1))+
annotation_scale(location = "tl", pad_y = unit(1.8, "cm"))+
annotation_north_arrow(location = "tl", style = north_arrow_fancy_orienteering())+
theme_bw()+
theme(axis.title = element_blank())
https://scrapbox.io/files/6a38a76f2ba3627f4ec6c18e.pnghttps://scrapbox.io/files/6a38a7a22ba3627f4ec6c200.png
地点データをsitesオブジェクトに格納し,geom_sf()で表示しています。sitesを作るのに使っているst_as_sf()は,data frameをsimple featureに変換してgeom_sf()を使えるようにするためのコマンドです。sitesがどんなものか一応チェックしておきます。
code: R
head(sites)
code: console
Simple feature collection with 2 features and 1 field
Geometry type: POINT
Dimension: XY
Bounding box: xmin: 135.5378 ymin: 34.73179 xmax: 135.9364 ymax: 35.15639
Geodetic CRS: JGD2011
Locality geometry
1 Wani River POINT (135.9364 35.15639)
2 Shirokita Wando POINT (135.5378 34.73179)
geom_sf()では,採集地点を表す点について,枠線の太さと色,塗りつぶしの色,サイズを指定しています。ここは自由に変えてください。geom_text_repel()ではsitesに入れておいた地名の情報を地図中にプロットさせています。地名ラベルがなるべく重ならないよう,自動調整してくれます。コード末尾にtheme(axis.title = element_blank())を加えていることに注意してください。geom_text_repel()は本来グラフ中に文字を配置するものなので,これを使うとggplotが地図を散布図等と誤認してx, yと軸ラベルをつけてしまいます。theme(axis.title = element_blank())はこれを表示させないようにするコマンドです。どういうことかわからなければ,上記コマンドをtheme_bw()までにして実行し,結果を見比べてみてください。
これで地図は概ね完成です。
なお,このコードを実行すると,以下の警告が出ます。これは無視して構いません。
code: console
警告メッセージ:
st_point_on_surface.sfc(sf::st_zm(x)) で:
st_point_on_surface may not give correct results for longitude/latitude data
これもgeom_text_repel()が関係しています。geom_sf()が扱うsimple featureは球面の座標系で定義されています。ところが,geom_text_repel()が設置する文字列の位置は球面ではなく平面の座標系で定義されます。座標系が異なるので「文字列が正しい座標に表示されないかもしれないよ」と警告が出ます。ただ,今回ぐらい拡大している球面であれば,特に問題にはなりません。
どうしてもエラーが気持ち悪ければ,無理に文字を入力する必要はありません。PDFやSVGなどの編集可能な形で出力し,IllustratorやAffinityやInkscapeといった編集ソフトで文字を入力してしまえばいいのです。最後に出力方法を見ておきます。
7. 地図を出力する
地図ができたらファイルとして出力します。色々な出力形式がありますが,PDFやSVGにしておくと,編集ソフトでの追加編集がしやすいと思います。これ以上の変更が不要なら,PNG,JPEG,TIFFでも保存できます。
code: R
# 都道府県の境目あり
map1 <- ggplot() +
geom_sf(data = prefs, fill = "gray", color = "black", linewidth = 0.1) +
geom_sf(data = lakes |> filter(Lake_name == "Biwa"), color = NA, fill = "white")+
geom_sf(data = yodo_river, color = "white", fill = NA, linewidth = 0.8)+
geom_sf(data = sites, shape = 21, size = 2, stroke = 0.5, color = "black", fill = "firebrick")+
geom_text_repel(data = sites, aes(label = Locality, geometry = geometry), stat = "sf_coordinates", size = 3)+
coord_sf(xlim = c(135, 136.8), ylim = c(34.1, 36.1))+
annotation_scale(location = "tl", pad_y = unit(1.8, "cm"))+
annotation_north_arrow(location = "tl", style = north_arrow_fancy_orienteering())+
theme_bw()+
theme(axis.title = element_blank())
# 都道府県の境目なし
map2 <- ggplot() +
geom_sf(data = prefs |> st_union() |> sf_remove_holes(), fill = "gray", color = "black", linewidth = 0.1) +
geom_sf(data = lakes |> filter(Lake_name == "Biwa"), color = NA, fill = "white")+
geom_sf(data = yodo_river, color = "white", fill = NA, linewidth = 0.8)+
geom_sf(data = sites, shape = 21, size = 2, stroke = 0.5, color = "black", fill = "firebrick")+
geom_text_repel(data = sites, aes(label = Locality, geometry = geometry), stat = "sf_coordinates", size = 3)+
coord_sf(xlim = c(135, 136.8), ylim = c(34.1, 36.1))+
annotation_scale(location = "tl", pad_y = unit(1.8, "cm"))+
annotation_north_arrow(location = "tl", style = north_arrow_fancy_orienteering())+
theme_bw()+
theme(axis.title = element_blank())
# PDFで保存する場合
# 都道府県の境目あり
ggsave(
"YOUR/PATH/TO/map1.pdf",
map1,
width = 75,
height = 100,
units = "mm",
device = cairo_pdf,
dpi = 300
)
# 都道府県の境目なし
ggsave(
"YOUR/PATH/TO/map2.pdf",
map2,
width = 75,
height = 100,
units = "mm",
device = cairo_pdf,
dpi = 300
)
# PNGで保存する場合
# 都道府県の境目あり
ggsave(
"YOUR/PATH/TO/map1.png",
map1,
width = 75,
height = 100,
units = "mm",
dpi = 300
)
# 都道府県の境目なし
ggsave(
"YOUR/PATH/TO/map2.png",
map2,
width = 75,
height = 100,
units = "mm",
dpi = 300
)
widthは横幅,heightは高さ,unitsはそれらの長さの単位,dpiは画質を指定します。2段組論文で1段に収めようとするなら,大体75 mmの横幅で作っておくといいかなと思います。2段とも使ってキャプションを横置きするなら120 mm,キャプションを下に入れるなら150 mmの横幅でOKです。dpiは300–600くらいあれば十分なことが多いです。
このページの目標はこれで達成です。
日本の河川で行われる生物調査の論文の図としてあと必要なのは,日本列島を含む東アジアの地図でしょうか。これはこのページのデータでは描画できません(最初のprefsの描画で見たように,このデータには日本列島しか含まれていないからです)。需要があれば別ページに解説を作りたいと思います。
以下は付録です。
Appendix 1. RDSファイル作成に用いたコード
本ページの元になっているrdsファイル作成に使ったコードを置いておきます。AIに読ませたら何しているか説明してくれると思います。
code: build_basemap.R
# build_basemap.R
library(sf)
library(sfheaders)
library(tidyverse)
library(rmapshaper)
# --- 行政区域(N03)---
# フォルダ内のshpを一括読み込み
n03_files <- list.files("PATH/TO/国土数値情報/2024",
pattern = "N03-.*\\.shp$",
admin_list <- lapply(n03_files, function(f) {
message("Processing: ", f)
x <- read_sf(f) |>
select(N03_001, geometry) |>
st_make_valid()
# 市区町村 → 県にまとめる
pref <- x |>
group_by(N03_001) |>
summarise()
# 県ポリゴンだけを簡略化
pref_slim <- ms_simplify(pref, keep = 0.01)
return(pref_slim)
})
admin_pref <- bind_rows(admin_list)
saveRDS(admin_pref, "PATH/TO/prefs.rds", compress = "xz")
# --- 河川(W05)---
w05_files <- list.files("PATH/TO/国土数値情報/00_rivers",
pattern = "W05.*Stream\\.shp$",
recursive = TRUE, full.names = TRUE)
river_all <- lapply(w05_files, \(f) {
read_sf(f, crs = "+proj=longlat +datum=WGS84") |>
select(W05_001, W05_002, W05_003, W05_004)
# W05_001: 水系コード, W05_002: 河川コード, W05_003: 水系名, W05_004: 河川名
}) |>
bind_rows() |>
st_make_valid()
# CRS揃える
river_all <- st_transform(river_all, st_crs(admin_pref))
# 空間結合
rivers <- st_join(river_all, admin_pref"N03_001") saveRDS(rivers, "~/Dropbox/Research/basemap_japan/rivers.rds", compress = "xz")
rm(river_all); gc()
# --- 湖沼(HydroLAKES)---
lake <- read_sf("PATH/TO/HydroLAKES_polys_v10.shp") |>
filter(Country == "Japan") |>
select(Hylak_id, Lake_name, Lake_area) |>
st_transform(6668) |>
ms_simplify(keep = 0.3, keep_shapes = TRUE)
saveRDS(lake, "~/Dropbox/Research/basemap_japan/lakes.rds", compress = "xz")
rm(lake); gc()
Appendix 2. 描画したい河川を探すためのtips
河川の絞り込みは厄介な問題です。都道府県で河川が絞りこめるなら楽なのですが,同じ都道府県に同名の川があったりすることもたまにあります。そういう時は,riversのW05_001に入っている「水系域コード」を使って河川を絞り込む方法もあります。水系域コードには水系に対して一意に決まる値が定められており,同一水系内に同名の川がなければ(大体の場合はないです),河川を特定する絞り込みが可能です。ただ,目的の河川の水系域コードを調べるのが面倒です。以下の関数を作っておくと,この作業がほんのちょっとだけ楽になったりします。水系域コードを調べ,絞り込みのためのコードを取得する関数です。 code: R
river_index <- rivers |>
st_drop_geometry() |>
distinct(W05_001, W05_004, N03_001) |>
arrange(W05_004)
pick_river <- function(keyword, pref = NULL) {
library(stringr)
pattern <- paste(keyword, collapse = "|")
cand <- river_index |>
filter(str_detect(W05_004, pattern))
if (!is.null(pref)) {
cand <- cand |> filter(N03_001 == pref)
}
cand <- cand |>
distinct(W05_004, W05_001, N03_001) |>
mutate(id = row_number())
for (i in seq_len(nrow(cand))) {
cat(sprintf("%d %s | %s | %s\n", }
input <- readline("Select row number(s): ")
ids <- as.integer(unlist(strsplit(input, ",")))
sel <- cand |> filter(id %in% ids)
# 再現コードを出力
code <- sprintf(
'rivers |> filter(W05_001 %%in%% c(%s), W05_004 %%in%% c(%s))',
paste0('"', unique(sel$W05_001), '"', collapse = ", "),
paste0('"', unique(sel$W05_004), '"', collapse = ", ")
)
cat("\n--- Reproducible code ---\n")
cat(code, "\n")
cat("-------------------------\n\n")
# 実データも返す
rivers |>
filter(W05_004 %in% sel$W05_004,
W05_001 %in% sel$W05_001)
}
例として大阪の淀川の水系域コードを調べ,絞り込みのためのコードを取得してみます。上記のコードを実行した後に,次のコードを実行してください。
code: R
pick_river("淀川")
すると以下が出ます。
code: console
6 旧淀川(堂島川) | 860604 | 大阪府 8 旧淀川(安治川) | 860604 | 大阪府 Select row number(s):
ほしいのは大阪の淀川なので,consoleに15と打って実行します。
code: console
Select row number(s): 15
--- Reproducible code ---
rivers |> filter(W05_001 %in% c("860604"), W05_004 %in% c("淀川"))
-------------------------
Simple feature collection with 23 features and 5 fields
Geometry type: LINESTRING
Dimension: XY
Bounding box: xmin: 135.4202 ymin: 34.68301 xmax: 135.6827 ymax: 34.88786
Geodetic CRS: JGD2011
# A tibble: 23 × 6
W05_001 W05_002 W05_003 W05_004 geometry N03_001
* <chr> <chr> <chr> <chr> <LINESTRING °> <chr> 1 860604 8606040001 1 淀川 (135.4352 34.68763, … 大阪府
2 860604 8606040001 1 淀川 (135.4618 34.69932, … 大阪府
3 860604 8606040001 1 淀川 (135.5137 34.72297, … 大阪府
4 860604 8606040001 1 淀川 (135.619 34.80708, 1… 大阪府
5 860604 8606040001 1 淀川 (135.6124 34.79243, … 大阪府
6 860604 8606040001 1 淀川 (135.6097 34.78832, … 大阪府
7 860604 8606040001 1 淀川 (135.6451 34.83025, … 大阪府
8 860604 8606040001 1 淀川 (135.6451 34.83, 135… 大阪府
9 860604 8606040001 1 淀川 (135.6443 34.8285, 1… 大阪府
10 860604 8606040001 1 淀川 (135.6416 34.82173, … 大阪府
# ℹ 13 more rows
# ℹ Use print(n = ...) to see more rows
Reproducible codeに出てくるrivers |> filter(W05_001 %in% c("860604"), W05_004 %in% c("淀川"))が重要です。これをYDOオブジェクトとしておいて,描画します。
code: R
YDO <- rivers |> filter(W05_001 %in% c("860604"), W05_004 %in% c("淀川"))
ggplot() +
geom_sf(data = prefs, fill = "gray", color = "black", linewidth = 0.1) +
geom_sf(data = lakes |> filter(Lake_name == "Biwa"), color = NA, fill = "white")+
geom_sf(data = YDO, color = "white", fill = NA, linewidth = 0.8)+
coord_sf(xlim = c(135, 136.8), ylim = c(34.1, 36.1))+
theme_bw()
https://scrapbox.io/files/6a38a7aa2ba3627f4ec6c217.png
こうすれば,ほしい淀川を特定して描画することが可能です。京都の宇治川と滋賀の瀬田川もあわせて描画するならこうします。いずれも淀川水系ですから,水系域コードは淀川と同一です。pick_riverで調べ直す必要はありません。
code: R
yodo_river <- rivers |> filter(W05_001 %in% c("860604"), W05_004 %in% c("瀬田川", "宇治川", "淀川"))
ggplot() +
geom_sf(data = prefs, fill = "gray", color = "black", linewidth = 0.1) +
geom_sf(data = lakes |> filter(Lake_name == "Biwa"), color = NA, fill = "white")+
geom_sf(data = yodo_river, color = "white", fill = NA, linewidth = 0.8)+
coord_sf(xlim = c(135, 136.8), ylim = c(34.1, 36.1))+
theme_bw()
https://scrapbox.io/files/6a38a7962ba3627f4ec6c1eb.png
河川の名前と都道府県がわかっていれば,どんな河川でも基本的にこの方法を応用して描画できます。
Appendix 3. 実行環境
大貫の簡単な実行環境を載せておきます。
code: console
R.version.string
1 "R version 4.5.2 (2025-10-31)" packageVersion("tidyverse")
packageVersion("sf")
packageVersion("sfheaders")
packageVersion("ggspatial")
packageVersion("ggrepel")
更新履歴
2026-06-27 微修正
2026-06-22 公開