数据, 术→技巧

中国行政区划边界GeoJSON数据

钱魏Way · · 7,387 次浏览

行政区划相关信息在GIS中算是不可或缺的基础数据,然而由于行政区划经常会进行调整,所以许多网上搜集的已经存在了不同程度的过时。国外的数据,又会有领土的问题。DataV是阿里云出品的拖拽式可视化工具,专精于业务数据与地理信息融合的大数据可视化。阿里同时也提供的相应的GeoJSON数据供使用。

GeoJSON简介

GeoJSON是一种基于JSON的地理空间数据交换格式,它定义了几种类型JSON对象以及它们组合在一起的方法,以表示有关地理要素、属性和它们的空间范围的数据。2015年,互联网工程任务组(IETF)与原始规范作者组建了一个GeoJSON工作组,一起规范GeoJSON标准。在2016年8月,推出了最新的GeoJSON数据格式标准规范(RFC 7946)。GeoJSON使用唯一地理坐标参考系统WGS1984和十进制度单位,一个GeoJSON对象可以是Geometry, Feature或者FeatureCollection.

其几何对象包括有点(表示地理位置)、线(表示街道、公路、边界)、多边形(表示国家、省、领土),以及由以上类型组合成的复合几何图形。TopoJSON基于GeoJSON作了扩展,使得文件更小。

基本几何图形:

类型 图形 数据
{
“type”: “Point”,
“coordinates”: [30, 10]
}
线段 {
“type”: “LineString”,
“coordinates”: [[30, 10], [10, 30], [40, 40]]
}
多边形 {
“type”: “Polygon”,
“coordinates”: [[[30, 10], [40, 40], [20, 40], [10, 20], [30, 10]]]
}
{
“type”: “Polygon”,
“coordinates”: [
[[35, 10], [45, 45], [15, 40], [10, 20], [35, 10]],
[[20, 30], [35, 35], [30, 20], [20, 30]]
]
}

复合集合图形:

类型 图形 数据
{
“type”: “MultiPoint”,
“coordinates”: [
[10, 40], [40, 30], [20, 20], [30, 10]
]
}
线段 {
“type”: “MultiLineString”,
“coordinates”: [
[[10, 10], [20, 20], [10, 40]],
[[40, 40], [30, 30], [40, 20], [30, 10]]
]
}
多边形 {
“type”: “MultiPolygon”,
“coordinates”: [
[
[[30, 20], [45, 40], [10, 40], [30, 20]]
],
[
[[15, 5], [40, 10], [10, 20], [5, 10], [15, 5]]
]
]
}
{
“type”: “MultiPolygon”,
“coordinates”: [
[
[[40, 40], [20, 45], [45, 30], [40, 40]]
],
[
[[20, 35], [10, 30], [10, 10], [30, 5], [45, 20], [20, 35]],
[[30, 20], [20, 15], [20, 25], [30, 20]]
]
]
}

GeoJson可通过geojson.io转换为shp、csv、kml等格式。

GeoJSON数据提取

使用GeoJSON行政区划边界提取小工具DataV.GeoAtlas,最低可以提取区县级边界数据,区域adcode可以查阅省市区adcode与经纬度映射表,提取方法如下。

  • 省级:区域热力层默认显示为全国范围内,各个省和直辖市区域热力层数据,可以直接使用。
  • 地市级:以提取浙江省范围内所有地级市边界数据为例,提取方法如下图所示。
  • 区县级:以提取肇庆市范围内所有区县边界数据为例,提取方法如下图所示。
  • 乡镇街道及自定义区域:乡镇街道数据需要用户自己获取。根据需要自定义区域边界,如中国大陆可以分为东部地区、西部地区、华南地区、华北地区、华中地区五大区,可以根据对应包含的省级边界数据合并得到。

Python抓取程序:

import requests
import os


def get_json(save_dir, adcode):
    # 获取当前地图轮廓
    base_url = 'https://geo.datav.aliyun.com/areas/bound/' + str(adcode) + '.json'
    full_url = 'https://geo.datav.aliyun.com/areas/bound/' + str(adcode) + '_full.json'
    base_r = requests.get(base_url)
    if base_r.status_code == 200:
        cur_obj_name = base_r.json()['features'][0]['properties']['name']
        print(cur_obj_name)
        cur_file_dir = os.path.join(save_dir, cur_obj_name)
        if not os.path.exists(cur_file_dir):
            os.mkdir(cur_file_dir)
        base_json_file = os.path.join(cur_file_dir, str(adcode) + '.json')
        with open(base_json_file, 'w') as file:
            file.write(base_r.text)
    # 获取当前地图子地图轮廓
    full_r = requests.get(full_url)
    if full_r.status_code == 200 and 'cur_obj_name' in vars():
        full_json_file = os.path.join(cur_file_dir, str(adcode) + '_full.json')
        with open(full_json_file, 'w') as file:
            file.write(full_r.text)
        for item in full_r.json()['features']:
            chadcode = item['properties']['adcode']
            if chadcode == adcode:
                pass
            else:
                get_json(cur_file_dir, chadcode)


if __name__ == "__main__":
    get_json('D:\\DataV', 100000)

在GeoPandas中使用GeoJson数据

绘制含有九段线的中国地图:

import geopandas as gpd
import matplotlib.pyplot as plt

gdf = gpd.read_file("100000_full.json",encoding='utf-8')
gdf.plot()
plt.show()

如果出现如下错误:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-13-6be42f4feb94> in <module>
----> 1 gdf = gpd.read_file("100000_full.json",encoding='gbk')
      2 gdf.plot()
      3 plt.show()

D:\ProgramData\Anaconda3\lib\site-packages\geopandas\io\file.py in read_file(filename, bbox, **kwargs)
     93 
     94             columns = list(features.meta["schema"]["properties"]) + ["geometry"]
---> 95             gdf = GeoDataFrame.from_features(f_filt, crs=crs, columns=columns)
     96 
     97     return gdf

D:\ProgramData\Anaconda3\lib\site-packages\geopandas\geodataframe.py in from_features(cls, features, crs, columns)
    281 
    282         rows = []
--> 283         for f in features_lst:
    284             if hasattr(f, "__geo_interface__"):
    285                 f = f.__geo_interface__

fiona/ogrext.pyx in fiona.ogrext.Iterator.__next__()

fiona/ogrext.pyx in fiona.ogrext.FeatureBuilder.build()

TypeError: startswith first arg must be bytes or a tuple of bytes, not str

导致原因是Windows环境下,文件被保存为ANSI编码了,解决方案是将其修改为UTF-8编码。

其他链接:

  • https://lbs.amap.com/api/javascript-api/example/district-search/draw-district-boundaries/
  • http://lbsyun.baidu.com/jsdemo.htm#c1_10
  • https://lbs.amap.com/api/javascript-api/guide/services/district-search
  • https://gallery.echartsjs.com/editor.html?c=xr1IEt3r4Q

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注