y_uti のブログ

統計、機械学習、自然言語処理などに興味を持つエンジニアの技術ブログです

D3.js で日本地図を描く

D3.js と TopoJSON を使って、ブラウザ上に地図を描くことが簡単にできるようです。ウェブ上の解説記事を参考にしながら私も試してみました。作成にあたっては、主に下記ウェブページの解説を参考にしました。
D3.js と TopoJSON で地図を作る

できあがりは以下のとおりです。地図データは Natural Earth で公開されているものを利用しました。
D3.js と TopoJSON で日本地図を描く

作業の流れは次のようになります。

  1. Shape 形式の地図データを入手する
  2. GeoJSON 形式に変換する
  3. TopoJSON 形式に変換する
  4. D3.js と TopoJSON プラグインを使って TopoJSON 形式のデータをブラウザ上に描画する

私は普段 CentOS を利用しているのですが、CentOS 6.5 では、一連の作業に必要なソフトウェアは EPEL に揃っていました。ここでは、EPEL のパッケージを使って CentOSCUI 環境のみで作業する手順を説明します。

Shape 形式の地図データを入手する

まず、shape 形式の地図データを入手します。今回は、日本全図を都道府県ごとに塗り分けてみたいと思い、その用途に使えそうな地図を探しました。Natural Earth の以下のページにある "Admin 1 – States, Provinces" というデータがそれに該当するので、これを利用しました。
1:10m Cultural Vectors | Natural Earth

このデータをダウンロードして展開します。ウェブサイトにも記載があるように zip ファイルの状態で 14MB 程度の大きさがあります。なお、この zip ファイルは、ディレクトリを作らずカレントディレクトリにフラットに展開されました。

$ wget http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_1_states_provinces.zip
$ unzip ne_10m_admin_1_states_provinces.zip
GeoJSON 形式に変換する

Shape 形式のファイルを GeoJSON 形式に変換する方法は色々あるようですが、CentOS 6.5 の CUI では ogr2ogr というコマンドが使えるようです。CentOS 6.5 の公式リポジトリではパッケージが提供されていないのですが、EPEL からインストールできます。yum に EPEL リポジトリを追加して gdal パッケージをインストールします*1yum へのリポジトリの追加方法については以下のウェブページの情報を参考にしました。
CentOSにEPELリポジトリを追加する - Qiita

$ wget http://ftp-srv2.kddilabs.jp/Linux/distributions/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm
$ sudo rpm -ivh epel-release-6-8.noarch.rpm
$ sudo yum install gdal --enablerepo=epel

以下のようにして shape ファイルから GeoJSON 形式のファイルを生成できます。ogr2ogr は GeoJSON のほかにも各種形式への変換をサポートしており、-f オプションで出力形式を指定します。

$ ogr2ogr -f GeoJSON ne_10m_admin_1_states_provinces.geojson ne_10m_admin_1_states_provinces.shp

さて、今回ダウンロードしてきたデータは、日本だけではなく全世界の情報を含むものでした。日本地図を描くためには、データ全体の中から日本だけを選択的に抽出する必要があります。これは、ogr2ogr でファイル形式を変換する際に -where オプションを指定することで実現できます。

どのような条件を指定すればよいか、データの仕様を調べるのが本来の方法だとは思いますが、それも面倒なので適当に探してみることにします。

$ jq '.' ne_10m_admin_1_states_provinces.geojson | grep Japan
        "geonunit": "Japan",
        "admin": "Japan",
        "note": "JPN-99 (Japan minor island)",
        "geonunit": "Japan",
        "admin": "Japan",
        "woe_label": "Hiroshima Prefecture, JP, Japan",
        "geonunit": "Japan",
...

このように見つかりましたので、たとえば geonunit が Japan であることを条件にすれば良さそうです*2。なお、ここで利用している jqコマンドラインJSON プロセッサです。これも、CentOS 6.5 では EPEL からインストールできます。

改めて、日本のみという条件をつけて shape ファイルを GeoJSON 形式に変換します。日本だけのデータになるので、出力ファイル名も japan.geojson としました。

$ ogr2ogr -f GeoJSON -where 'geonunit = "Japan"' japan.geojson ne_10m_admin_1_states_provinces.shp

