2026-03-22

【Metabase】套用台灣地圖進行分析(二) -- 區、里(村)級行政區

參考資料 ----
github.com/g0v/twgeojson


github.com/g0v/twgeojson/json,有數個 json 檔,其中 twTown1982.geo.json區級行政區,twVillage1982.geo.json 則是 里(村)級

另有 twTown1982.topo.json 及 twVillage1982.topo.json,是 geo.json 的後繼優化格式,簡略記一下主要的差異:就是相鄰的 2 個區中間的界線不重複記錄。
例如:A 區與 B 區相鄰,geo.json 是完整地記錄 A 區的座標點 [1,2,3,4,5] 及 B 區的座標點 [1,6,7,8,9,2],如此 點 1點 2 就被記錄了 2 次,而 topo.json 則透過拓撲方法只記錄 1 次 點1到點2 的弧線,相較之下,topo.json 的檔案就比較小。





Metabase 目前只支援 geojson 格式,所以我們就下載這 2 個檔,以 twTown1982.geo.json 為例
點擊 twTown1982.geo.json
→ 點擊【下載】圖示下載 json

→ 將 twTown1982.geo.json 放置在 /var/www/html/ 下,然後在 Metabase 設定 twTown1982.geo.json 的 url,在本例為 http://localhost/twTown1982.geo.json

瞄一下檔案內容
 
