日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

D3学习之地图

發(fā)布時間:2025/3/21 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 D3学习之地图 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

D3學(xué)習(xí)之地圖

(2017.03.09-03.11)

地圖的意義

在可視化領(lǐng)域中,將數(shù)據(jù)點投影和關(guān)聯(lián)到地理區(qū)域上,是一個非常關(guān)鍵的內(nèi)容(體現(xiàn)了可視化中利用讀者自身知識常識從而加速吸收信息的原則)。

GeoJSON and TopoJSON

GeoJSON是用于描述地圖空間信息的數(shù)據(jù)格式。GeoJSON不是一種新的格式,其語法規(guī)范是符合JSON格式的,只不過對其名稱進(jìn)行了規(guī)范,專門用于表示地理信息。GeoJSON里的對象也是由名稱/值對的集合構(gòu)成,名稱總是字符串,值可以是字符串、數(shù)字、布爾值、對象、數(shù)組、null。內(nèi)部結(jié)構(gòu)的話,每一個GeoJSON都必有一個type屬性,表示對象的類型,如Point(點)、LineString(線)、Feature(特征)等。

上圖展示的就是一個標(biāo)準(zhǔn)GeoJSON文件的內(nèi)容,可以看到type值為FeatureCollection(特征集合),則該對象必須要一個名稱為features的成員(就在type下一行),features是一個數(shù)組,數(shù)組每一項都是一個特征對象,如果是中國地圖的話,則每一項描述一個省的地理信息。

TopoJSON是GeoJSON按拓補(bǔ)學(xué)編碼后的擴(kuò)展形式,TopoJSON中的每一個幾何體都是通過將共享邊整合后組成的,從而消除了部分冗余數(shù)據(jù),同時地理坐標(biāo)使用整數(shù),因此文件大小較GeoJSON縮小了80%左右。同時,TopoJSON的語法規(guī)范也是符合JSON格式的。

獲取地圖數(shù)據(jù)

首先介紹一個非常好的地理數(shù)據(jù)網(wǎng)站Natural Earth,其中提供了大量免費的地理數(shù)據(jù)下載內(nèi)容,包括中國地圖,那么在網(wǎng)站上下載了相應(yīng)的zip包后,進(jìn)行解壓:

其中的shp文件,我們需要從中提取出需要的地理信息,并保存為中文形式,標(biāo)準(zhǔn)的工具室ogr2ogr,但是工具需要使用命令行操作,而且需要VS進(jìn)行編譯,較為麻煩,因此我們使用一個基于ogr2ogr開發(fā)的圖形化軟件:ogr2gui,下載地址為ogr2gui,下載完成后打開工具,進(jìn)行下圖操作:(切記!!導(dǎo)入的文件和導(dǎo)出的文件路徑中一定不能出現(xiàn)漢字,不然會導(dǎo)致導(dǎo)出失敗并且沒有任何錯誤提示!

完成后生成china.geojson文件,那么我們通過在線工具來看看我們獲取的數(shù)據(jù)繪制成地圖后長什么樣,瀏覽http://mapshaper.org,導(dǎo)入我們的geojson文件:

地圖繪制得不錯,然而不能接受的是地圖里沒有臺灣省。。。。所以最后我在網(wǎng)上下載了一個更合適的地圖:

mapshaper這個網(wǎng)站還有一個很重要的功能就是簡化地圖的邊界,原始地圖數(shù)據(jù)通常非常大,因為其中包含了大量地圖的細(xì)微邊界變化數(shù)據(jù),而其中一些我們并不需要,因此可以進(jìn)行簡化,下圖就是簡化后的效果:

可以發(fā)現(xiàn)適當(dāng)?shù)暮喕⒉挥绊懙貓D的整體效果(并且有時候,舍棄基本的地理信息可以讓我們展示更真實的數(shù)據(jù),見我的博客《數(shù)據(jù)可視化之美閱讀》)。

使用D3繪制地圖

那么我們最終的目的當(dāng)然是使用D3來繪制地圖,GeoJSON和TopoJSON格式都可以繪制地圖,然而TopoJSON具有文件大小更小的優(yōu)勢,所以盡可能都是用TopoJSON,但TopoJSON的缺點在于它標(biāo)準(zhǔn)是由D3作者制定,目前還不是世界范圍內(nèi)承認(rèn)的標(biāo)準(zhǔn)。下面的內(nèi)容,我們來分別使用兩種方式來繪制地圖。

GeoJSON

首選無論使用GeoJSON還是TopoJSON,都需要先定義地圖的投影和地理路徑生成器,具體代碼和注釋如下:

