2015年5月6日 星期三

從 OSM 撈有趣的座標資料: 網站與工具

高鐵左營站附近的所有鐵道路線座標 (高鐵、臺鐵、捷運) 有時我們可能會需要某類的地圖資訊, 例如霧峰所有的便利商店座標、 全臺灣火車站位置、 或是左營高鐵站附近的鐵道路線座標等等。 你可以選擇 一次下載整個 pbf 資料庫, 再用命令列工具處理。 或者, 如果你要抓的資料量不大、 次數不是很頻繁, 那麼另一個選擇是採用 RESTful API 直接從網站上撈資料。 沒耐性的讀者可以直接跳到第五節 「Overpass Turbo」。

一、 預備動作

OSM 內部有 三類的資料: 點 (node)、 線 (way)、 關係 (relation)。 如果我們只對座標有興趣的話, 應該只會用到 node 和 way。 其中 way 不只包含道路, 還有多邊形區域的邊界也是用 way 來表示。

用 geofabrik 的 calc 服務找出矩形範圍的座標

首先, 最簡單的過濾圖資方式, 就是只鎖定一小個矩形範圍內的圖資。 請到 geofabrik 網站。 把地圖移到你有興趣的地理區域。 按著 ctrl 鍵不放, 用滑鼠定義你要的矩形。 (變成橘色) 在頁面右側, 從預設的 TC 分頁 (Tile Calculator) 切換到 CD 分頁 (Coordinate Display)。 會看到畫面上多出一個略大於你所選取橘色區域的虛線矩形。 這是因為小數位數不足, 無條件捨去或進入之後所得的結果。 如果希望虛線矩形 (等一下下指令時真實的查詢範圍) 更貼近你所選擇的範圍, 可以提高小數位數 (number of decimal places)。 調整滿意之後, 把 「simple copy」 所顯示的四個數字剪貼下來。

二、 xapi

如果要擷取的是 nodes, 那麼可以用簡單、 最適合初學者的 xapi 介面。 查詢結果以 xml 格式呈現, 所以請用 firefox 點進以下連結。 如果是 chrome, 請搜尋 「chrome xml」 並挑一個可以檢視 xml 的外掛裝起來。 請研究以下每個連結的網址 -- 查詢指令就在網址裡面。 這就是 RESTful API

  1. 語法: node[shop=*][bbox=120.684,24.043,120.727,24.083] 撈出矩形內所有的商店。 請另存新檔, 叫做 shop.xml 好了。 如果不加 [shop=*] 會抓到太多無趣的 nodes, 包含彎來彎去道路上的每個節點。 [各位體貼的 OSM 用戶請只拿你需要的資料就好, 省著點用, 別把服務全球的辛苦伺服器操爆啊。]
  2. 語法: node[amenity=*][bbox=120.684,24.043,120.727,24.083] 撈出矩形內所有 "amenity" 類型的 nodes。 請另存新檔, 叫做 amenity.xml。 所謂 amenity (便利設施) 包含餐廳、 咖啡館、 學校、 停車場、 廁所、 提款機、 ... 等等除了商店之外, 其他絕大多數我們可能會有興趣的地點。 有時商店也被標記為 amenity。 到底怎麼標才正確, 我也不確定。
  3. 語法: node[shop=convenience][bbox=120.684,24.043,120.727,24.083] 撈出矩形內所有便利商店。 請另存新檔, 叫做 convenience.xml。
  4. 其實 xapi 也可以查詢 way。 語法: way[railway=*][bbox=120.284,22.663,120.356,22.723] 撈出高鐵左營站附近所有的鐵道座標。 請另存新檔, 叫做 railway.xml。

三、 node 轉檔與上傳

把 geojson 檔上傳到 umap 去 接下來要把 xapi 所產出的 xml 格式轉成 geojson 格式, 並上傳到自己的地圖上查看。

  1. 在 debian wheezy 底下, 安裝 gdal-bin 跟 gpsbabel 兩個套件。
  2. 從 amenity.xml 產生 amenity.geojson: ogr2ogr -f geojson amenity.geojson amenity.xml 或是從 amenity.xml 產生 amenity.gpx: ogr2ogr -f gpx amenity.gpx amenity.xml
  3. 如果覺得產生的 .geojson 檔擠在一起很難讀, 可以用 jq 轉檔瑞士刀 整理: jq '.' amenity.geojson > amenity-pretty-print.geojson
  4. 打開你的 umap 私房地圖、 把畫面縮放移動到你有興趣的地理區域。
  5. 按右上角的筆開始編輯。
  6. 按右側的 「上傳」 (匯入資料)、 瀏覽選取剛剛產生的 geojson 或 gpx、 選擇 「匯入至新圖層」、 按 「匯入」。 成功看見抓出來的便利設施! 做實驗時會重複匯入資料。 每次把匯入的資料放在新的獨立圖層, 要刪除比較方便。

四、 更強大完整的 Overpass API

上面的方法處理 nodes 很好用; 至於用 xapi 所抓出來的 way 則無法如上處理。 搜尋到幾個可能的方案:

  1. 用 osmn2nodegpx 轉成 gpx 會遺失很多資訊。
  2. 先用 xappy 轉成 json 用 jq 轉成 geojson
  3. 用 xapi 的除錯模式可以轉成 geojson

