使用D3 Geo模塊畫澳大利亞地圖
數據
數據可視化主要旨在藉助於圖形化手段,清晰有效地傳達與溝通訊息。所以作數據可視化前須要想明白2件事:
本文中的示例中,將以不一樣的顏色顯示澳大利亞不一樣地區的客戶數量。
所以,首先須要澳大利亞的地圖數據,D3中的Geo模塊能夠處理GeoJSON格式的地理數據。(GeoJSON是一種對各類地理數據結構進行編碼的格式。GeoJSON對象能夠表示幾何、特徵或者特徵集合。GeoJSON支持下面幾何類型:點、線、面、多點、多線、多面和幾何集合。GeoJSON裏的特徵包含一個幾何對象和其餘屬性,特徵集合表示一系列特徵。參見:http://www.oschina.net/translate/geojson-spec?cmp)
開發者能夠從Natural Earth(http://www.naturalearthdata.com/)獲取到全球全部的地理數據,使用其地理數據須要 注意2點:
- 其有3種比例的數據1:10m,1:50m和1:110m。1:10m比例的數據擁有更細節的數據,只有它纔有州(省)的信息。
- 其數據不是GeoJSON格式的(Shapefile),須要經過GDAL(Geospatial Data Abstraction Library)庫轉換爲GeoJSON格式。
在Mac下安裝GDAL很是方便,感謝Homebrew:
而後經過以下命令就能夠Shapefile中的澳大利亞的數據提取出來。
- ogr2ogr -f GeoJSON -where "sr_adm0_a3 = 'AUS'" aus.states.json 10m_cultural/ne_10m_admin_1_states_provinces_lakes_shp.shp
是一個相似下文這樣的一個GeoJSON格式數據。
- {
- "type": "FeatureCollection",
- "features": [
- {
- "type": "Feature",
- "properties": {
- ...
- },
- "geometry": {
- "type": "Polygon",
- "coordinates": [
- [
- ....
- ]
- ]
- }
- },
- ......
順道提一下,Geo數據通常都比較大,尤爲是GeoJSON格式下的數據,像上面生成的數據就有741KB,這對於Web應用來講已是很大的一個數值。開發者能夠經過Topojson(https://github.com/mbostock/topojson/wiki)壓縮數據。Topojson是GeoJSON的一個擴展,使用方式大體相同,這兒就不講Topojson了,下圖可讓開發者大體瞭解一下三種格式下數據的大小:
畫圖
有了數據,接下來就開始畫圖。D3畫圖都有必定的套路,首先須要肯定把矢量圖SVG放到那兒,以及圖的大小
- var width = 960;
- var height = 580;
- var svg = d3.select("#geo_distribution").append("svg")
- .attr("width", width)
- .attr("height", height)
- .append("g")
- .attr("transform", "translate(0,0)");
接着,須要建立一個路徑生成器,路徑生成器能夠接收一個投射函數,該投射函數存在的目的是把圓形地球上的經緯度投射到平面的Web界面上。D3自帶了各類各樣的投射函數(https://github.com/mbostock/d3/wiki/Geo-Projections),本例中使用的是墨卡託投影(http://baike.baidu.com/view/301981.htm?fr=aladdin)。
- var projection = d3.geo.mercator()
- .center([132, -28])
- .scale(850)
- .translate([width/2, height/2]);
-
- var path = d3.geo.path()
- .projection(projection);
而後,根據讀取的GeoJSON數據繪製路徑:
- var color = d3.scale.category20();
- var states = svg.append("svg:g")
- .attr("id", "states");
- d3.json("data/aus.states.json", function(error, root) {
- if (error)
- return console.error(error);
-
- states.selectAll("path")
- .data( root.features)
- .enter()
- .append("path")
- .attr("stroke","#000")
- .attr("stroke-width",1)
- .attr("fill", function(d,i){
- return color(i);
- })
- .attr("d", path )
- .on("mouseover",function(d,i){
- d3.select(this)
- .attr("fill","yellow");
- })
- .on("mouseout",function(d,i){
- d3.select(this)
- .attr("fill",color(i));
- });
- });
畫到這兒一個澳大利亞的地圖就是下面這個樣子了:
加點佐料
畫了地區以後,純屬我的樂趣,還想畫點城市在上面,作法也是同樣的, 首先獲取Geo數據,仍是能夠從Natural Earth的地理數據中轉換獲得(注:轉換數據時,開發者能夠根據我的愛好過濾掉一些數據,比方說下面的命令中我過濾掉了規模上第四等級之後的小城市):
- ogr2ogr -f GeoJSON -where "ADM0_A3 = 'AUS' and SCALERANK <=4" aus.big.cities.json 10m_cultural/ne_10m_populated_places.shp
接着,把用於描述城市的小圓點和城市名字的SVG添加到底層SVG上:
- var circles = svg.append("svg:g")
- .attr("id", "circles");
-
- var texts = svg.append("svg:g")
- .attr("id", "texts");
而後,根據前面獲得的數據在建立的SVG上畫圖
- d3.json("data/aus.cities.json", function(error, root) {
- circles.selectAll("circle")
- .data(root.features)
- .enter().
- append("svg:circle")
- .attr("cx", function(d){return projection([d.properties['LONGITUDE'],d.properties['LATITUDE']])[0];})
- .attr("cy",function(d){return projection([d.properties['LONGITUDE'],d.properties['LATITUDE']])[1];})
- .attr("r", 3)
- .attr('fill','#29FF57');
-
- texts.selectAll("text")
- .data(root.features)
- .enter()
- .append("svg:text")
- .text(function(d){return d.properties['NAME'];})
- .attr("x", function(d){
- return projection([ d.properties['LONGITUDE'],d.properties['LATITUDE']])[0];})
- .attr("y",function(d){
- return projection([d.properties['LONGITUDE'],d.properties['LATITUDE']])[1];
- })
- .attr('fill','#000')
- .attr('font-size','9px');
-
- });
最後獲得的結果以下:
參考:
http://www.tnoda.com/blog/2013-12-07
https://github.com/mbostock/d3/wiki/Geo-Paths#path
歡迎關注本站公眾號,獲取更多信息