【数据处理】高德地图路径规划数据转存shp以及json转geojson介绍

 

大家好,我是小白鸽,上一期文章挖了一个坑,留了两个问题,分别是如何把json转为GeoJSON以及如何把高德路径规划结果转存成矢量数据,本期我们就来详细说说这两个问题。

其实要解决这两个问题的方法挺多的,但是进行数据分析首先要做的应该是分析数据结构,我们先来看一下路径规划返回的结果示例。

{
  "status" :"1",
  "info" :"ok",
  "infocode" :"10000",
  "count" :"1",
  "route" :{
    "origin" :"116.481028,39.989643",
    "destination" :"116.434446,39.90816",
    "paths" :[
      "0" :{
        "distance" :"11068",
        "duration" :"8854",
        "steps" :[
          "0" :{
            "instruction" :"向南步行16米左转",
            "orientation" :"南",
            "road" :[ ],
            "distance" :"16",
            "duration" :"13",
            "polyline" :"116.480885,39.989371;116.480907,39.989353;116.48089,39.989227",
            "action" :"左转",
            "assistant_action" :[ ],
            "walk_type" :"0"
          },
          "1" :{
            "instruction" :"步行292米右转",
            "orientation" :[ ],
            "road" :[ ],
            "distance" :"292",
            "duration" :"234",
            "polyline" :"116.480885,39.989223;116.480933,39.989201;116.480933,39.989201;116.480955,39.989184;116.481155,39.989058;116.481155,39.989058;116.481428,39.98888;116.481428,39.98888;116.481489,39.988841;116.481489,39.988841;116.482574,39.988125;116.48322,39.987665;116.48322,39.987665;116.48332,39.987565;116.48332,39.987565;116.48342,39.987435",
            "action" :"右转",
            "assistant_action" :[ ],
            "walk_type" :"0"
          }
        ]
      }
    ]
  }
}

其实,如果数据量不大,可以手动存成表格数据,再通过ArcGis转存成矢量数据。

e4b73249a89d42079377a12f6e368c68.png

那如果数据量很大呢?假设我们有20000个村采集的数据需要转存成矢量数据,那要一个个手动填吗?

 

6eba41ff2f2b1f89cb18dba02194ca03.jpeg

大可不必,可以看到路径规划返回的结果是一个json对象,我们本期的目标是把steps里面的内容解析出来,steps里面的其实是一个json对象数组,数组里面每一个元素都是json对象。json数据是以键值对的形式组织数据,每个键值对由一个键(key)和一个值(value)组成,它们之间用冒号 : 分隔。例如:

#name是键,John Doe是值{  "name": "John Doe"}

因此对于复杂的json对象也可以通过逐级索引的方式获取目标数据。以下是一个示例:

import json

# 假设这是你的JSON字符串
your_json_string = '''
{
  "person": {
    "name": "John Doe",
    "age": 30,
    "address": {
      "street": "123 Main St",
      "city": "Anytown",
      "zipCode": "12345"
    },
    "phoneNumbers": [
      {
        "type": "home",
        "number": "212 555-1234"
      },
      {
        "type": "office",
        "number": "212 555-4567"
      }
    ]
  }
}
'''

# 解析JSON字符串
json_data = json.loads(your_json_string)

# 逐层索引以获取办公室电话号码
office_number = json_data["person"]["phoneNumbers"][1]["number"]

print(office_number)  # 输出: 212 555-4567

获取到目标数据只是第一步,开头说了要把数据转换成GeoJSON,以及转存矢量数据,本文在此介绍3个python库(模块),分别是arcpy、geojson和geopandas,其中arcpy库和geopandas库都可以实现将结果数据直接转存成矢量数据,geojson库则可以实现将结果数据转换成GeoJSON格式,并且可以进一步结合geopandas库将GeoJSON格式数据转存成矢量数据。

 

b8d696f9de252688b6ada9a9a338f9a9.png

 

    利用arcpy转存矢量数据

arcpy其实是一个python库,通过引用(import)arcpy,可以让我们在python中使用arcgis的空间分析和数据管理等能力,相当于在python中使用ArcGis。本文在此只做简要介绍,以后将会开个专栏讲arcpy的使用以及如何利用arcpy去处理一些日常遇到的问题。

c8cbb4ef836a46028b2b2cd75d6d1dde.png

官方介绍请查阅:

https://desktop.arcgis.com/zh-cn/arcmap/latest/analyze/arcpy/what-is-arcpy-.htm

以下是利用arcpy将路径规划结果中的分段数据转存成矢量数据的示例:

import requests
import json
import arcpy

key = '你的高德地图api key'
#起点经纬度
origin = '116.481028,39.989643'
#终点经纬度
destination = '116.434446,39.90816'
#拼接url,上一期输出是xml格式,本期尝试输出json格式
url = 'https://restapi.amap.com/v3/direction/walking?origin='+ origin +'&destination='+ destination +'&key=' + key +'&output=JSON'
#请求url
responce = requests.get(url)
#获取返回内容
str = responce.content
#将返回的字符串转换为json对象
jstr = json.loads(str)
#定位到steps里面的内容
steps = jstr['route']['paths'][0]['steps']
#创建空list存数据
distance,duration,linestr,road = [],[],[],[]
#读取steps里面每一段路径的信息,包括distance、duration、road和polyline
for step in steps:
    distance.append(step['distance'])
    duration.append(step['duration'])
    linestr.append(step['polyline'])
    road.append(step['road'])