ここで、データを確認してみます。jq を使って調べてみると、features 要素に都道府県ごとのデータ (境界線の座標データとプロパティ) が格納されていて、その中の properties.name_local に都道府県名が入っているらしいことが分かります。これを出力させてみます。

$ jq '.features[].properties.name_local' japan.geojson | column
""              "福岡県"        "徳島県"        "富山県"        "滋賀県"        "東京都"        "新潟県"
"広島県"        "熊本県"        "愛知県"        "北海道"        "和歌山県"      "山梨県"        "山形県"
"岡山県"        "宮崎県"        "岐阜県"        "福井県"        "千葉県"        "秋田県"        "長崎県"
"島根県"        "愛媛県"        "石川県"        "兵庫県"        "茨城県"        "青森県"        "鹿児島県"
"鳥取県"        "香川県"        "三重県"        "京都府"        "神奈川県"      "福島県"        "沖縄県"
"山口県"        "高知県"        "長野県"        "奈良県"        "埼玉県"        "岩手県"        "群馬県"
"佐賀県"        "大分県"        ""              "大阪府"        "栃木県"        "宮城県"

全部で 48 要素あります。また、都道府県名が空になっているものが 2 要素ありました。並び順も、都道府県コード順ではなくばらばらに見えます。空になっている 2 要素のうち、先頭のものは

$ jq '.features[0].properties.note' japan.geojson | column
"JPN-99 (Japan minor island)"

とのことです。もう一方は、どうやら静岡県の name_local フィールドが欠落しているようです。

TopoJSON 形式に変換する

次に、このファイルを GeoJSON 形式から TopoJSON 形式に変換します。これは topojson というコマンドを使えばよいのですが、topojson は node.js のパッケージ管理システムである npm を使ってインストールする必要があるので、まず node.js と npm をインストールします。

$ sudo yum install nodejs npm --enablerepo=epel

私の環境では、これらのパッケージのインストール自体は正常終了したのですが、インストール直後に npm のパッケージ構成を調べてみたところ、以下のように依存関係のエラーが発生していました*3

$ npm -g list
...
npm ERR! missing: inherits@*, required by undefined@undefined
npm ERR! missing: inherits@*, required by block-stream@0.0.7
npm ERR! missing: inherits@*, required by fstream@0.1.24
npm ERR! missing: inherits@*, required by fstream-ignore@0.0.7
npm ERR! missing: inherits@*, required by fstream-npm@0.1.5
npm ERR! missing: inherits@*, required by glob@3.2.6
npm ERR! invalid: inherits@2.0.0 /usr/lib/node_modules/inherits@2
npm ERR! missing: inherits@*, required by npmconf@0.1.2
npm ERR! missing: inherits@*, required by tar@0.1.18
npm ERR! not ok code 0

私には node.js の経験がなく状況がよくわからないのですが、これに対処しようとして npm のパッケージ更新を行ったりすると、今度は node-gyp がエラーを起こすなどして泥沼でした。その一方で、topojson 自体はこのエラーをそのままにしても問題なくインストールできるようです。そこで、今回はエラーに対処せず手順を進めることにします。

$ sudo npm -g install topojson

インストールされた topojson を使ってファイル形式を変換します。

$ topojson japan.geojson >japan.topojson
D3.js と TopoJSON プラグインを使って TopoJSON 形式のデータをブラウザ上に描画する

TopoJSON ファイルを用意できたら、あとは D3.js と TopoJSON プラグインを使って、ブラウザ上に描画できます。この部分は冒頭に示したウェブページの説明のとおりに HTML ファイルや JavaScript ファイルを作成するだけなので、説明を省略します。元ページの解説や、できあがりのウェブページのソースコードを参考にしてください。

*1:gdal パッケージに ogr2ogr コマンドが含まれています。

*2:geounit ではなく geonunit です。私はこれに気付かず時間を無駄にしました。

*3:私の作業環境が汚れている可能性もあるかと思い、念のため新規に CentOS 6.5 の仮想機械を作成して OS セットアップ直後の状態にインストールしてみましたが、それでも同様でした。