一、簡(jiǎn)介
Shp格式是GIS中非常重要的數(shù)據(jù)格式,主要在Arcgis中使用,但在進(jìn)行很多基于網(wǎng)頁(yè)的空間數(shù)據(jù)可視化時(shí),通常只接受GeoJSON格式的數(shù)據(jù),眾所周知JSON(JavaScript Object Nonation)是利用鍵值對(duì)+嵌套來(lái)表示數(shù)據(jù)的一種格式,以其輕量、易解析的優(yōu)點(diǎn),被廣泛使用與各種領(lǐng)域,而GeoJSON就是指在一套規(guī)定的語(yǔ)法規(guī)則下用JSON格式存儲(chǔ)矢量數(shù)據(jù),本文就將針對(duì)GeoJSON的語(yǔ)法規(guī)則,以及如何利用Python完成Shp格式到GeoJSON格式的轉(zhuǎn)換進(jìn)行介紹。
二、Shp轉(zhuǎn)GeoJSON
2.1 GeoJSON格式說(shuō)明
GeoJSON本質(zhì)依舊是JSON,其基本格式如下:
{
"type": "FeatureCollection",
"features": []
}
一個(gè)完整的GeoJSON文件最外層為一個(gè)字典,把整個(gè)GeoJSON文件看做自頂向下的樹(shù)狀結(jié)構(gòu)的話,其根目錄包含鍵值對(duì) "type":"FeaturesCollection" ,以及存放所有要素的鍵值對(duì) "features":[] ,所有矢量要素都存放在這個(gè)列表中,每個(gè)要素都是一個(gè)字典,下面我們來(lái)認(rèn)識(shí)一下各種矢量要素在GeoJSON中的規(guī)范格式:
點(diǎn)要素(Point):
對(duì)于單個(gè)點(diǎn)要素,其格式如下:
{"type":"Feature",
"properties":{value1,value2},
"geometry":{
"type":"Point",
"coordinates":[經(jīng)度,緯度]
}
}
其中properties對(duì)應(yīng)的值為這個(gè)要素對(duì)應(yīng)的屬性表中按順序存放的值,geometry對(duì)應(yīng)的值中type指明了要素類(lèi)型,coordinates傳入一個(gè)包含兩個(gè)元素的列表,第一個(gè)元素代表經(jīng)度,第二個(gè)元素代表緯度。
多點(diǎn)要素(MultiPoint):
多點(diǎn)要素是點(diǎn)要素的特殊情況,其geometry下的type屬性傳入"MultiPoint",其coordinates屬性傳入的是一個(gè)二維列表,其最內(nèi)層列表定義了每個(gè)點(diǎn)的經(jīng)緯度,如下:
{"type":"Feature",
"properties":{value1,value2},
"geometry":{
"type":"MultiPoint",
"coordinates":[[經(jīng)度1,緯度1],
[經(jīng)度2,緯度2]
]
}
}
線要素(LineString):
線要素記錄的是一條線上所有折點(diǎn)的經(jīng)緯度信息,只需要按順序連接這些折點(diǎn)就可以還原一條線的形態(tài),在GeoJSON中線要素與多點(diǎn)要素在coordinates屬性上格式相同,區(qū)別在于geometry屬性需要傳入"LineString",如下:
{"type":"Feature",
"properties":{value1,value2},
"geometry":{
"type":"LineString",
"coordinates":[[經(jīng)度1,緯度1],
[經(jīng)度2,緯度2],
[經(jīng)度3,緯度3],
[經(jīng)度4,,緯度4]]
}
}
多線要素(MultiLineString):
多線要素是多個(gè)線要素的組合,因此其coordinates傳入三維列表,來(lái)組合多條線,對(duì)應(yīng)的geometry下type屬性為"MultiLineString",如下:
{"type":"Feature",
"properties":{value1,value2},
"geometry":{
"type":"MultiLineString",
"coordinates":
[
[
[經(jīng)度1,緯度1],
[經(jīng)度2,緯度2],
[經(jīng)度3,緯度3],
[經(jīng)度4,緯度4]
],
[
[經(jīng)度5,緯度5],
[經(jīng)度6,緯度6]
]
]
}
}
多邊形要素(Polygon):
多邊形要素記錄了構(gòu)成一個(gè)多邊形所有邊緣折點(diǎn)的經(jīng)緯度信息,其coordinates屬性傳入"Polygon",其geometry下type屬性格式為三維列表,其第三層列表中嵌套的所有列表記錄的經(jīng)緯度按順序連接即構(gòu)成了一個(gè)多邊形,但需要注意的是,多邊形頭尾折點(diǎn)的經(jīng)緯度需要相同,才能構(gòu)成一個(gè)閉合的多邊形,如下:
{"type":"Feature",
"properties":{value1,value2},
"geometry":{
"type":"Polygon",
"coordinates":[
[
[經(jīng)度1,緯度1],
[經(jīng)度2,緯度2],
[經(jīng)度3,緯度3],
[經(jīng)度4,緯度4],
[經(jīng)度1,緯度1]
]
]
}
}
多多邊形要素(MultiPolygon):
多多邊形的格式為四維列表,其geometry下type屬性傳入"MultiPloygon",由于多多邊形要素中存在幾種特殊情況,下面我們?cè)趃eojson.io中進(jìn)行對(duì)應(yīng)GeoJSON數(shù)據(jù)的可視化以便于理解:
互不重疊的兩個(gè)多邊形:
下面是互不重疊的兩個(gè)多邊形的示例:?
對(duì)應(yīng)的GeoJSON數(shù)據(jù)如下:
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "MultiPolygon",
"coordinates":
[
[
[
[102.74414062499999,36.217687122250574],
[102.7001953125,35.585851593232356],
[104.8590087890625,35.496456056584165],
[104.96337890625,36.24427318493909],
[102.74414062499999,36.217687122250574]
]
],
[
[
[102.6397705078125,35.074964853989556],
[103.0352783203125,34.23905366851639],
[105.00732421875,34.24813554589752],
[105.3973388671875,35.77771427205079],
[104.556884765625,35.05698043137265],
[102.711181640625,35.16931803601131],
[102.6397705078125,35.074964853989556]
]
]
]
}
}
可以看到在多個(gè)多邊形不重疊時(shí),直接將兩個(gè)多邊形要素對(duì)應(yīng)的三維列表存放在最外層列表下即可。
互有重疊的兩個(gè)多邊形:
互有重疊的多個(gè)多邊形要素格式同多個(gè)不重疊的多邊形,效果如下:
對(duì)應(yīng)的GeoJSON數(shù)據(jù)如下:
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[101.6455078125,27.68352808378776],
[114.78515624999999,27.68352808378776],
[114.78515624999999, 35.209721645221386],
[101.6455078125,35.209721645221386],
[101.6455078125,27.68352808378776]
]
],
[
[
[104.2822265625,30.107117887092357],
[108.896484375,30.107117887092357],
[108.896484375,33.76088200086917],
[104.2822265625,33.76088200086917],
[104.2822265625,30.107117887092357]
]
]
]
}
}
有孔的多邊形:
有孔的多邊形在類(lèi)別上也是歸類(lèi)到MultiPolygon,下面是一個(gè)示例:
對(duì)應(yīng)的GeoJSON數(shù)據(jù)如下,可以看出其與多個(gè)重疊的多邊形的區(qū)別在于多邊形矢量信息嵌套在第二層列表中:
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "MultiPolygon",
"coordinates":
[
[
[
[101.6455078125,27.68352808378776],
[114.78515624999999,27.68352808378776],
[114.78515624999999,35.209721645221386],
[101.6455078125,35.209721645221386],
[101.6455078125,27.68352808378776]
],
[
[104.2822265625,30.107117887092357],
[108.896484375,30.107117887092357],
[108.896484375,33.76088200086917],
[104.2822265625,33.76088200086917],
[104.2822265625,30.107117887092357]
]
]
]
}
}
2.2 將Shp格式轉(zhuǎn)換為GeoJSON
在2.1中我們較為詳細(xì)的了解到矢量數(shù)據(jù)在GeoJSON數(shù)據(jù)中具體的表現(xiàn)形式,通過(guò)下面的自編函數(shù),以Shp文件名稱(去除文件拓展名)、Shp文件編碼、GeoJSON文件編碼為輸入?yún)?shù):
def Shp2JSON(filename,shp_encoding='utf-8',json_encoding='utf-8'):
'''
這個(gè)函數(shù)用于將shp文件轉(zhuǎn)換為GeoJSON文件
:param filename: shp文件對(duì)應(yīng)的文件名(去除文件拓展名)
:return:
'''
'''創(chuàng)建shp IO連接'''
reader = shapefile.Reader(filename,encoding=shp_encoding)
'''提取所有field部分內(nèi)容'''
fields = reader.fields[1:]
'''提取所有field的名稱'''
field_names = [field[0] for field in fields]
'''初始化要素列表'''
buffer = []
for sr in tqdm(reader.shapeRecords()):
'''提取每一個(gè)矢量對(duì)象對(duì)應(yīng)的屬性值'''
record = sr.record
'''屬性轉(zhuǎn)換為列表'''
record = [r.decode('gb2312','ignore') if isinstance(r, bytes)
else r for r in record]
'''對(duì)齊屬性與對(duì)應(yīng)數(shù)值的鍵值對(duì)'''
atr = dict(zip(field_names, record))
'''獲取當(dāng)前矢量對(duì)象的類(lèi)型及矢量信息'''
geom = sr.shape.__geo_interface__
'''向要素列表追加新對(duì)象'''
buffer.append(dict(type="Feature",
geometry=geom,
properties=atr))
'''寫(xiě)出GeoJSON文件'''
geojson = codecs.open(filename + "-geo.json","w", encoding=json_encoding)
geojson.write(json.dumps({"type":"FeatureCollection",
"features":buffer}) + '\n')
geojson.close()
print('轉(zhuǎn)換成功!')
下面我們通過(guò)一個(gè)示例來(lái)展示實(shí)際轉(zhuǎn)換效果,使用到的Shp數(shù)據(jù)為中國(guó)省份數(shù)據(jù),在arcgis中效果如下:
import shapefile
import json
import codecs
def Shp2JSON(filename,shp_encoding='utf-8',json_encoding='utf-8'):
'''
這個(gè)函數(shù)用于將shp文件轉(zhuǎn)換為GeoJSON文件
:param filename: shp文件對(duì)應(yīng)的文件名(去除文件拓展名)
:return:
'''
'''創(chuàng)建shp IO連接'''
reader = shapefile.Reader(filename,encoding=shp_encoding)
'''提取所有field部分內(nèi)容'''
fields = reader.fields[1:]
'''提取所有field的名稱'''
field_names = [field[0] for field in fields]
'''初始化要素列表'''
buffer = []
for sr in tqdm(reader.shapeRecords()):
'''提取每一個(gè)矢量對(duì)象對(duì)應(yīng)的屬性值'''
record = sr.record
'''屬性轉(zhuǎn)換為列表'''
record = [r.decode('gb2312','ignore') if isinstance(r, bytes)
else r for r in record]
'''對(duì)齊屬性與對(duì)應(yīng)數(shù)值的鍵值對(duì)'''
atr = dict(zip(field_names, record))
'''獲取當(dāng)前矢量對(duì)象的類(lèi)型及矢量信息'''
geom = sr.shape.__geo_interface__
'''向要素列表追加新對(duì)象'''
buffer.append(dict(type="Feature",
geometry=geom,
properties=atr))
'''寫(xiě)出GeoJSON文件'''
geojson = codecs.open(filename + "-geo.json","w", encoding=json_encoding)
geojson.write(json.dumps({"type":"FeatureCollection",
"features":buffer}) + '\n')
geojson.close()
print('轉(zhuǎn)換成功!')
if __name__ == '__main__':
import os
os.chdir(r'C:\Users\hp\Desktop\飛線圖素材')
Shp2JSON(filename='bou2_4p.shp',
shp_encoding='gbk',
json_encoding='utf-8')
運(yùn)行之后同一目錄下出現(xiàn)對(duì)應(yīng)的json文件:
?
導(dǎo)入到Kepler.gl中進(jìn)行可視化:
from keplergl import KeplerGl
import json
with open('bou2_4p.shp-geo.json') as b:
data = json.load(b)
map1 = KeplerGl(height=700,data={'layer1':data});map1
總結(jié)
以上所述是小編給大家介紹的利用Python實(shí)現(xiàn)Shp格式向GeoJSON的轉(zhuǎn)換方法 ,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺(jué)得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元