path="你的文件输出路径"
#输出可以是XXXX.shp
outputname="你的输出文件名称"
#设置空间参考,一般为4326,即wgs84
spatR = arcpy.SpatialReference(4326)
#创建一个空的线要素
line = arcpy.CreateFeatureclass_management(path, outputname,'POLYLINE',"","","",spatR)
#给shp添加字段属性,包括distance,duration,road
arcpy.AddField_management(line,'distance','Short Integer')
arcpy.AddField_management(line,'duration','Short Integer')
arcpy.AddField_management(line,"road",'Text')
fields =['SHAPE@',"distance", "duration", "road"]
#创建游标,arcpy对数据的操作通过游标进行
cur = arcpy.InsertCursor(line)
#通过循环对数据进行操作
for i in range(0,len(linestr)):
    #准备好属性数据,实际上如果熟练可以把该循环整合到上一个循环
    distance_ = distance[i]
    duration_ = duration[i]
    road_ = road[i]
    #获取单挑线段的坐标集合
    line = linestr[i]
    #获取该坐标集合中所有的点
    pnts = line.split(';')
    #创建空的array
    array = arcpy.Array()
    #对坐标集合中的点进行遍历,创建Point,并添加到array中,形成符合arcgis格式要求的点集
    for pnt in pnts:
        pnt_ = pnt.split(',')
        lon = pnt_[0]
        lat = pnt_[1]
        point = arcpy.Point(lon,lat)
        array.add(point)
    #根据点集创建Polyline线
    polyline = arcpy.Polyline(array,spatR)
    #清空array,为下一轮循环做准备
    array.removeAll()
    #根据上面的fields格式要求创建newFields并添加到原来的fields中
    newFields = [polyline,distance_,duration_,road_]
    cur.insertRow(newFields)
del cur

    利用geopandas转存矢量数据

geopandas也是一个python库,它是对pandas库的扩展,通过geopandas也可以进行空间分析和数据处理,与arcpy不同的是,不需要安装ArcGis就可以使用这些空间分析能力,它的易用性更好。

 

44919ba7c905b9494dd2e8511dc17d0c.png

官方介绍请查阅:

https://desktop.arcgis.com/zh-cn/arcmap/latest/analyze/arcpy/what-is-arcpy-.htm

以下是利用geopandas将路径规划结果中的分段数据转存成矢量数据的示例:

import requests
import json
from shapely.geometry import  LineString;
from geopandas import GeoSeries,GeoDataFrame
key = '你的高德地图api key'
#起点经纬度
origin = '116.481028,39.989643'
#终点经纬度
destination = '116.434446,39.90816'
#拼接url,上一期输出是xml格式,本期尝试输出json格式
url = 'https://restapi.amap.com/v3/direction/walking?origin='+ origin +'&destination='+ destination +'&key=' + key +'&output=JSON'
#请求url
responce = requests.get(url)
#获取返回内容
str = responce.content
#将返回的字符串转换为json对象
jstr = json.loads(str)
#定位到steps里面的内容
steps = jstr['route']['paths'][0]['steps']
#创建空list存数据
distance,duration,polyline,road = [],[],[],[]
#读取steps里面每一段路径的信息,包括distance、duration、road和polyline
for step in steps:
    distance.append(step['distance'])
    duration.append(step['duration'])
    polyline.append(step['polyline'])
    road.append(step['road'])
#创建一个空的GeoSeries
g = GeoSeries()
#通过循环向GeoSeries中添加数据
for i in range(0,len(polyline)):
    line = polyline[i]
    newstr = line.split(';')
    location_tuples = [tuple(map(float, loc.split(','))) for loc in newstr]
    pl = LineString(location_tuples)
    new_geoseries = GeoSeries(pl)
    g = pd.concat([g, new_geoseries])
#为避免出错,重置一下索引
g.reset_index(drop=True,inplace=True)
#将数据组装成GeoDataFrame,其中{'distance' :distance,'duration': duration,'road': road}代表属性信息,geometry=g代表空间信息,crs='epsg:4326'代表投影信息
gdf = GeoDataFrame({'distance' :distance,'duration': duration,'road': road}, geometry=g,crs='epsg:4326')
#保存成shp
gdf.to_file('line.shp')

    结合geojson和geopandas转存矢量数据

geojson是python的一个模块,geojson模块支持GeoJSON标准定义的所有数据结构,包括几何对象(点、线、多边形等)、特征、特征集合和坐标参考系统。该模块提供了函数来解析和序列化GeoJSON数据,包括从字符串和文件中解析GeoJSON数据,以及将Python对象序列化为GeoJSON字符串或写入文件。

422fdecd220643089892029d4a87d4b6.png