var projection = d3.geo.mercator().center([107, 31])   //設(shè)置地圖中心位置,前經(jīng)度后緯度.scale(850) //設(shè)置縮放量.translate([width/2, height/2]);    //設(shè)置平移量//定義地理路徑生成器 var path = d3.geo.path()      //應(yīng)用上面生成的投影,每一個坐標(biāo)都會先調(diào)用此投影函數(shù),然后才產(chǎn)生路徑值.projection(projection);

然后,通過d3.json請求文件china.geojson,并添加足夠數(shù)量的path(svg的path,svg是d3的基礎(chǔ)),每一個path用于繪制一個省的路徑。

//顏色比例尺 var color = d3.scale.category20(); //請求china.geojson,把文件的json內(nèi)容傳遞給root對象 d3.json("../geojson/china.geojson", function(error, root) {if (error)return console.error(error);console.log(root.features);svg.selectAll("path").data( root.features ).enter().append("path").attr("stroke","#aaa") //svg邊線屬性定義,這里是顏色.attr("stroke-width",1)  //這里是寬度.attr("stroke-dasharray",10,10) //svg stroke虛線.attr("fill", function(d,i){ //每一塊的顏色填充return color(i);}).attr("d", path ).on("mouseover",function(d,i){ //兩個交互,鼠標(biāo)放置和鼠標(biāo)移開d3.select(this).attr("fill","yellow");}).on("mouseout",function(d,i){d3.select(this).attr("fill",color(i));}); });

至此,地圖繪制成功,步驟非常簡潔,并且?guī)в胁糠纸换バЧ?#xff0c;我們來看看效果:

如上圖所示,鼠標(biāo)箭頭停留處對應(yīng)的省份顏色會變成黃色,實現(xiàn)了一定程度的交互效果(虛擬機(jī)截圖關(guān)系,看不到鼠標(biāo)箭頭。。)。

查看網(wǎng)頁源代碼,看看地圖的HTML格式:

每一個path對應(yīng)一個省份,并且都在svg元素內(nèi)。

TopoJSON

使用上文提到的mapshaper網(wǎng)站,可以將GeoJSON文件轉(zhuǎn)為TopoJSON文件后導(dǎo)出。首先需要明確的一點是,我們使用D3雖然導(dǎo)入的是topojson文件,但D3通過將TopoJSON對象轉(zhuǎn)換為GeoJSON再繪制地圖,所以實質(zhì)還是使用GeoJSON對象繪制地圖,和上面的操作并不多少不同。我們主要來看看對象轉(zhuǎn)換過程:

