使用D3 Geo模块画澳大利亚地图

[size=large][b]数据[/b][/size]
数据可视化主要旨在借助于图形化手段,清晰有效地传达与沟通信息。因此做数据可视化前需要想明白2件事:
[list]
[*]你有什么数据?
[*]你要传达什么信息?
[/list]
本文中的示例中,将以不同的颜色显示澳大利亚不同地区的客户数量。

因此,首先需要澳大利亚的地图数据,D3中的Geo模块可以处理GeoJSON格式的地理数据。(GeoJSON是一种对各种地理数据结构进行编码的格式。GeoJSON对象可以表示几何、特征或者特征集合。GeoJSON支持下面几何类型:点、线、面、多点、多线、多面和几何集合。GeoJSON里的特征包含一个几何对象和其他属性,特征集合表示一系列特征。参见:[url]http://www.oschina.net/translate/geojson-spec?cmp[/url])
开发者可以从Natural Earth([url]http://www.naturalearthdata.com[/url]/)获取到全球所有的地理数据,使用其地理数据需要 注意2点:
[list]
[*]其有3种比例的数据1:10m,1:50m和1:110m。1:10m比例的数据拥有更细节的数据,只有它才有州(省)的信息。
[*]其数据不是GeoJSON格式的(Shapefile),需要通过GDAL(Geospatial Data Abstraction Library)库转换为GeoJSON格式。
[/list]
在Mac下安装GDAL非常方便,感谢Homebrew:
brew install gdal

然后通过如下命令就可以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([url]https://github.com/mbostock/topojson/wiki[/url])压缩数据。Topojson是GeoJSON的一个扩展,使用方式大致相同,这儿就不讲Topojson了,下图可以让开发者大致了解一下三种格式下数据的大小:
[img]http://dl2.iteye.com/upload/attachment/0103/6112/f12d13f5-8b88-33a0-b245-91a4d398ff3e.png[/img]

[size=large][b]画图[/b][/size]
有了数据,接下来就开始画图。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自带了各种各样的投射函数([url]https://github.com/mbostock/d3/wiki/Geo-Projections[/url]),本例中使用的是墨卡托投影([url]http://baike.baidu.com/view/301981.htm?fr=aladdin[/url])。
 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);//color函数可根据数据设置每个州板块的颜色,示例中使用的是D3自带的颜色函数。
})
.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));
});
});

画到这儿一个澳大利亚的地图就是下面这个样子了:
[img]http://dl2.iteye.com/upload/attachment/0103/6114/a9a0cd68-9694-39ed-a747-4e8f3ddf05e5.gif[/img]

[size=large][b]加点佐料 [/b][/size]
画了地区之后,纯属个人乐趣,还想画点城市在上面,做法也是一样的, 首先获取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');

});
最后得到的结果如下:
[img]http://dl2.iteye.com/upload/attachment/0103/6117/3c2d0ff6-a4f3-36fc-b8ea-c683f8de6c18.png[/img]

参考:

[url]http://www.tnoda.com/blog/2013-12-07[/url]
[url]https://github.com/mbostock/d3/wiki/Geo-Paths#path[/url]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值