前言
草薙昭彦 2019 年推出了超強視覺化專案:Mini Tokyo 3D,還很佛心的開源。原本就對鐵路資料視覺化滿有興趣,又最近剛好看到這個完成度如此高的東東,當然要來研究一下其背後程式架構設計,看看是否有機會套用台灣鐵路資料上去。於是寫了本篇記錄。
資料分析
Show me your tables, and I won’t usually need your flowcharts; they’ll be obvious.
– Fred Brooks
首先要來研究一下,Mini Tokyo 3D 是如何存儲火車相關資料,看了一下原始檔可以總結出以下類別(跟火車無關的先不列出):
train-timetables/按車次編排的時刻表,可選加入直通運轉車次資料。coordinates.json記錄軌道位置資訊,格式跟 GeoJson 不太一樣。poi.json車站出口資訊。rail-direction.json記錄車次走向的翻譯文。railway.json記錄軌道車站列表。station-groups.json儲存車站繪製時,需要要黏在一起的車站群。stations.json記錄所有車站資訊(繪製時程式會自動將車站座標移動到軌道線上)。train-types.json記錄車種別翻譯文。train-vehicles.json記錄車廂繪製顏色。顏色列表依序指定:車頂、側邊中線、側邊下緣、前後面。
名稱取得相當直覺。接下來要來理解其中的 ID 配置。
線路繪製需要:每一條線路分配一條軌道 ID。相同車站為不同軌各自分配車站 ID,再使用 Station Groups 做分群。
時刻表資料需要:同一輛車在不同線路不同運行日下需要各自分配時刻表 ID。若這輛車會接續其他線路繼續行駛,則使用 nt(next)跟 pt(previous)連結時刻表 ID。該車輛可以額外設定終點站 ID、運行走向 ID、車種 ID(如區間、快速等)、車廂 ID(預設跟軌道同色)等資訊。時刻表需要在 tt 中設定每一個車站的到站時刻,而終點站只需要設定抵達時刻。
自己猜半天之後,發現原始碼 data-classes/ 底下的註解還滿完整的。日本鐵路系統相當複雜,一定程度上可以 Cover 掉所有鐵路運行情形,想說速速將資料全部換成台灣的就可以搞定上線⋯⋯殊不知轉檔地獄才正要開始。
台灣資料轉換
台灣 TDX 給的資料格式相當參差不齊啊(崩潰!還有寫錯字。結果轉檔花了蠻多時間處理,底下記錄下一些雷點。
台鐵的複複線?
台鐵的線路座標資料不確定是根據什麼基準量測,蠻多很接近的小片段,方向也不一致。需要自己寫解析器去按線段各自整理成一長條完整的座標線。演算法很簡單:
- 減少整體線段點數以提升繪製效能。折角超過 1 度或是距離超過 250 公尺才拿取下一點。
- 挑一條最長的做為線段串連起點,重複以下動作直到找不到下一條可以銜接:
- 頭尾接龍:取頭尾最靠近且幾乎為接續直線的線段往下拼湊(若線段走向相反要順便反向)
- 平行線接續:在頭尾處尋找非常靠近且幾乎平行的線,從中砍一刀,將目前線段接上去。然後捨棄另一半幾乎重疊的線段。
搞定!

台鐵的類直通運轉
在日本,列車路線是按照行駛區間來區分路線名稱,原則上都有自己獨立軌道,就算和別人共用軌道也會另外取一條線路名稱,例如:東京上野 Line。但台鐵目前只有按照行走地理位置區分成:西部幹線(WL)、海線(WL-C)、南迴線(SL)、⋯⋯等,也就沒有另外為每個區間命名。若直接拿地理路線當成行駛區間路線會遇到一些問題。
例如,台鐵許多南北橫跨超長區間運營的列車。於是寫了一段演算法,將長途列車拆分成區間與區間的直通運轉。
台鐵循環區間??
又例如,海線 1006 自強號會依序行駛以下時刻表(前綴為時刻表 ID):
WL.1006西部幹線。指定nt為WL-C.1006WL-C.1006海線。指定pt為WL.1006,nt為WL.1006。WL.1006再回到西部幹線。指定pt為WL-C.1006。
前面分析過,同一天的同一班車會給定唯一 ID,又接續的前後時刻表會分別指定 nt 跟 pt。於是這種運行模式就會造成頭尾時刻表配到相同時刻表 ID 的問題,程式就無法辨識 WL-C.1006 是第一段還是最後一段。後來決定把西部幹線從台中切一刀,分成西部幹線南北兩段,以解決此問題。
直達車找嘸線路
後來又發現花蓮(位於東部幹線)有直達車開往南港(位於西部幹線-北段)。這會造成我的時刻表切割演算法出問題,因為中途站宜蘭到下一班南港之間,沒有共用路線可以銜接。於是乎,我又把東部幹線擅自延長到台北車站。
車站分群
延長路線時,需要為延伸段額外增加車站點。其實就是複製現有的,再修改一下車站 ID。最後要記得把這些車站在 Station Groups 中再次分組到同一群,否則滑鼠會點選不到重疊的車站。該 JSON 檔案中,使用了 2 層 List 來記錄相連的車站。最內層緊鄰的群將繪製成一坨長圓形。而外面層的則會為其繪製連通道連接。
另外,台鐵有兩個台北車站。除了基本的「台北」之外,也要記得把環島列車用的「臺北-環島」跟台北放同一群。
軌道繪製內差設定
高鐵的資料最為乾淨,台鐵的整理完之後,大概 2 個晚上就搞定。但為求地圖美觀,又額外花許多時間去處理線路重疊問題,包含以下區間:
- 南港至浮洲地下段
- 台鐵六家接近區間
- 台鐵沙崙接近區間
- 台鐵新左營接近區間
從原本 Mini Tokyo 3D 成品中,可以觀察出 Zoom Level 越遠(數值越小)時,線路間隔會相應變寬,以避免緊鄰線路打架。研究了一番,發現竟然是程式直接內差計算出來的,共軌部分只需要存一組座標線——例如:前綴為 Base. 的軌道 ID,此特殊軌道只有被引用時會繪製,其他的只要再標記頭尾跟偏移量即可!原作者這塊處理的真的相當不錯,實在佩服。底下設定方式完全是我自己研究原始碼實驗出來的,有誤請多見諒。
首先,一條線路可以拆成多段連續座標線,記錄於 sublines 陣列中。留意拆線段的時候,需要保持相同走向,否則火車追蹤功能會顛倒。又,每一小條 Subline 可以設定不同 type,整理如下表。
| Subline Type | 意義 | 詳細說明 |
main | 使用 coords 中指定的座標陣列繪製線路。 | 若指定 start 或 end,內差計算會在 Zoom Level 需要時,根據指定軌道 ID 將頭尾偏移 offset 整數倍。可分別加入 zoom 參數以指定分界 Zoom Level。 |
sub | coords 只需指定頭尾 2 點座標。中間線段會使用 start 及 end 指定的軌道 ID 來計算。 | 可選設定 offset(預設為 0 表示使用重疊的線路位置)及 altitude 以調整海拔。 |
hybrid | Zoom Out 時使用 sub 方式;Zoom In 時使用 main 方式來繪製線路。可指定 zoom 參數以設定 Zoom Level 的切換點。 | 需指定 start 及 end,Zoom Out 時會根據設定偏移整條路線 offset 倍。 |
來看調整前後差異。

做為參考,上圖中台鐵六家線路線形狀設定為:
{
"id": "TR.LJ",
"sublines": [
{
"type": "main",
"coords": [新竹, ..., 竹中],
"end": {"railway": "THSR.Main", "offset": 1, "zoom": 16}
},
{
"type": "hybrid",
"coords": [竹中, ..., 六家],
"zoom": 16,
"start": {"railway": "THSR.Main", "offset": 1, "zoom": 16},
"end": {"railway": "THSR.Main", "offset": 1, "zoom": 16}
}
]
}這裡需要留意第一條 main 路線要設定 end 資訊,用以無縫接軌下一條 hybrid 線段。
鐵路地下化!
在 subline 設定中指定 altitude 為 -1 的話,該鐵路線段就會繪製到地底下。altitude 設定若放在 subline 底下第一層表示設定整段海拔。若設定在 start 或 end 中表示起終點的線路起伏。
看成果!

做為參考,上圖中台鐵高雄段路線形狀設定為:
{
"id": "TR.WL-S",
"sublines": [
{ 台中, ..., 新左營 },
{
"coords": [新左營, ..., 後庄],
"altitude": -1,
"start": {"altitude": 0},
"end": {"altitude": 0},
},
{ 後庄, ..., 屏東 }
]
}時刻表差異處理
運行日調整。在日本,時刻表主要分成 3 個時段:平日、土(週六)、日祝(週日及國定假日)。但翻了一圈台鐵時刻表,發現 API 是一到日一天一天給說當天有沒有開。例如:196 車次是五六日開;191 車次是一六日開⋯⋯啊~~運行日模式太多,乾脆拆分成一天一天記錄好了。此改動需要額外修改原始碼中:獲取當天時刻表、跟製作每日時刻表的相關函式。
又,台北捷運已經方便到乘客可以無視車次。結果從 API 拿到的質料也只剩下每一站的發車時刻表。只好再自己寫解析器,參考站間運行時間資料,將站間時刻表黏成一列一列捷運班車。車次就自己隨意流水號,然後車種全部設定成「區間」。另外,因為文湖線無法取得時刻表,所以就先讓它空晾在一邊。
成果 Demo
Mini Taiwan 3D題外話。由於台北的火車全部地下化,地上檢視時其實看不太到火車在跑 XD 又若切換成地下模式檢視,變成看不到建築物(台北 101 QQ)。無論如何都會使得截圖看起來頗無聊 >< 這就是無腦地下化之後的宿命嗎⋯⋯最喜歡看火車窗外風景的說。
相似專案
資料來源
原始碼
從 Mini Tokyo 3D 專案 Fork 過來修改的版本。master 用來持續更新原專案的新改動。台灣修改版本放在 dev/taiwan-map Branch 上。
未來規劃
- 新增台灣其他縣市的捷運路線
- 新增 Live Cam 資料
- 新增台灣航班資訊
- 支援動態抓去當日時刻表
- 支援誤點列車顯示
References
- foliumの基本的な使い方とオープンデータ活用 #Python – Qiita
- 都内の鉄道の“動き”を3D地図上にリアルタイムに再現、「Mini Tokyo 3D」はいかにして作られたのか? 開発者・草薙昭彦氏が語る【地図とデザイン】 – INTERNET Watch
