使用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
欢迎关注本站公众号,获取更多信息