{"type": "FeatureCollection",
 "features": [

 ...
 ...
 
    {"properties":{"TOWNSN":"64000002","TOWNID":"6400003","COUNTYNAME":"高雄市","TOWNNAME":"左營區","name":"高雄市/左營區"},
				   "type":"Feature",
				   "geometry":{"type": "Polygon", 
							   "coordinates": [[[ 120.274766995608132, 22.706593189102705 ], 
                                   ...
                                   ...
                               ]] 
							}
				},
    ...
    ...
 

登入 Metabase,點擊【齒輪】圖示
→ 管理員設定

→ 地圖 → 新增一個地圖


→【URL】輸入 http://localhost/twTown1982.geo.json
→【區域識別符】選擇 TOWNID
→【區域顯示名稱】選擇 TOWNNAME


g0v/twgeojson 的是 2014 年的資料,理論上這幾年並沒有重新劃分區級行政區,所以資料應該仍可信、準確。


g0v/twgeojson/json/twVillage1982.geo.json 則更細, 行政區範圍小至 "村/里",村/里的劃分就可能不定期會變動了,例如老人家居住的里聽說最慢 2027 年就將要拆成 4 個里。


建立區級資料表存放 geojson 的資料,在本筆記,資料表命名為 town_geo
 
CREATE TABLE `town_geo` (
    `id` INT AUTO_INCREMENT PRIMARY KEY,
    `TOWNSN` VARCHAR(20),
    `TOWNID` VARCHAR(20),
    `COUNTYNAME` VARCHAR(50),
    `TOWNNAME` VARCHAR(50),
    `name` VARCHAR(100),
    `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
 


寫一個 php 讀取 twTown1982.geo.json 並存入 town_geo
 
<?php
ini_set('display_errors', 1);
ini_set('memory_limit', '512M');    // 放寬記憶體限制, 才能讀大檔案

// 資料庫連線設定
$host = 'localhost';
$dbname = '資料庫名稱';
$username = '帳號';
$password = '密碼';

try {
    // 1. 建立 PDO 連線
    $pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // 2. 讀取並解析 GeoJSON 檔案
    $jsonFile = 'twTown1982.geo.json';
    if (!file_exists($jsonFile)) {
        die("錯誤:找不到檔案 $jsonFile");
    }

    $jsonContent = file_get_contents($jsonFile);
    $data = json_decode($jsonContent, true);

    if ($data === null) {
        die("錯誤:JSON 解析失敗");
    }

    // 3. 準備 SQL 插入語句
    $sql = "INSERT INTO town_geo (TOWNSN, TOWNID, COUNTYNAME, TOWNNAME, name) 
            VALUES (:townsn, :townid, :countyname, :townname, :name)";
    $stmt = $pdo->prepare($sql);

    // 4. 開始交易 (Transaction) 以提升大量寫入的速度
    $pdo->beginTransaction();

    $count = 0;
    foreach ($data['features'] as $feature) {
        $props = $feature['properties'];

        // 綁定參數並執行
        $stmt->execute([
            ':townsn'     => $props['TOWNSN'] ?? null,
            ':townid'     => $props['TOWNID'] ?? null,
            ':countyname' => $props['COUNTYNAME'] ?? null,
            ':townname'   => $props['TOWNNAME'] ?? null,
            ':name'       => $props['name'] ?? null
        ]);
        
        $count++;
    }

    // 5. 提交交易
    $pdo->commit();

    echo "成功!共匯入 $count 筆資料。";

} catch (PDOException $e) {
    // 發生錯誤時回滾
    if (isset($pdo) && $pdo->inTransaction()) {
        $pdo->rollBack();
    }
    echo "資料庫錯誤:" . $e->getMessage();
} catch (Exception $e) {
    echo "一般錯誤:" . $e->getMessage();
}
?>
 

如此就能結合自己的資料表,建立區級行政區的圖表了。




再建立里(村)級資料表,在本例為 village_geo
 
CREATE TABLE `village_geo` (
    `id` INT AUTO_INCREMENT PRIMARY KEY,
    `VILLAGESN` VARCHAR(20),
    `VILLAGEID` VARCHAR(20),
    `COUNTYNAME` VARCHAR(50),
    `TOWNNAME` VARCHAR(50),
    `VILLAGENAM` VARCHAR(50),
    `name` VARCHAR(150),
    `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
 


寫一個 php 讀取 twVillage1982.geo.json 並存入 village_geo
 
<?php
// 1. 提高記憶體限制(針對較大的村里 GeoJSON 檔案)
ini_set('memory_limit', '512M');
set_time_limit(0); // 取消執行時間限制

// 資料庫連線設定
$host = 'localhost';
$dbname = '資料庫名稱';
$username = '帳號';
$password = '密碼';

try {
    // 2. 建立 PDO 連線
    $pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // 3. 讀取 GeoJSON 檔案
    $jsonFile = 'twVillage1982.geo.json';
    if (!file_exists($jsonFile)) {
        die("錯誤:找不到檔案 $jsonFile");
    }

    echo "正在讀取檔案...\n";
    $jsonContent = file_get_contents($jsonFile);
    
    echo "正在解析 JSON...\n";
    $data = json_decode($jsonContent, true);
    
    // 解析完立刻釋放字串記憶體
    unset($jsonContent); 

    if ($data === null) {
        die("錯誤:JSON 解析失敗,請檢查檔案格式。");
    }

    // 4. 準備 SQL 插入語句
    $sql = "INSERT INTO village_geo (VILLAGESN, VILLAGEID, COUNTYNAME, TOWNNAME, VILLAGENAM, name) 
            VALUES (:v_sn, :v_id, :c_name, :t_name, :v_name, :full_name)";
    $stmt = $pdo->prepare($sql);

    // 5. 開始交易處理 (大量資料寫入必備)
    $pdo->beginTransaction();

    echo "正在匯入資料...\n";
    $count = 0;
    foreach ($data['features'] as $feature) {
        $props = $feature['properties'];

        $stmt->execute([
            ':v_sn'      => $props['VILLAGESN'] ?? null,
            ':v_id'      => $props['VILLAGEID'] ?? null,
            ':c_name'    => $props['COUNTYNAME'] ?? null,
            ':t_name'    => $props['TOWNNAME'] ?? null,
            ':v_name'    => $props['VILLAGENAM'] ?? null,
            ':full_name' => $props['name'] ?? null
        ]);
        
        $count++;
    }

    // 6. 提交交易
    $pdo->commit();
    echo "匯入完成!成功存入 $count 筆村里資料。";

} catch (PDOException $e) {
    if (isset($pdo) && $pdo->inTransaction()) {
        $pdo->rollBack();
    }
    echo "資料庫錯誤:" . $e->getMessage();
} catch (Exception $e) {
    echo "一般錯誤:" . $e->getMessage();
}
?>
 
匯入的記錄如下圖


如果您需要的圖資精細顆粒度要小到村/里國土測繪中心政府資料開放平臺(opendata) 也有提供圖資,感覺有提續在更新,可能會較適合您,但國土測繪中心沒有直接提供 geo.json 格式,我們需要轉換程式幫忙。

到 村里界圖(TWD97經緯度),點擊【資料資源下載網址】,下載的是壓縮檔,找個目錄解壓縮存放,會看到解壓出來的檔案中有副檔名 .shp 的檔案,這是主檔。



到 QGIS 下載格式轉換程式並安裝,藉助程式將 shp 轉換為 geo.json 格式。


選擇 shp 檔,在本例為 VILLAGE_NLSC_1150306.shp



功能表 【Layer】→【Save As】→【Format】欄位選擇 GeoJSON → 輸入檔名,在本例為 town_twd97 → 按下【確定】鈕


開啟檔案,會發現 properties 內的欄位跟上面 g0v 的不同,由此可知,properties 的欄位是各自定義的;所以,若您圖資是選擇國土測繪中心的,需注意匯入資料的欄位也會不同。



相關筆記 ----


沒有留言:

張貼留言