zoukankan      html  css  js  c++  java
  • 使用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:
    Shell代码  收藏代码
    1. brew install gdal  

    然后通过如下命令就可以Shapefile中的澳大利亚的数据提取出来。
    Shell代码  收藏代码
    1. ogr2ogr -f GeoJSON -where "sr_adm0_a3 = 'AUS'" aus.states.json 10m_cultural/ne_10m_admin_1_states_provinces_lakes_shp.shp  

    是一个类似下文这样的一个GeoJSON格式数据。
    Javascript代码  收藏代码
    1. {  
    2.     "type": "FeatureCollection",  
    3.     "features": [  
    4.         {  
    5.             "type": "Feature",  
    6.             "properties": {  
    7.                 ...  
    8.             },  
    9.             "geometry": {  
    10.                 "type": "Polygon",  
    11.                 "coordinates": [  
    12.                     [  
    13.                         ....  
    14.                     ]  
    15.                 ]  
    16.             }  
    17.         },  
    18.         ......  

    顺道提一下,Geo数据一般都比较大,尤其是GeoJSON格式下的数据,像上面生成的数据就有741KB,这对于Web应用来说已经是很大的一个数值。开发者可以通过Topojson(https://github.com/mbostock/topojson/wiki)压缩数据。Topojson是GeoJSON的一个扩展,使用方式大致相同,这儿就不讲Topojson了,下图可以让开发者大致了解一下三种格式下数据的大小:


    画图
    有了数据,接下来就开始画图。D3画图都有一定的套路,首先需要确定把矢量图SVG放到那儿,以及图的大小
    Javascript代码  收藏代码
    1. var width  = 960;  
    2. var height = 580;  
    3. var svg = d3.select("#geo_distribution").append("svg")  
    4.         .attr("width", width)  
    5.         .attr("height", height)  
    6.         .append("g")  
    7.         .attr("transform", "translate(0,0)");  
    接着,需要创建一个路径生成器,路径生成器可以接收一个投射函数,该投射函数存在的目的是把圆形地球上的经纬度投射到平面的Web界面上。D3自带了各种各样的投射函数(https://github.com/mbostock/d3/wiki/Geo-Projections),本例中使用的是墨卡托投影(http://baike.baidu.com/view/301981.htm?fr=aladdin)。
    Javascript代码  收藏代码
    1. var projection = d3.geo.mercator()  
    2.        .center([132, -28])  
    3.        .scale(850)  
    4.        .translate([width/2, height/2]);  
    5.   
    6.    var path = d3.geo.path()  
    7.        .projection(projection);  

    然后,根据读取的GeoJSON数据绘制路径:
    Javascript代码  收藏代码
    1. var color = d3.scale.category20();  
    2. var states = svg.append("svg:g")  
    3.         .attr("id", "states");  
    4. d3.json("data/aus.states.json", function(error, root) {  
    5.         if (error)  
    6.             return console.error(error);  
    7.   
    8.         states.selectAll("path")  
    9.             .data( root.features)  
    10.             .enter()  
    11.             .append("path")  
    12.             .attr("stroke","#000")//路径线颜色  
    13.             .attr("stroke-width",1)//路径线宽度  
    14.             .attr("fill", function(d,i){  
    15.                 return color(i);//color函数可根据数据设置每个州板块的颜色,示例中使用的是D3自带的颜色函数。  
    16.             })  
    17.             .attr("d", path )  
    18.             .on("mouseover",function(d,i){//添加鼠标事件  
    19.                 d3.select(this)  
    20.                     .attr("fill","yellow");  
    21.             })  
    22.             .on("mouseout",function(d,i){  
    23.                 d3.select(this)  
    24.                     .attr("fill",color(i));  
    25.             });  
    26.     });  

    画到这儿一个澳大利亚的地图就是下面这个样子了:


    加点佐料
    画了地区之后,纯属个人乐趣,还想画点城市在上面,做法也是一样的, 首先获取Geo数据,还是可以从Natural Earth的地理数据中转换得到(注:转换数据时,开发者可以根据个人爱好过滤掉一些数据,比方说下面的命令中我过滤掉了规模上第四等级以后的小城市):
    Shell代码  收藏代码
    1. ogr2ogr -f GeoJSON -where "ADM0_A3 = 'AUS' and SCALERANK <=4" aus.big.cities.json 10m_cultural/ne_10m_populated_places.shp  

    接着,把用于描述城市的小圆点和城市名字的SVG添加到底层SVG上:
    Javascript代码  收藏代码
    1. var circles = svg.append("svg:g")  
    2.     .attr("id", "circles");  
    3.   
    4. var texts = svg.append("svg:g")  
    5.     .attr("id", "texts");  

    然后,根据前面得到的数据在创建的SVG上画图
    Javascript代码  收藏代码
    1. d3.json("data/aus.cities.json", function(error, root) {  
    2.         circles.selectAll("circle")  
    3.             .data(root.features)  
    4.             .enter().  
    5.             append("svg:circle")  
    6.             .attr("cx", function(d){return projection([d.properties['LONGITUDE'],d.properties['LATITUDE']])[0];})//根据城市的经纬度投射确定圆点坐标  
    7.             .attr("cy",function(d){return projection([d.properties['LONGITUDE'],d.properties['LATITUDE']])[1];})  
    8.             .attr("r", 3)  
    9.             .attr('fill','#29FF57');  
    10.   
    11.         texts.selectAll("text")  
    12.             .data(root.features)  
    13.             .enter()  
    14.             .append("svg:text")  
    15.             .text(function(d){return d.properties['NAME'];})  
    16.             .attr("x", function(d){  
    17.                 return projection([ d.properties['LONGITUDE'],d.properties['LATITUDE']])[0];})  
    18.             .attr("y",function(d){  
    19.                 return projection([d.properties['LONGITUDE'],d.properties['LATITUDE']])[1];  
    20.             })  
    21.             .attr('fill','#000')  
    22.             .attr('font-size','9px');  
    23.   
    24.     });  
    最后得到的结果如下:


    参考:

    http://www.tnoda.com/blog/2013-12-07
    https://github.com/mbostock/d3/wiki/Geo-Paths#path
  • 相关阅读:
    HDU2159 二维完全背包
    HDU1401 BFS
    HDU2842 矩阵乘法
    CF2.E
    CF2.D
    *HDU2254 矩阵乘法
    CF2.C
    *HDU1907 博弈
    博弈
    *HDU2147 博弈
  • 原文地址:https://www.cnblogs.com/xiaohui123-com/p/6547068.html
Copyright © 2011-2022 走看看