2025年9月27日土曜日

ロビンソン図法

YouTubeで世界地図の話題があった。世界地図のパターンとしては,(1) 日本が中心で右が太平洋をはさんで米大陸,左が欧州アフリカ,(2) 欧州アフリカが中心で左に米大陸,右がアジア日本,(3) アメリカが中心で,左にアジアの東半分,右に欧州アフリカとアジアの右半分,とある。アメリカの小学校だと(3)らしい。日本だと(1)だ。概ねの世界標準は(2)だと。

しかしそれよりも気になるのは,メルカトル図法の歪みだ。シベリアとカナダとグリーンランドがやたらと拡大される。小学校ではこの地図を画用紙に何度も描いて社会の勉強をしていた。そこで正積図法に何かないかと調べていると,あまり聞いたことがないNell-Hammer図法がお薦めされた。

さっそくChatGPT-5に「SVG図を作って」というとHTMLファイルが返ってきた。どうもごちゃごちゃしているので描画の肝の部分がどこかを教えてもらった。すると,

A(ChatGPT-5):
このHTMLファイルで「世界地図を描画する肝」となる部分は、JavaScript内のD3.jsとTopoJSONを使った処理です。特に以下の要素がポイントです

1.投影法の指定
const projection = d3.geoNellHammer();
const path = d3.geoPath(projection);
ここで Nell–Hammer図法 を指定しています。
d3.geoPath(projection) によって、地理データをSVGパスに変換できるようになります。

2.データの読み込みと変換
const url = "https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json";
const world = await fetch(url).then(r => r.json());
const countries = topojson.feature(world, world.objects.countries);
const borders   = topojson.mesh(world, world.objects.countries, (a,b) => a !== b);
Natural Earth → world-atlas 由来のTopoJSONを読み込み。
topojson.feature で国境データをGeoJSONに変換。
topojson.mesh で隣接国間の国境線を抽出。

3.実際の描画処理
oceanLayer.append("path")
  .attr("class", "ocean")
  .attr("d", path({type:"Sphere"}));

landLayer.selectAll("path.land")
  .data(countries.features)
  .join("path")
  .attr("class", "land")
  .attr("fill", (d,i) => palette[i % palette.length])
  .attr("d", path);

borLayer.append("path")
  .attr("class", "borders")
  .attr("d", path(borders));
海(Sphere), 陸地(国ごと), 国境線 をSVGパスとして追加。
path(...) がD3によって座標を投影→SVGパス文字列に変換します。

4.レンダリング制御
function fitProjection(m) {
  projection.fitExtent([[m, m], [W - m, H - m]], { type: "Sphere" });
}
余白(marginInputで指定)を考慮して、投影範囲を A4サイズ (297×210mm) にフィットさせています。

5.まとめると:
肝は d3.geoNellHammer() 投影と d3.geoPath の組み合わせであり、
TopoJSONから取得した国データを path 関数を通してSVGに描画する部分が中核です。

ご希望なら、この「肝」だけを抜き出した最小限のサンプル(例えば海と国だけ表示するコード)を書き出しましょうか?

で,いちおうできたのだけれど,他の図法はどうなっているのだ。簡単なことで, 投影法の指定のconst projection = d3.geoNellHammer(); の所を変えればいいだけだ。メルカトル図法(d3.geoMercator()),ロビンソン図法(d3.geoRobinson()),モルワイデ図法(d3.geoMollweide()),サンソン図法(d3.geoSinuMollweide();),正距方位図法(d3.geoAzimuthalEquidistant().center([0, 90])),正射図法(d3.geoOrthographic().rotate([0, -30]))

これらを切り替えられるようなhtmlの製作を依頼したところ,この世界地図ページができた。SVGファイルもダウンロードできる。この中で一番よさげなロビンソン図法は妥協の産物で,正積でも正方位でもないけれどまあまあみやすい。


図:ロビンソン図法の場合


あれもできます,これもできますと提案してきたので,はいはいと言っているうちになんだが大層なものができてしまった。うまく表示されなかったので文句をいうとすぐに修正してくれた(できあがった世界地図はこれ,視点の緯度経度なども変更できる優れもの)。うーん,この環境でのプログラミング教育とはいったい・・・。


0 件のコメント: