强大的GeoPandas,几行代码实现点转线功能

强大的GeoPandas,几行代码实现点转线功能

在GIS数据处理操作时,经常会用到点转线操作。一般ArcGIS、QGIS等等都会提供相应的工具。
这里提供一种利用Python实现点转线的方法。

1、原料 Pandas、GeoPandas、Shapely

Pandas及GeoPandas的强大之处,谁用谁知道
先来看以下点文件,格式是带经纬度坐标的csv文件。我们先用pandas将数据呈现出来。内容如下:

import pandas as pd
import geopandas as gpd
from shapely.geometry import LineString,Point

fp = r'E:\Dev\data\BigRoads31.csv'
df = pd.read_csv(fp)
df.iloc[:30,:]
FIDNameStateSpeedNumLngLat
00科技六路310.00108.88810734.211662
11科技六路310.00108.88972534.211670
22瞪羚路215.01108.85692634.201595
33瞪羚路215.01108.85703334.201599
44瞪羚路215.01108.85941334.201637
55瞪羚路215.01108.86189334.201626
66瞪羚路215.01108.86365534.201611
77瞪羚路215.01108.86838534.201630
88瞪羚路215.01108.86940834.201630
99瞪羚路225.02108.86940834.201710
1010瞪羚路225.02108.86930834.201710
1111瞪羚路225.02108.86840834.201698
1212瞪羚路225.02108.86355634.201675
1313瞪羚路225.02108.85941334.201695
1414瞪羚路225.02108.85703334.201706
1515瞪羚路225.02108.85692634.201702
1616高新六路225.03108.87728134.211655
1717高新六路225.03108.87728134.211735
1818高新六路225.03108.87726634.212143
1919高新六路225.03108.87727434.214108
2020高新六路225.03108.87724334.216526
2121高新六路225.03108.87724334.220024
2222高新六路225.03108.87728134.220097
2323高新四路225.04108.89508834.235291
2424高新四路225.04108.89507334.235027
2525高新四路225.04108.89508834.232681
2626高新四路225.04108.89509634.232456
2727高新四路225.04108.89505834.231377
2828高新四路225.04108.89504234.228569
2929高新四路225.04108.89504234.228458

可以看出,每一行代表一个点,每一行的最后两列为坐标。另外有两列是我们需要关注的,FID列是数据的自增ID,Num是一个编号。后面的点转线,将依据这两列。

用Geopandas将点打印出来,可以看到点的地理分布情况,如下图:

xy = [Point(xy) for xy in zip(df.Lng,df.Lat)]
pointDataFrame = gpd.GeoDataFrame(df,geometry=xy)
pointDataFrame.plot(figsize = (24, 24))
<matplotlib.axes._subplots.AxesSubplot at 0x1f5eeb3b390>

点转线

熟悉GIS矢量数据结构的人都知道,线是由点构成的,其在物理结构上表现的就是一连串有序排列的点。根据这一特征,我们来进行点转线操作。

2、点转线

有规则才成方圆,不,有规则才能连成线,通过查看上面的表,我们按照如下规则,将点转换为线:
1、num值相同的点,合并成一根线段;
2、线段上的点的排列顺序,按照其在表中的排列顺序FID
转换过程如下:

#分组
dataGroup = df.groupby('Num')

#构造数据
tb = []
geomList = []
for name,group in dataGroup:
    # 分离出属性信息,取每组的第1行前5列作为数据属性
    tb.append(group.iloc[0,:5])
    # 把同一组的点打包到一个list中
    xyList = [xy for xy in zip(group.Lng, group.Lat)]
    
    line = LineString(xyList)
    geomList.append(line)

# 点转线
geoDataFrame = gpd.GeoDataFrame(tb, geometry = geomList)

我们打印下结果看看

geoDataFrame.iloc[:20,:]
FIDNameStateSpeedNumgeometry
00科技六路310.00LINESTRING (108.888107 34.21166229999999, 108....
22瞪羚路215.01LINESTRING (108.856926 34.2015953, 108.857033 ...
99瞪羚路225.02LINESTRING (108.869408 34.2017097, 108.869308 ...
1616高新六路225.03LINESTRING (108.877281 34.2116547, 108.877281 ...
2323高新四路225.04LINESTRING (108.895088 34.2352905, 108.895073 ...
3131科技一路220.05LINESTRING (108.900749 34.2257996, 108.900589 ...
3838210国道140.06LINESTRING (108.781281 33.8055725, 108.781242 ...
29142914210国道145.07LINESTRING (108.8955 34.19851679999999, 108.89...
31313131太白南路135.08LINESTRING (108.895638 34.1985016, 108.89666 3...
31743174丈八三路130.09LINESTRING (108.875626 34.1899567, 108.87558 3...
31803180丈八三路130.010LINESTRING (108.875481 34.19846339999999, 108....
31873187唐延南路135.011LINESTRING (108.881477 34.1797485, 108.881508 ...
32293229唐延南路135.012LINESTRING (108.890282 34.19849779999999, 108....
32673267丈八东路135.013LINESTRING (108.874435 34.2050018, 108.874565 ...
33393339丈八东路135.014LINESTRING (108.945831 34.19813920000001, 108....
34083408丈八六路135.015LINESTRING (108.855911 34.1825256, 108.855934 ...
34303430丈八六路140.016LINESTRING (108.857033 34.2045937, 108.856934 ...
34513451锦业路135.017LINESTRING (108.841652 34.1938324, 108.841728 ...
34823482丈八五路140.018LINESTRING (108.864204 34.1888275, 108.86409 3...
34973497丈八五路135.019LINESTRING (108.863541 34.20478060000001, 108....

可以看到,数据已经按Num分组,并合并成了一个LineString对象。

##通过地图显示查看结果。
geoDataFrame.plot(figsize = (24, 24))
<matplotlib.axes._subplots.AxesSubplot at 0x1f5ecc0bc18>

线结果

3、将结果保存为geojson文件

1)保存为geojson,两种方法

# 方法一 
fp = r"E:\Dev\data\lineRoads.geojson"
geoDataFrame.to_file(fp, driver='GeoJSON', encoding="utf-8")

#方法二
json = geoDataFrame.to_json()
with open(fp,'w') as f:
    f.write(json)

2)保存为shp

shp = r"E:\Dev\data\lineRoads.shp"
geoDataFrame.to_file(shp,driver="ESRI Shapefile",encoding="utf-8")

4、点转线完整代码

刨除上面的一些测试验证代码,仅仅几行即可实现点转线功能。Good!!!

import pandas as pd
import geopandas as gpd
from shapely.geometry import LineString,Point


def main():
    fp = r'E:\Dev\data\BigRoads31.csv'
    df = pd.read_csv(fp)

    #分组
    dataGroup = df.groupby('Num')

    #构造数据
    tb = []
    geomList = []
    for name,group in dataGroup:
        # 分离出属性信息,取每组的第1行前5列作为数据属性
        tb.append(group.iloc[0,:5])
        # 把同一组的点打包到一个list中
        xyList = [xy for xy in zip(group.Lng, group.Lat)]

        line = LineString(xyList)
        geomList.append(line)

    # 点转线
    geoDataFrame = gpd.GeoDataFrame(tb, geometry = geomList)

    fp = r"E:\Dev\data\lineRoads.geojson"
    geoDataFrame.to_file(fp, driver='GeoJSON', encoding="utf-8")

if __name__ == '__main__':
    main()
  • 12
    点赞
  • 78
    收藏
    觉得还不错? 一键收藏
  • 23
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值