其中 「xapi 除錯模式」 那個問答提到: 其實 xapi 底下會去呼叫更強大的 Overpass API, 而後者可以採用 json (但並非 geojson) 格式輸出資料。

於是根據 這篇教學文 以及 overpass api 輸出格式說明, 把先前的查詢指令改成呼叫 overpass 的指令如下。 請在另外的空目錄下這些指令, 因為我們要產生檔名會跟第二節重複。

  1. 位於霧峰的商店, 以 OSM xml 格式輸出: wget 'http://overpass-api.de/api/interpreter?data=node[shop](24.043,120.684,24.083,120.727);out;' -O shop.xml
  2. 位於霧峰的商店, 以 json 格式輸出: wget 'http://overpass-api.de/api/interpreter?data=[out:json];node[shop](24.043,120.684,24.083,120.727);out;' -O shop.json
  3. 位於霧峰的商店, 以 html 格式輸出, 適合人眼直接閱讀: 請直接點 連結。 注意: 如果你的瀏覽器有安裝 noscript 的話, 這會被當成 xss 擋起來。 需要暫時允許 「不安全的重新讀取」。

請注意: Overpass API 填寫座標的方式, 是緯度在前經度在後, 跟 xapi 相反。

但是處理 way 的時候, 還是一樣遇到麻煩。 高鐵左營站附近所有的鐵道座標, 以 json 格式輸出: wget 'http://overpass-api.de/api/interpreter?data=[out:json];way[railway](22.663,120.284,22.723,120.356);out;' -O railway.json 打開 railway.json 來看, 會發現裡面並沒有座標, 只有一堆 node id。 在 out 之前加上 「>;」 表示要遞迴地把被引用的 nodes 也一併抓回來: wget 'http://overpass-api.de/api/interpreter?data=[out:json];way[railway](22.663,120.284,22.723,120.356);>;out;' -O railway_full.json 終於出現像樣的 json。 但還是需要再 用 jq 轉成 geojson。 我累了, 我需要保力達蠻牛...

五、 懶人救星: 網頁填表直接下載的 Overpass turbo 服務

操作 overpass turbo 最後終於搜尋到超好用的 Overpass Turbo: 國網映射 意見反映 歐洲官網

  1. 在右側把地圖調整到你所關心的地理區域。
  2. 在左側填寫 overpass api 的查詢指令。 連 bbox 都不必寫出座標了。 例如查詢所有的便利設施(含餐廳咖啡店等等)與商店:
    node[amenity]({{bbox}}); out;
    node[shop]({{bbox}}); out;
    
  3. 按左上角的 「執行」。
  4. 如果查詢的是 way, 這個網站還會很貼心地問你是否要把相關的 nodes 資料一起拉進來。 點選 「修正檢索」 之後, 左側的查詢指令會自動增加一小段。 再按一次執行。

然後右側就出現查詢結果: 左營站附近的高鐵、 臺鐵、 捷運路線全部都以藍色線條顯示出來。 再進入 「匯出」 選單, 可以選擇用 geojson、 gpx 或 kml 格式下載。 用編輯器打開 geojson 檔, 可以看到裡面不只有 Point, 也有 LineString 跟 Polygon, 成功! 為了確認輸出資料可用, 再把匯出的檔案上傳到 umap, 得到本文第一張圖。

使用 overpass turbo 的查詢精靈 Overpass Turbo 上面那排按鈕的 「精靈模式」 很適合初學者。 例如輸入 「 railway=rail or railway=station」 它會幫你寫出完整的查詢指令 -- 同時查詢某區域內所有的鐵道路線及火車站/捷運站。 又例如 「tourism in kaohsiung」 可以查詢高雄的觀光景點。

[8/16 ICOS 上面見到 supaplex 大大本尊, 他也寫了兩篇圖文並茂的 OverpassTurbo 教學文: 詳盡入門教學 + 不必手動下載上傳, 讓 umap 永遠呈現最新的 OverpassTurbo 即時資料

六、 結論

全臺所有鐵道車站 (高鐵、臺鐵、捷運) 請想想看: 如果沒有 OSM, 而是要向內政部地政司申請這些資料, 要經過多少手續? (假設你要的資料政府有開放申請的話) 最後出來的會是很方便、 立即可以上傳顯示的電子檔, 還是一張圖檔, 甚至只是一張印有許多座標的紙本報表呢? 比起向政府申請什麼碗糕的, 這是不是要方便多了呢? (右圖搜尋指令: node[railway=station])

請研究一下 各種圖徵名稱、 發揮您的想像力, 製作一些有趣的地圖, 留言分享連結吧! 自己的地圖自己畫。 當我們夠多人拿 OSM 來做有趣的應用、 當我們夠多人關心圖資正確性與完整性的問題時, 大家就會有更高的動機參與畫圖、 更正地圖。 然後我們就可以享用更高品質的地圖。

(本文接受科技部計畫補助: MOST-103-2221-E-492-028 「台灣開放街圖圖資平台建置與應用」)

2 則留言:

  1. 最後一張圖,火車站部分會漏掉標成railway=halt,有一些無人站會這麼標示

    回覆刪除
  2. 臺灣好像沒有這種站厚?

    哇, 今天終於在 ICOS 上看到大大 :-)
    已經在第五節裡面加入你那兩篇 OverpassTurbo 大作的連結。

    回覆刪除

因為垃圾留言太多,現在改為審核後才發佈,請耐心等候一兩天。