d3.json("../geojson/china.topojson",function(error,toporoot){if(error)return console.error(error);//輸出china.topojson的對象console.log(toporoot);//將topoJSON對象轉(zhuǎn)換為GeoJSON,保存在georoot中//然而需要注意的是,實際上在繪制地圖時,還是使用了GeoJSON對象。//feature方法返回GeoJSON的特征(Feature)或特征集合(FeatureColleciton)var georoot = topojson.feature(toporoot,toporoot.objects.china);console.log(georoot);

后面繪制過程和使用GeoJSON并不差別,所以不貼代碼了。

那么為什么我們要使用TopoJSON呢,除了它文件相比GeoJSON會小很多外,它還能實現(xiàn)一些有趣的功能。
①合并地區(qū)

舉個例子,要將東南各省合并在一起用一個顏色表示,那么就可以使用topojson.merge( )方法來返回一個合并后的幾何體對象,并且其中只保存著我們所需要的幾個省的幾何信息。代碼如下:

var southeast = d3.set(["廣東", "海南", "福建", "浙江", "江西","江蘇", "臺灣", "上海", "香港", "澳門"]);//所有省份var georoot = topojson.feature(toporoot,toporoot.objects.china);//合并東南各省var mergePolygon = topojson.merge(toporoot, toporoot.objects.china.geometries.filter(function (d) {return southeast.has(d.properties.name); //只有集合中名字相稱的省份才會留下,其他會被filter過濾}));

在繪制的時候我們分兩步來繪制,一、繪制除東南各省外的其他省份;二、繪制東南各省,代碼如下:

//先不繪制選中的那幾塊svg.selectAll("path").data(georoot.features.filter(function(d){return !southeast.has(d.properties.name); //篩選掉東南各省,不繪制})).enter().append("path").attr("class","province").style("fill","#ccc").attr("d",path);//繪制東南各省svg.append("path").datum(mergePolygon).attr("class","province").style("fill","blue") //用藍(lán)色標(biāo)注.attr("d",path);

繪制后,看看結(jié)果:

效果不錯~

②繪制邊界線
假設(shè)我們現(xiàn)在需要用藍(lán)色標(biāo)注新疆的西藏的邊界,使其更加顯眼,那該怎么做呢,下面代碼展示了如何使用topojson做到邊界線的繪制:

d3.json("../geojson/china.topojson",function(error,toporoot){if(error)return console.log(error);//獲取西藏和新疆的邊界線var boundary = topojson.mesh(toporoot,toporoot.objects.china,function (a,b) {//經(jīng)嘗試發(fā)現(xiàn)a和b的取值存在順序關(guān)系,參數(shù)相反的話無法識別,所以正反條件都加上了return (a.properties.name ==="西藏" && b.properties.name ==="新疆")or (b.properties.name ==="西藏" && a.properties.name ==="新疆");});console.log(boundary);var georoot = topojson.feature(toporoot,toporoot.objects.china);//繪制整體地圖svg.selectAll("path").data(georoot.features).enter().append("path").attr("class","province").style("fill","#ccc").attr("d",path);//繪制特殊邊界線svg.append("path").datum(boundary) //boundary為topojson.mesh方法生成的幾何對象.attr("class","boundary").style("fill","none") //path如果不設(shè)置fill為none的話會自帶黑色填充,導(dǎo)致無法呈現(xiàn)為一條線.style("stroke","blue").style("stroke-width",3).attr("d",path);});

效果如圖:

③查找相鄰區(qū)域
TopoJSON除了可獲取兩省份的邊界線之外,還可以計算與一個省份相鄰的省份,需要用到topojson.neighbors( )方法,代碼如下:

d3.json("../geojson/china.topojson",function(error,toporoot){//通過topojson.neighbors計算所有省份的相鄰省份,保存在數(shù)組neighbors里//數(shù)組neighbors保存有各省份的鄰省序號var neighbors = topojson.neighbors(toporoot.objects.china.geometries);var georoot = topojson.feature(toporoot,toporoot.objects.china);paths = svg.selectAll("path").data(georoot.features).enter().append("path").style("fill","#ccc").attr("class","province").attr("d",path);console.log(paths);svg.selectAll("path").each(function (d,i) {//為每一個元素添加相鄰省份的選擇集d.neighbors = d3.selectAll(neighbors[i].map(function(j){ //使用map方法通過序號返回鄰省的path對象return paths[0][j];}));}).on("mouseover",function (d,i) {//鼠標(biāo)移入后,變色d3.select(this).style("fill","red");d.neighbors.style("fill","steelblue");}).on("mouseout",function(d,i){//鼠標(biāo)移出后,恢復(fù)原來的顏色d3.select(this).style("fill","#ccc");d.neighbors.style("fill","#ccc");}); });

效果如圖:

網(wǎng)格生成器

作為地圖,有時候需要我們添加經(jīng)緯線,我們可以使用網(wǎng)格生成器來繪制:

var width = 1000, height = 1000; var svg = d3.select("body").append("svg").attr("width", width).attr("height", height).append("g").attr("transform", "translate(0,0)");var eps = 1e-4; //防止網(wǎng)格沒有邊界線,不過因為我們是對中國區(qū)域畫網(wǎng)格,并不影響//創(chuàng)建一個經(jīng)緯度網(wǎng)格生成器,設(shè)置經(jīng)度和緯度范圍以及步長 var graticule = d3.geo.graticule().extent([[71,16],[137+eps,54]]).step([3,3]);//生成網(wǎng)格數(shù)據(jù) var grid = graticule(); var projection = d3.geo.mercator().center([107,31]).scale(800).translate([width/2,height/2]); var path = d3.geo.path().projection(projection);d3.json("../geojson/china.topojson",function(error,toporoot){if(error)return console.error(error);var georoot = topojson.feature(toporoot,toporoot.objects.china);svg.append("path").datum(grid).attr("class","graticule").style("stroke","steelblue").style("stroke-width","2").attr("d",path);svg.selectAll("path.province").data(georoot.features).enter().append("path").attr("class","province").attr("fill", "#ccc").style("stroke","steelblue").attr("d", path ); });

效果如下:

總結(jié)

地圖會成為我畢設(shè)后續(xù)代碼編寫的一塊主要內(nèi)容,通過這幾天的學(xué)習(xí)初步掌握了地圖繪制的方式,在以后的代碼編寫中再來鞏固。

轉(zhuǎn)載于:https://www.cnblogs.com/xiaoYu3328/p/6536036.html

總結(jié)

以上是生活随笔為你收集整理的D3学习之地图的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。