🗺️

Makie.jlでGMTの地図を扱う

に公開

はじめに

Juliaで図を描くライブラリにはMakie.jlPlots.jlなどがあるが、図の要素を細かくカスタムできるので、筆者はMakie.jl(特にCairoMakie.jl)を使用している。地図を描画する場合は、Generic Mapping Tools(GMT)のJuliaラッパーのGMT.jlや、Makie.jlをベースにしたGeoMakie.jlなどを利用できる。GeoMakie.jlを使うと、Makie.jlで作ったFigureの中に地図を共存させられるなど、Makie.jlのエコシステム内で完結できる利点がある。しかし、GeoMakie.jlよりGMTで作った地図が好みなので、力業でMakie.jlのFigureの中にGMTで作成した地図を入れる方法を紹介する。

対象読者

  • Makie.jlで地図を扱いたい人(Plots.jlなどでも応用可能)
  • GeoMakie.jlよりGMTで作った地図が好みの人

出力の比較

まずは、東経135°、北緯35°を中心にした正距方位図法で地図を作成し、それぞれの出力を比較してみる。

GMT

gmt begin GMT png
gmt coast -JE135/35/12c -Rg -Bg -Wthinnest -Glightgray
gmt end

GeoMakie.jl

GeoMakie.jlは投影法の指定にPROJ-stringsを用いる。

using CairoMakie, GeoMakie
fig = Figure();
ax = GeoAxis(fig[1,1],
    dest="+proj=aeqd +lon_0=135 +lat_0=35",
    limits=(-180, 180, -90, 90)
)
poly!(ax, GeoMakie.land(), color=:lightgray)
lines!(ax, GeoMakie.coastlines(10), color=:black)
hidedecorations!(ax, grid=false)
save("GeoMakie.png", fig)

出力の比較

GMTとGeoMakie.jlで作成した地図を以下に示す。GMTは全球を描けているが、GeoMakie.jlでは地図の端の領域が描画されていない。また、GeoMakie.jlは上下が切れているが、これはデフォルトの動作だと思われる(余白のせいかと思い、Figure(figure_padding=)をいじってみたが変わらなさそう?)。

コードの量を比較すると、GMTの方が少ない。GMTのコマンドは慣れるまでに時間がかかるが、その分細かな設定を短いコードでできる印象がある。あと個人的に、GeoMakieを使いこなせるほど理解していない。

GMT.jl

GMT.jlはGMTのJuliaラッパーである。Makie.jlと一緒に使うと衝突する関数があり、毎回CairoMakie.scatterとかGMT.scatterとか書けば問題ないのだが、少々面倒である。他方、Juliaで扱っている最中のデータをプロットするような場合は、シェルではなくJuliaのREPL内で完結でき点で便利である[1]。出力はGMTと同じなので省略する。

GMTで作成した画像を読み込ませて解決する

関数の衝突を避けるためにGMT.jlは使用せず、GMTのシェルコマンドで画像を生成し、その画像をMakie.jlで読み込む。幸いJuliaではrun(cmd)でシェルコマンドを実行できるため、Juliaスクリプト内で完結させられる。

Juliaでの画像ファイルの読み込みはFileIO.jlでできる。Makie.jlでの扱いはimage | Makieを参照されたい。load()すると、画像が90度反時計回りに回転してしまうので、rotr90()するとよい。

using CairoMakie, FileIO

# シェルのGMTで地図を作成する
run(`gmt begin tmp png`)
run(`gmt coast -JE135/35/6c -Rg -W0.1p -Bg`)
run(`gmt end`)

# 画像を読み込む
img = load("tmp.png")

# プロットする
fig = Figure();
ax = Axis(fig[1,1], aspect=DataAspect())
image!(ax, rotr90(img))
hidedecoration!(ax) # ticksなどを隠す
hidespines!(ax) # 枠を隠す

# 他のプロット
Axis(fig[2,1])

# 表示
fig

出力を以下に示す。これで、GMTで描画した地図をMakie.jlのFigureに入れられた。

Figureの寸法によってはload()した画像がガビガビになってしまうため、GMTで出力するときの寸法を調整したり、地図をPDFで出力してPNGに変換するなどするとよい。load()でPDFを読み込むこともできるが、ベクター画像としてではなく、適当なサイズの行列として読み込まれ、PNGよりもガビガビになることがある。ベクター画像をベクター画像として読み込む方法や、解像度を指定する方法を筆者は知らないので、あれば教えていただきたいです。

さいごに

本記事では、GMTで出力した画像ファイルをFileIO.load()で読み込むことによって、Makie.jlのFigureにGMTの地図を入れる手法を紹介した。GMTの地図の綺麗さはさることながら、Makie.jlのエコシステムで地理情報を描画できるGeoMakie.jlも有用であるので、場合に応じて使い分けたい。

脚注
  1. 2025-11-15追記。open("tmp.dat", "w")してデータを書き込み、gmt plot tmp.datすれば、GMT.jlを使わずに、REPLから出ずに、大量のデータのプロットができる。 ↩︎

Discussion