D3 可以用來畫地圖,做資料視覺化,但是地圖的處理須要經過一些複雜的程序,有一些地圖知識,才能順利做出來,而查詢到的資料大部分都是台灣地圖的製作,但我這個泰國迷就是想要做泰國的地圖嘛,所以今天帶大家來實作泰國的資料。
先前準備
QGIS : 一個處理地圖的應用程式,到他的官網下載安裝(版本3)。
分為三大步驟: 資料蒐集、資料處理(QGIS)、資料呈現(D3)。
1. 資料蒐集
地圖的座標資料會儲存在.shp的檔案裡面,如果你要找到不同語系的data,就可以用該語言搜尋,台灣的資料可以在政府公開資料平台找到,點一下shp下載下來,而我使用的泰國資料在BANGKOKGIS裡面。解壓縮之後,有幾個檔案副檔名名稱: ,shp,shx, dbf, ,cpg pri,sbn,sbx,稍微認識一下這些資料:
必要檔案
這三個是打開地圖的必要資料!
.shp — 是美國環境系統研究所公司(ESRI)開發的空間資料,可以用來描述點point、線line、多邊形polygen等資料。
.shx — 圖形索引格式。幾何體位置索引,記錄每一個幾何體在shp檔案之中的位置,能夠加快向前或向後搜尋一個幾何體的效率。
.dbf — 屬性資料格式,以dBase III+ 的資料表格式儲存每個幾何形狀的屬性資料,有些圖形上面有資訊,座標、名稱,就是存在這裡。
非必要檔案
.prj — 投影格式,用於儲存地理坐標系統與投影資訊,包含了幾何資料所使用的經緯度坐標系統。
.cpg — 用於描述.dbf檔案的頁碼,指明其使用的字元編碼,當你使用資料是不同語系的時候,就需要這個檔案。
.sbn,. sbx — Shapefile空間索引格式,這是一個二進位的空間索引檔案,僅僅可以應用在ESRI的軟體之中。不是必須的,因為.shp檔案之中已經包含了所有的解析空間資料所需的資訊。
2. QGIS資料轉換
接下來,由於D3需要的是geojson(地圖專用的json資料)格式,所以我們必須要把shp轉換成geojson(使用經緯度),可以利用mapshaper 做轉換,把檔案拉進去匯出檔案格式即可,不過有些資料沒有辦法,就需要利用強大的qgis做資料處理。
打開安裝好的QGIS,選擇上方 圖層->加入圖層->加入向量圖層,選擇你的shp檔案,編碼的地方很重要! 國外的資料要去查看看該語系編碼是多少,泰國的資料可以用cp874,按下加入。
接著地圖就會出來了! 看到左邊的圖層已經加入了捷運站的點!
點擊左方圖層bts_station右鍵,開啟屬性表格,可以看到除了座標資料的name、location等資料(存在.dbf),如果剛剛沒有轉換cpg的話,這裡會是亂碼喔! 確認正常顯示後就可以先將屬性表格關起來。
在頁面下方的資訊,可以看到奇怪的座標值,以及EPSG32647。
EPSG是European Petroleum Survey Group的縮寫,EPSG定義了世界各國投影、坐標系統,所以不同的數值表不同的投影系統。我們必須把檔案轉換常見的經緯度數值EPSG:4326。
EPSG:4326是WGS84大地基準(Google Earth),是一般的經緯度數值。
也就是說,把EPSG32647àEPSG4326,並存成geojson檔。
所以我們按下圖層右鍵,匯出 → save feature as,格式選擇geojson,命名檔案名稱,crs坐標參考系統選擇4326,按下ok後就匯出了。
利用編輯器打開geojson檔案,確保檔案有找到正常的經緯度值。
3. D3.js作呈現
經過前面繁瑣的資料處理後,接著來到重頭戲了! 準備好geojson檔案後,開啟一個js file。
這裡用截圖想讓大家好看一點,附上程式碼在後面~
登登~出現囉~
這樣就利用d3把點座標畫出來囉!
const width = ‘600’const height = ‘400’// 讓d3抓svg,並寫入寬高var svg = d3.select(‘#svg’).attr(‘width’, width).attr(‘height’, height).attr(‘viewBox’, `0 0 ${width} ${height}`);console.log(svg)// 定義投影的資料var projection = d3.geo.mercator() // 利用麥卡托投影mercator(),.translate([width / 2, height / 2]) // translate把中心偏移量調整回來,.center([100.53, 13.74]) // center以該經緯度作為中心點(可以參考geojson裡面的座標值),.scale(122600); // scale要自己去調整,我使用的是捷運站資料,所以放大的倍數很大。// 座標變換函式var path = d3.geo.path().projection(projection);// 讓d3抓GeoJSON檔,並寫入path的路徑 bts_stationvar url = ‘../data/transBTS.geojson’; // GeoJSON的檔案路徑d3.json(url, (error, geometry) => {if (error) throw error;//插入分组元素var location = svg.selectAll(“.location”).data(geometry.features).enter().append(“g”).attr(“class”, “location”).attr(“transform”, function (d) {//计算标注点的位置var coor = projection([d.geometry.coordinates[0], d.geometry.coordinates[1]]);return “translate(“ + coor[0] + “,” + coor[1] + “)”;});location.append(“circle”).attr(“r”, 5).attr(“fill”, “#E91E63”).attr(“class”, “location”);});