Natural Earth からダウンロードした Shapefile データを使用して、D3.js で表示可能な日本地図データを作成する手順を説明する。私の実行環境はNext.js v15.3.3
だが、NuxtやVueでも動作する汎用的な内容になっている。
全部で2記事構成になっており、当記事ではデータの作成について解説し、次の記事ではd3.jsを使った地図の描画方法を解説する。最終的には、以下のような日本地図をWEB上で描画できるようになる。

GeoJSONとは何か
GeoJSONは地理空間データを表現するための軽量なデータ形式である。JSONをベースとしており、点、線、面といった地理的な図形と、それに関連する属性情報を一つのファイルで管理できる。例えば、都道府県の境界線データなら、各都道府県の形状(座標の集合)と名前や人口といった属性を組み合わせて記録する。WebブラウザでもNode.jsでも簡単に扱えるため、Web地図アプリケーションの開発で広く使われている。従来のShapefileと比べて、単一ファイルで完結し、テキスト形式なので人間が読みやすく、JavaScriptで直接操作できる点が大きな利点。特にLeafletやD3といったライブラリとの相性が良く、データの可視化や分析が簡単に行える。
手順 1: Natural Earth データのダウンロード
- Natural Earth 公式サイトから Admin 1 データをダウンロード
- URL: https://www.naturalearthdata.com/downloads/10m-cultural-vectors/
- “Admin 1 – States, Provinces” をダウンロード
- ファイル名:
ne_10m_admin_1_states_provinces.zip
- データの配置
- ダウンロードした ZIP ファイルを解凍
- 以下の 4 つのファイルを
public/natural-earth/
ディレクトリに配置:ne_10m_admin_1_states_provinces.shp
(20MB) – 地理形状データne_10m_admin_1_states_provinces.shx
(36KB) – インデックスファイルne_10m_admin_1_states_provinces.dbf
(14MB) – 属性データne_10m_admin_1_states_provinces.prj
(145B) – 投影法定義
手順 2: 必要な依存関係のインストール
npm install shapefile
Shapefile から日本の都道府県データのみを抽出し、D3.js で使用可能な軽量な GeoJSON ファイルを作成するために使用する。※node.js スクリプト実行時に ES モジュール構文をそのまま使用するため、package.json に "type": "module"
が記載されていることを確認する。
手順 3: データ変換
3-1. 変換コードの実装
tools/shapefile-converter.js を作成し、以下のスクリプトを実装する。
import shapefile from "shapefile";
import fs from "fs";
import path from "path";
/**
* ShapefileをGeoJSONに変換するツール
*/
// コマンドライン引数を解析
const args = process.argv.slice(2);
if (args.length < 2) {
process.exit(1);
}
const inputPath = args[0];
const outputPath = args[1];
// オプション解析
const options = {
filterJapan: args.includes("--filter-japan"),
simplify: args.includes("--simplify"),
encoding: "utf8",
};
// エンコーディング指定
const encodingIndex = args.indexOf("--encoding");
if (encodingIndex !== -1 && encodingIndex + 1 < args.length) {
options.encoding = args[encodingIndex + 1];
}
/**
* 日本のデータのみをフィルタリング
*/
function filterJapanFeatures(features) {
return features.filter((feature) => {
const props = feature.properties;
// Natural Earthの正しいプロパティ名で日本を判定
if (
props.iso_a2 === "JP" ||
props.adm0_a3 === "JPN" ||
props.sov_a3 === "JPN" ||
props.admin === "Japan" ||
props.geonunit === "Japan"
) {
return true;
}
// 念のため、adminやgeonunitにJapanが含まれているかもチェック
if (
(props.admin && props.admin.includes("Japan")) ||
(props.geonunit && props.geonunit.includes("Japan"))
) {
return true;
}
return false;
});
}
/**
* 座標の簡略化(Douglas-Peucker アルゴリズムの簡易版)
*/
function simplifyCoordinates(coordinates, tolerance = 0.01) {
if (!Array.isArray(coordinates[0])) {
return coordinates;
}
if (Array.isArray(coordinates[0][0])) {
// ポリゴンの場合
return coordinates.map((ring) => simplifyRing(ring, tolerance));
} else {
// LineStringの場合
return simplifyRing(coordinates, tolerance);
}
}
function simplifyRing(ring) {
if (ring.length <= 2) return ring;
// 簡易的な間引き処理
const simplified = [ring[0]]; // 最初の点は必ず含める
for (let i = 1; i < ring.length - 1; i += 2) {
// 2点おきに取得
simplified.push(ring[i]);
}
simplified.push(ring[ring.length - 1]); // 最後の点も必ず含める
return simplified;
}
/**
* メイン変換処理
*/
async function convertShapefileToGeoJSON() {
try {
// Shapefileを読み込み
const source = await shapefile.open(inputPath, undefined, {
encoding: options.encoding,
});
const features = [];
let result;
// すべてのフィーチャーを読み込み
while (!(result = await source.read()).done) {
if (result.value) {
features.push(result.value);
}
}
// 日本のデータのみに絞り込み
let filteredFeatures = features;
if (options.filterJapan) {
filteredFeatures = filterJapanFeatures(features);
}
// 座標の簡略化
if (options.simplify) {
filteredFeatures.forEach((feature) => {
if (feature.geometry && feature.geometry.coordinates) {
feature.geometry.coordinates = simplifyCoordinates(
feature.geometry.coordinates
);
}
});
}
// GeoJSONオブジェクトを作成
const geoJSON = {
type: "FeatureCollection",
name: path.basename(inputPath, ".shp"),
crs: {
type: "name",
properties: {
name: "urn:ogc:def:crs:OGC:1.3:CRS84",
},
},
features: filteredFeatures,
};
// 出力ディレクトリを作成
const outputDir = path.dirname(outputPath);
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
// ファイルに書き込み
fs.writeFileSync(outputPath, JSON.stringify(geoJSON, null, 2));
} catch (error) {
console.error("❌ エラーが発生しました:", error);
process.exit(1);
}
}
// メイン処理を実行
convertShapefileToGeoJSON();
3-2. 変換コマンドの実行
以下のコマンドを実行し、ne_10m_admin_1_states_provinces.shp
ファイルをインプットに、GeoJSONデータを出力する。
node tools/shapefile-converter.js public/natural-earth/ne_10m_admin_1_states_provinces.shp public/natural-earth/ne_10m_admin_1_states_provinces.json --filter-japan --simplify
- 第 1 引数: 入力 Shapefile のパス
- 第 2 引数: 出力 GeoJSON ファイルのパス
--filter-japan
: 全世界データから日本のデータのみを抽出--simplify
: 座標を間引いてファイルサイズを削減
コマンド実行後、第 2 引数で指定した場所に json が出力されれば OK。
3-3. 出力データの構造
出力されたJSONデータの構造を栃木県のデータを例に解説する。ne_10m_admin_1_states_provinces.jsonファイルが、以下のような構成で正しく出力さてるかをチェックする。
全体
{
"type": "FeatureCollection",
"name": "ne_10m_admin_1_states_provinces",
"crs": {
"type": "name",
"properties": {
"name": "urn:ogc:def:crs:OGC:1.3:CRS84"
}
},
"features": [
// 各都道府県のFeatureオブジェクトが配列で格納される
{ /* 鹿児島県 */ },
{ /* 栃木県 */ },
{ /* その他45の都道府県 */ }
]
}
各都道府県(Feature)の構造
{
"type": "Feature",
"properties": {
// === 基本情報 ===
"name": "Tochigi", // 英語名(ヌル文字パディング付き)
"name_local": "栃木県", // 現地語名(日本語)
"name_ja": "栃木県", // 日本語名
"name_en": "Tochigi Prefecture", // 英語正式名
// === 識別コード ===
"iso_3166_2": "JP-09", // ISO 3166-2コード
"iso_a2": "JP", // 国コード
"adm1_code": "JPN-1859", // 行政区分コード
"code_hasc": "JP.TC", // HASCコード
"fips": "JA38", // FIPSコード
// === 分類・タイプ ===
"type": "Ken", // 都道府県種別(県)
"type_en": "Prefecture", // 英語での種別
"region": "Kanto", // 地方名(関東)
"region_cod": "JPN-KNT", // 地方コード
// === 地理的情報 ===
"latitude": 36.6593, // 中心緯度
"longitude": 139.786, // 中心経度
"area_sqkm": 0, // 面積(km²)
// === 多言語名称 ===
"name_de": "Präfektur Tochigi", // ドイツ語
"name_fr": "Tochigi", // フランス語
"name_ko": "도치기현", // 韓国語
"name_zh": "栃木县", // 中国語(簡体字)
"name_zht": "栃木縣", // 中国語(繁体字)
// その他20以上の言語での名称...
// === メタデータ ===
"scalerank": 6, // 表示優先度ランク
"labelrank": 6, // ラベル表示ランク
"datarank": 2, // データ品質ランク
"min_zoom": 3, // 最小ズームレベル
"wikidataid": "Q44843", // Wikidata ID
"ne_id": 1159312195 // Natural Earth ID
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
// 栃木県の境界線を構成する座標点の配列
// [経度, 緯度] の形式で点が並ぶ
[139.44051232258562, 36.268484199086515], // 開始点
[139.42356245284486, 36.27910370497199], // 2番目の点
[139.3913163597622, 36.31098806374814], // 3番目の点
// ... 境界線を形成する多数の座標点 ...
[139.46826256716372, 36.27300588601281], // 最後から2番目
[139.44051232258562, 36.268484199086515] // 終点(開始点と同じ)
]
]
}
}
次のステップ
生成されたGeoJSONデータと、d3.jsを使って地図を描画する。詳しくは次の記事「【D3.jsで日本地図描画②】d3.jsを使って日本列島を描画する方法」を参照のこと。