本文介绍一个强大的Python GIS工具库,涵盖10+个高频使用场景,从距离计算到空间分析,开箱即用,上手简单!
📌 前言
做地理空间数据处理时,经常要处理经纬度、距离计算、缓冲区分析、图层匹配 等繁琐工作。TableGIS 就是为了简化这些操作而生,它基于 GeoPandas 和 Shapely,提供了一套开箱即用的高效工具。
本文通过10个真实场景的代码案例,让你快速掌握这个库的精髓。
🚀 5分钟快速安装
bash
pip install tablegis
导入使用:
python
import pandas as pd
import tablegis as tg
📊 核心功能速览
| 功能模块 | 主要方法 | 应用场景 |
|---|---|---|
| 📍 距离计算 | min_distance_twotable(), distancea_str() |
找最近的门店、配送路由 |
| 🗺️ 空间分析 | add_buffer(), add_sectors(), add_polygon() |
服务范围、风险评估 |
| 📐 几何操作 | polygon_centroid(), add_area(), add_length() |
面积统计、距离测量 |
| 🔗 数据转换 | df_to_gdf(), points_coverage_merge() |
格式互转、属性关联 |
💡 10个实战案例
案例1:找最近的配送点
场景:有100个待送达的订单位置和50个配送站,需要为每个订单找最近的3个配送站。
python
import pandas as pd
import tablegis as tg
# 订单数据
orders = pd.DataFrame({
'order_id': ['O001', 'O002', 'O003'],
'lon': [116.404, 116.405, 116.406],
'lat': [39.915, 39.916, 39.917]
})
# 配送站数据
stations = pd.DataFrame({
'station_id': ['S001', 'S002', 'S003', 'S004'],
'lon': [116.403, 116.407, 116.404, 116.408],
'lat': [39.914, 39.918, 39.916, 39.919]
})
# 找最近的3个配送站,返回id、坐标、距离
result = tg.min_distance_twotable(
orders, stations,
lon1='lon', lat1='lat',
lon2='lon', lat2='lat',
df2_id='station_id',
n=3 # 找3个最近的
)
print(result[['order_id', 'nearest1_station_id', 'nearest1_distance',
'nearest2_station_id', 'nearest2_distance',
'nearest3_station_id', 'nearest3_distance']])
# 输出示例:
# order_id nearest1_station_id nearest1_distance nearest2_station_id nearest2_distance
# O001 S001 1200.5 S003 3400.2
✨ 优势:
- 自动处理坐标转换,精度到米
- 返回所有信息,无需二次查询
- 支持任意数量的邻近点查询
案例2:计算两点间直线距离
场景:快递员要去某个地址取货,需要知道当前位置到目的地有多远。
python
import tablegis as tg
# 快递员当前位置
current_lon, current_lat = 116.404, 39.915
# 目的地位置
dest_lon, dest_lat = 116.407, 39.920
# 计算距离(单位:米)
distance = tg.distancea_str(current_lon, current_lat, dest_lon, dest_lat)
print(f"距离:{distance:.0f} 米,约 {distance/1000:.2f} 公里")
# 输出:距离:625 米,约 0.62 公里
✨ 特点:
- 使用Haversine公式,精确到米
- 自动处理角度转弧度
- 参数验证,防止坐标输入错误
案例3:批量计算DataFrame内任意两列坐标的距离
场景:有用户当前位置和店铺位置两组坐标,需要计算每个用户到对应店铺的距离。
python
import pandas as pd
import tablegis as tg
# 用户数据(当前位置 vs 目标店铺)
df = pd.DataFrame({
'user_id': ['U001', 'U002', 'U003'],
'user_lon': [116.404, 116.405, 116.406],
'user_lat': [39.915, 39.916, 39.917],
'shop_lon': [116.407, 116.408, 116.409],
'shop_lat': [39.918, 39.919, 39.920]
})
# 一行代码计算距离
result = tg.distancea_df(
df,
lon_1='user_lon', lat_1='user_lat',
lon_2='shop_lon', lat_2='shop_lat',
columns_name='到店距离'
)
print(result[['user_id', '到店距离']])
# user_id 到店距离
# U001 3335.5
# U002 3335.5
✨ 优点:
- 向量化计算,处理百万级数据无压力
- 自动添加列,无需手动赋值
案例4:创建服务覆盖区域(缓冲区)
场景:医院周边1000米是其服务范围,需要为每个医院创建缓冲区。
python
import pandas as pd
import tablegis as tg
# 医院数据
hospitals = pd.DataFrame({
'hospital_id': ['H001', 'H002'],
'lon': [116.404, 116.407],
'lat': [39.915, 39.918],
'coverage_meter': [1000, 1500] # 覆盖范围(米)
})
# 创建缓冲区,自动处理坐标系转换
result_gdf = tg.add_buffer(
hospitals,
lon='lon', lat='lat',
dis='coverage_meter', # 指定距离列
geometry='buffer_zone'
)
print(result_gdf)
print(f"缓冲区面积:{result_gdf['buffer_zone'].area.values[0]:.0f} 平方米")
✨ 精妙之处:
- 自动检测坐标,选择最优UTM投影
- 输入单位为米,计算精准
- 返回GeoDataFrame,可直接导出为Shapefile或GeoJSON
案例5:计算多边形的质心
场景:有若干个社区的边界多边形,需要找到每个社区的中心点(用于地图展示)。
python
import geopandas as gpd
import pandas as pd
import tablegis as tg
from shapely.geometry import Polygon
# 创建社区多边形数据
gdf = gpd.GeoDataFrame({
'community_id': ['C001', 'C002'],
'geometry': [
Polygon([(116.404, 39.915), (116.407, 39.915), (116.407, 39.918), (116.404, 39.918)]),
Polygon([(116.410, 39.920), (116.413, 39.920), (116.413, 39.923), (116.410, 39.923)])
]
})
# 计算质心
centroids = tg.polygon_centroid(gdf)
# 添加质心坐标到原数据
gdf['center_lon'] = centroids[0]
gdf['center_lat'] = centroids[1]
print(gdf[['community_id', 'center_lon', 'center_lat']])
# community_id center_lon center_lat
# C001 116.4055 39.9165
# C002 116.4115 39.9215
✨ 应用:
- 用于地图聚类展示
- 计算分布密度
- 快速定位感兴趣区域
案例6:计算多边形面积
场景:地产公司有100个地块的边界,需要计算每个地块的面积用于定价。
python
import geopandas as gpd
import tablegis as tg
from shapely.geometry import Polygon
# 地块数据
gdf = gpd.GeoDataFrame({
'plot_id': ['P001', 'P002'],
'geometry': [
Polygon([(116.400, 39.910), (116.410, 39.910), (116.410, 39.920), (116.400, 39.920)]),
Polygon([(116.420, 39.930), (116.430, 39.930), (116.430, 39.940), (116.420, 39.940)])
]
}, crs='EPSG:4326')
# 计算面积(自动进行投影转换)
result = tg.add_area(gdf, column='面积_平方米')
print(result[['plot_id', '面积_平方米']])
# plot_id 面积_平方米
# P001 11123400
# P002 11123400
✨ 技术细节:
- 自动选择最优UTM投影
- 避免地理坐标系下的面积误差
- 支持Polygon和MultiPolygon
案例7:计算线条长度(道路、河流等)
场景:城市规划部门有多条道路的线条数据,需要计算每条道路的长度。
python
import geopandas as gpd
import tablegis as tg
from shapely.geometry import LineString
# 道路数据
gdf = gpd.GeoDataFrame({
'road_id': ['R001', 'R002'],
'geometry': [
LineString([(116.400, 39.910), (116.410, 39.920), (116.420, 39.915)]),
LineString([(116.420, 39.930), (116.440, 39.950)])
]
}, crs='EPSG:4326')
# 计算长度(单位:米)
result = tg.add_length(gdf, column='道路长度_米')
print(result[['road_id', '道路长度_米']])
# road_id 道路长度_米
# R001 2156.5
# R002 3142.3
✨ 应用场景:
- 道路养护预算计划
- 供水管网设计
- 电力网络规划
案例8:创建扇形区域
场景:无人机从某个位置出发,覆盖特定方向和距离的扇形区域,用于巡检规划。
python
import pandas as pd
import tablegis as tg
# 无人机基地位置
bases = pd.DataFrame({
'base_id': ['B001', 'B002'],
'lon': [116.404, 116.407],
'lat': [39.915, 39.918],
'azimuth': [45, 90], # 方向角(度数)
'distance': [2000, 2500], # 巡检距离(米)
'angle': [60, 45] # 扇形角度(度数)
})
# 创建扇形覆盖区域
result_gdf = tg.add_sectors(
bases,
lon='lon', lat='lat',
azimuth='azimuth',
distance='distance',
angle='angle'
)
print(result_gdf)
# 可用于地图可视化或与其他图层做空间关系分析
✨ 特殊用途:
- 无人机/卫星覆盖范围规划
- 信号塔覆盖分析
- 防护区域划定
案例9:创建规则多边形(正方形、正六边形等)
场景:需要为每个配送中心创建一个1000米的服务区(以正方形表示),用于区域划分。
python
import pandas as pd
import tablegis as tg
# 配送中心
centers = pd.DataFrame({
'center_id': ['C001', 'C002'],
'lon': [116.404, 116.407],
'lat': [39.915, 39.918],
'side_length': [2000, 2500] # 正方形边长(米)
})
# 创建正方形覆盖区域
result_gdf = tg.add_polygon(
centers,
lon='lon', lat='lat',
num_sides=4, # 4边形 = 正方形
side_length='side_length',
rotation=45 # 旋转45度让边平行于坐标轴
)
# 也可以创建正六边形
result_hex = tg.add_polygon(
centers,
lon='lon', lat='lat',
num_sides=6, # 6边形 = 正六边形
side_length=2000
)
print(result_gdf)
print(f"正方形面积:{result_gdf['geometry'].area.values[0]:.0f} 平方米")
✨ 应用场景:
- 蜂窝网格划分
- 网格化数据汇总
- 规划区域划分
案例10:将坐标匹配到行政区或其他图层属性
场景:有1000个客户的经纬度位置,需要批量查询他们分别在哪个社区、哪个行政区。
python
import pandas as pd
import tablegis as tg
import geopandas as gpd
# 客户数据
customers = pd.DataFrame({
'customer_id': ['CUST001', 'CUST002', 'CUST003'],
'lon': [116.404, 116.405, 116.406],
'lat': [39.915, 39.916, 39.917]
})
# 行政区图层(可从本地加载或使用现成的shp文件)
district_gdf = gpd.read_file('district.shp', encoding='gbk')
# 或者直接传入GeoDataFrame
result = tg.points_coverage_merge(
customers,
lon='lon', lat='lat',
coverage=district_gdf, # 可以是shp路径,也可以是GeoDataFrame
df_merge_coverage_columns=['district_name', 'district_code'],
merge_only_right_mark='未知' # 匹配不到时的默认值
)
print(result[['customer_id', 'district_name', 'district_code']])
# customer_id district_name district_code
# CUST001 朝阳区 110105
# CUST002 朝阳区 110105
# CUST003 东城区 110101
✨ 强大之处:
- 支持大规模批量匹配(秒级)
- 自动处理坐标系转换
- 支持多个属性列同时返回
- 支持多边形和点的所有空间关系查询
案例11:从WKT或16进制格式转换为GeoDataFrame
场景:从数据库中导出的几何数据是WKT或十六进制格式,需要转换为GeoDataFrame进行分析。
python
import pandas as pd
import tablegis as tg
# 数据库导出的数据(WKT格式)
df_wkt = pd.DataFrame({
'id': [1, 2],
'geometry': [
'POINT (116.404 39.915)',
'POLYGON ((116.400 39.910, 116.410 39.910, 116.410 39.920, 116.400 39.920, 116.400 39.910))'
]
})
# 转换为GeoDataFrame
gdf = tg.df_to_gdf(df_wkt, geometry='geometry')
print(gdf)
print(f"坐标系:{gdf.crs}") # EPSG:4326
# 如果是十六进制格式
df_hex = pd.DataFrame({
'id': [1, 2],
'geometry_hex': ['0101000000...', '010300000...']
})
gdf_hex = tg.df_to_gdf_16_10(df_hex, geometry_16='geometry_hex')
print(gdf_hex)
✨ 适用场景:
- 与数据库系统集成
- 处理旧系统导出的数据
- 数据迁移和格式转换
🎯 核心优势对比
| 操作 | 原生方案 | TableGIS |
|---|---|---|
| 距离计算 | 需要自己写Haversine公式 | 一行代码 distancea_str() |
| 缓冲区 | 需要手动处理投影转换 | 自动选择UTM add_buffer() |
| 两表关联距离 | 需要KDTree + 复杂循环 | 直接 min_distance_twotable() |
| 坐标匹配图层 | 需要sjoin + 复杂处理 | 一行 points_coverage_merge() |
🔧 高级技巧
技巧1:处理大规模数据
python
# 当处理100万+条记录时,分批处理
import pandas as pd
import tablegis as tg
# 分块加载
for chunk in pd.read_csv('orders.csv', chunksize=10000):
result = tg.min_distance_twotable(chunk, stations, n=3)
# 逐块处理,减少内存占用
result.to_csv('output.csv', mode='a')
技巧2:验证输入数据
python
# 检查坐标范围
import numpy as np
def validate_coords(df, lon, lat):
if not (df[lon].between(-180, 180).all() and df[lat].between(-90, 90).all()):
print("⚠️ 发现异常坐标!")
return False
return True
# 使用前验证
if validate_coords(orders, 'lon', 'lat'):
result = tg.min_distance_twotable(orders, stations, n=3)
技巧3:导出为不同格式
python
import geopandas as gpd
import tablegis as tg
result_gdf = tg.add_buffer(hospitals, dis=1000)
# 导出为Shapefile
result_gdf.to_file('hospitals_coverage.shp', encoding='gbk')
# 导出为GeoJSON(可直接在网页地图上显示)
result_gdf.to_file('hospitals_coverage.geojson', driver='GeoJSON')
# 导出为KML(Google Earth)
result_gdf.to_file('hospitals_coverage.kml', driver='KML')
📚 常见问题速答
Q1:为什么距离计算结果与GPS不一致?
A:TableGIS使用Haversine公式,基于大圆距离,精度为±0.5%。GPS导航使用的是实际道路,结果会不同。
Q2:处理错误坐标系怎么办?
A:使用
to_lonlat()函数进行坐标系转换,自动检测并转换为WGS84。
Q3:支持离线使用吗?
A:完全支持!所有计算都在本地进行,无需网络连接。
Q4:能处理多边形与多边形的关系吗?
A:可以,使用
gpd.sjoin()结合TableGIS的预处理功能。
🌟 总结
TableGIS让复杂的地理空间计算变得简单直接,特别适合:
✅ 电商配送系统(找最近门店、分配运力)
✅ 地产开发(地块面积、容积率计算)
✅ 城市规划(区域划分、覆盖分析)
✅ 社交应用(找周边用户、推荐)
✅ 公共服务(医院学校覆盖分析)
立即开始使用:
bash
pip install tablegis
python
import tablegis as tg
xxx
📖 更多资源
如果这篇文章对你有帮助,👍收藏!
有任何问题欢迎在评论区讨论,我会持续更新更多实战案例!