结合geojson和geopandas的处理方式分两步,第一步是将结果数据转换成GeoJSON格式,第二步是将GeoJSON格式数据转存成矢量数据。第一步时可以根据需求将多条线段转换成一个多段线要素(MultiLineString),也可以转换成多个线要素(LineString)。

MultiLineString和LineString的区别在于,MultiLineString一条记录可以对应多条线,LineString一条记录只对应一条线。

 

5aa528e0ab03c1a02edbcced28ade593.png

 

  • 转换成一个多段线要素示例:

import requests
import json
import geojson
key = '你的高德地图api key'
#起点经纬度
origin = '116.481028,39.989643'
#终点经纬度
destination = '116.434446,39.90816'
#拼接url,上一期输出是xml格式,本期尝试输出json格式
url = 'https://restapi.amap.com/v3/direction/walking?origin='+ origin +'&destination='+ destination +'&key=' + key +'&output=JSON'
#请求url
responce = requests.get(url)
#获取返回内容
str = responce.content
#将返回的字符串转换为json对象
jstr = json.loads(str)
#定位到steps里面的内容
steps = jstr['route']['paths'][0]['steps']
#创建空list存数据
distance,duration,polyline,road = [],[],[],[]
#读取steps里面每一段路径的信息,包括distance、duration、road和polyline
for step in steps:
    distance.append(step['distance'])
    duration.append(step['duration'])
    polyline.append(step['polyline'])
    road.append(step['road'])

line_list = []
#数据清洗,重新组织数据格式
for line in polyline:
    newstr = line.split(';')
    location_tuples = [tuple(map(float, loc.split(','))) for loc in newstr]
    line_list.append(location_tuples)
#创建MultiLineString
MultiLineString_geojson = geojson.MultiLineString(coordinates=line_list)
#创建FeatureCollection
Multi_feature_collection = geojson.FeatureCollection(features=[geojson.Feature(geometry=MultiLineString_geojson)])
#添加属性示例 属性名称name,属性值OD_name
Multi_feature_collection['features'][0]['properties']['name'] = 'OD_name'
#尝试打印
print(geojson.dumps(Multi_feature_collection, indent=2))
  • 转换成多个线要素示例

 

import requests
import json
import geojson
key = '你的高德地图api key'
#起点经纬度
origin = '116.481028,39.989643'
#终点经纬度
destination = '116.434446,39.90816'
#拼接url,上一期输出是xml格式,本期尝试输出json格式
url = 'https://restapi.amap.com/v3/direction/walking?origin='+ origin +'&destination='+ destination +'&key=' + key +'&output=JSON'
#请求url
responce = requests.get(url)
#获取返回内容
str = responce.content
#将返回的字符串转换为json对象
jstr = json.loads(str)
#定位到steps里面的内容
steps = jstr['route']['paths'][0]['steps']
#创建空list存数据
distance,duration,polyline,road = [],[],[],[]
#读取steps里面每一段路径的信息,包括distance、duration、road和polyline
for step in steps:
    distance.append(step['distance'])
    duration.append(step['duration'])
    polyline.append(step['polyline'])
    road.append(step['road'])

#创建一个空的LineString和FeatureCollection,用于存放后续数据
totalLineString_geojson = geojson.LineString()
total_feature_collection = geojson.FeatureCollection(features=[geojson.Feature(geometry=totalLineString_geojson)])
#通过循环将steps中每一段路径都转换成Feature,并添加进空的FeatureCollection
for i in range(0,len(polyline)):
    line = polyline[i]
    newstr = line.split(';')
    location_tuples = [tuple(map(float, loc.split(','))) for loc in newstr]
    one_LineString_geojson = geojson.LineString(coordinates=location_tuples)
    one_feature = geojson.Feature(geometry=one_LineString_geojson)
    #为每一段路径添加属性
    one_feature['properties']['distance'] = distance[i]
    one_feature['properties']['duration'] = duration[i]
    one_feature['properties']['road'] = road[i]
    #添加进FeatureCollection
    total_feature_collection['features'].append(one_feature)
#删除最初始的空feature
total_feature_collection['features'].remove(total_feature_collection['features'][0])
#尝试打印
print(geojson.dumps(total_feature_collection, indent=2))
  • 在上述代码基础上,只需如下代码即可将数据转存为矢量数据

#引用geopandas
import geopandas
# total_feature_collection 上一步生成的FeatureCollection
#将FeatureCollection转换成GeoDataFrame
#crs='epsg:4326'设置坐标为wgs84,最好提前进行坐标转换
total_gdf = geopandas.GeoDataFrame.from_features(total_feature_collection,crs='epsg:4326')
#重置一下索引
total_gdf.reset_index(drop=True,inplace=True)
#保存成line.shp
total_gdf.to_file('line.shp')

     结果展示

25bb119de7674ee09b231e5dd4e3f365.png

 

最后,其实数据处理的方法有很多,实现同一个目标也有多种不同的路径,最主要的是根据实际的需求选择适合自己的方法。本期分享就到此结束,我是小白鸽,欢迎大家点赞关注,欢迎评论交流。

 

663b7574c1da0100415f8f56be72e525.jpeg

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值