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

文章目录

  • 强大的GeoPandas,几行代码实现点转线功能
    • 1、原料 Pandas、GeoPandas、Shapely
    • 2、点转线
    • 3、将结果保存为geojson文件
    • 4、点转线完整代码

强大的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,:]
FID Name State Speed Num Lng Lat
0 0 科技六路 3 10.0 0 108.888107 34.211662
1 1 科技六路 3 10.0 0 108.889725 34.211670
2 2 瞪羚路 2 15.0 1 108.856926 34.201595
3 3 瞪羚路 2 15.0 1 108.857033 34.201599
4 4 瞪羚路 2 15.0 1 108.859413 34.201637
5 5 瞪羚路 2 15.0 1 108.861893 34.201626
6 6 瞪羚路 2 15.0 1 108.863655 34.201611
7 7 瞪羚路 2 15.0 1 108.868385 34.201630
8 8 瞪羚路 2 15.0 1 108.869408 34.201630
9 9 瞪羚路 2 25.0 2 108.869408 34.201710
10 10 瞪羚路 2 25.0 2 108.869308 34.201710
11 11 瞪羚路 2 25.0 2 108.868408 34.201698
12 12 瞪羚路 2 25.0 2 108.863556 34.201675
13 13 瞪羚路 2 25.0 2 108.859413 34.201695
14 14 瞪羚路 2 25.0 2 108.857033 34.201706
15 15 瞪羚路 2 25.0 2 108.856926 34.201702
16 16 高新六路 2 25.0 3 108.877281 34.211655
17 17 高新六路 2 25.0 3 108.877281 34.211735
18 18 高新六路 2 25.0 3 108.877266 34.212143
19 19 高新六路 2 25.0 3 108.877274 34.214108
20 20 高新六路 2 25.0 3 108.877243 34.216526
21 21 高新六路 2 25.0 3 108.877243 34.220024
22 22 高新六路 2 25.0 3 108.877281 34.220097
23 23 高新四路 2 25.0 4 108.895088 34.235291
24 24 高新四路 2 25.0 4 108.895073 34.235027
25 25 高新四路 2 25.0 4 108.895088 34.232681
26 26 高新四路 2 25.0 4 108.895096 34.232456
27 27 高新四路 2 25.0 4 108.895058 34.231377
28 28 高新四路 2 25.0 4 108.895042 34.228569
29 29 高新四路 2 25.0 4 108.895042 34.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))

强大的GeoPandas,几行代码实现点转线功能_第1张图片

熟悉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,:]
FID Name State Speed Num geometry
0 0 科技六路 3 10.0 0 LINESTRING (108.888107 34.21166229999999, 108....
2 2 瞪羚路 2 15.0 1 LINESTRING (108.856926 34.2015953, 108.857033 ...
9 9 瞪羚路 2 25.0 2 LINESTRING (108.869408 34.2017097, 108.869308 ...
16 16 高新六路 2 25.0 3 LINESTRING (108.877281 34.2116547, 108.877281 ...
23 23 高新四路 2 25.0 4 LINESTRING (108.895088 34.2352905, 108.895073 ...
31 31 科技一路 2 20.0 5 LINESTRING (108.900749 34.2257996, 108.900589 ...
38 38 210国道 1 40.0 6 LINESTRING (108.781281 33.8055725, 108.781242 ...
2914 2914 210国道 1 45.0 7 LINESTRING (108.8955 34.19851679999999, 108.89...
3131 3131 太白南路 1 35.0 8 LINESTRING (108.895638 34.1985016, 108.89666 3...
3174 3174 丈八三路 1 30.0 9 LINESTRING (108.875626 34.1899567, 108.87558 3...
3180 3180 丈八三路 1 30.0 10 LINESTRING (108.875481 34.19846339999999, 108....
3187 3187 唐延南路 1 35.0 11 LINESTRING (108.881477 34.1797485, 108.881508 ...
3229 3229 唐延南路 1 35.0 12 LINESTRING (108.890282 34.19849779999999, 108....
3267 3267 丈八东路 1 35.0 13 LINESTRING (108.874435 34.2050018, 108.874565 ...
3339 3339 丈八东路 1 35.0 14 LINESTRING (108.945831 34.19813920000001, 108....
3408 3408 丈八六路 1 35.0 15 LINESTRING (108.855911 34.1825256, 108.855934 ...
3430 3430 丈八六路 1 40.0 16 LINESTRING (108.857033 34.2045937, 108.856934 ...
3451 3451 锦业路 1 35.0 17 LINESTRING (108.841652 34.1938324, 108.841728 ...
3482 3482 丈八五路 1 40.0 18 LINESTRING (108.864204 34.1888275, 108.86409 3...
3497 3497 丈八五路 1 35.0 19 LINESTRING (108.863541 34.20478060000001, 108....

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

##通过地图显示查看结果。
geoDataFrame.plot(figsize = (24, 24))

强大的GeoPandas,几行代码实现点转线功能_第2张图片

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()

你可能感兴趣的:(Python)