2、GIS基础概念:地理坐标系、投影坐标系、矢量数据与栅格数据、空间参考与拓扑
在进入Python与GIS的实战之前,必须先建立一套清晰的空间数据认知框架。很多初学者在读取Shapefile或GeoTIFF时,往往只关注属性表或像素值,却忽略了数据最底层的“空间骨架”——坐标系、数据模型与拓扑规则。如果这些基础概念不牢固,后续的缓冲区分析、叠加分析、地图叠加显示都会出现“错位”或“变形”的严重问题。本章将围绕四个核心支柱展开:地理坐标系与投影坐标系的本质区别、矢量与栅格两种数据模型的适用场景、空间参考的完整组成,以及拓扑规则如何保障空间数据的逻辑一致性。
上图展示了本章四个核心概念之间的逻辑关系:地理坐标系是投影坐标系的基础,而空间参考则是两者的综合封装;矢量与栅格是两种不同的空间数据表达方式,它们都必须依附于某个空间参考才能被正确解析。下面我们逐一深入拆解。
2.1 地理坐标系:地球的“经纬度骨架”
核心原理
地理坐标系(Geographic Coordinate System, GCS)是用三维球面来定义地球表面位置的一种坐标系。它使用经度(Longitude)和纬度(Latitude)两个角度值来定位,单位是十进制度(Decimal Degrees)。GCS的构成包含三个关键要素:参考椭球体(Ellipsoid)、大地基准面(Datum)和本初子午线(Prime Meridian)。参考椭球体是对地球不规则形状的数学近似,常见的有WGS84椭球、CGCS2000椭球等;大地基准面则定义了椭球体相对于地球质心的位置和方向,例如WGS84基准面、NAD83基准面。简单来说,椭球体是“形状”,基准面是“位置校准”。
判断方法与操作流程
在Python的GeoPandas库中,你可以通过以下方式快速查看一个矢量数据的地理坐标系:
import geopandas as gpd
gdf = gpd.read_file('cities.shp')
print(gdf.crs) # 输出类似 EPSG:4326 (WGS84)
# 判断是否为地理坐标系
print(gdf.crs.is_geographic) # 返回 True 或 False
如果返回的crs是EPSG:4326或EPSG:4490(CGCS2000),说明数据是地理坐标系。此时若直接测量面积或距离,得到的结果单位是度,无法用于实际工程计算。
案例拆解:全球城市坐标的读取
假设你从公开数据源下载了一份全球主要城市的CSV文件,其中经纬度字段是十进制度。你使用GeoPandas创建点数据时,必须显式声明其坐标系为WGS84:
from shapely.geometry import Point
import pandas as pd
import geopandas as gpd
df = pd.read_csv('world_cities.csv')
geometry = [Point(x, y) for x, y in zip(df['lng'], df['lat'])]
gdf = gpd.GeoDataFrame(df, geometry=geometry, crs='EPSG:4326')
如果不声明crs,后续任何空间操作(如缓冲区、叠加)都会因缺少坐标参考而报错或产生错误结果。这是初学者最容易忽略的步骤。
2.2 投影坐标系:从球面到平面的“变形艺术”
核心原理
投影坐标系(Projected Coordinate System, PCS)是在地理坐标系的基础上,通过数学映射将球面坐标转换为平面直角坐标(X, Y),单位通常是米。投影的本质是变形——没有任何一种投影能同时保持面积、形状、距离和方向完全不变。常见的投影类型包括:等角投影(如Web Mercator,保持形状但面积变形严重)、等积投影(如Albers,保持面积但形状变形)、等距投影(保持特定方向的距离)。
判断方法与操作流程
在Python中,使用PyProj库可以轻松进行坐标系转换:
from pyproj import Transformer
# 从WGS84经纬度转Web Mercator (EPSG:3857)
transformer = Transformer.from_crs("EPSG:4326", "EPSG:3857", always_xy=True)
x, y = transformer.transform(116.4074, 39.9042) # 北京坐标
print(x, y) # 输出米制坐标
判断一个数据是否为投影坐标系,可以检查其crs的is_projected属性。中国常用的投影坐标系包括:UTM分区(全球通用)、CGCS2000 / 3-degree Gauss-Kruger(中国国家标准)、Web Mercator(在线地图专用)。
案例拆解:面积计算中的坐标系陷阱
假设你需要计算北京市各行政区的面积。如果数据是WGS84经纬度,直接使用gdf.area得到的结果是“平方度”,毫无意义。正确做法是:
# 先投影到适合北京的等积投影,例如 Albers Equal Area (EPSG: 102025)
gdf_projected = gdf.to_crs('EPSG:102025')
gdf_projected['area_km2'] = gdf_projected.geometry.area / 1e6
print(gdf_projected[['name', 'area_km2']])
这里选择等积投影是为了保证面积计算准确。如果选择Web Mercator,高纬度地区的面积会被严重夸大,导致计算结果失真。
to_crs()是矢量数据转换坐标系的常用方法。对于栅格数据,则需要使用rasterio库的reproject()函数,且要注意重采样方法的选择(如双线性、最近邻)。
2.3 矢量数据与栅格数据:两种空间表达模型
核心原理
矢量数据(Vector Data)用点、线、面(Point, Line, Polygon)来精确表达离散地理对象,每个要素可以附带属性信息。其优点是精度高、存储量小、适合网络分析和拓扑分析。栅格数据(Raster Data)则用规则像元(Pixel/Cell)矩阵来表达连续表面或影像,每个像元存储一个数值(如高程、温度、光谱反射率)。其优点是数据结构简单、适合空间插值和地表分析,但精度受分辨率限制。
选择判断流程
| 维度 | 矢量数据 | 栅格数据 |
|---|---|---|
| 空间表达 | 离散对象(道路、地块) | 连续表面(DEM、遥感影像) |
| 精度 | 高,边界精确 | 受像元大小限制 |
| 存储量 | 相对较小(简单几何) | 大,与分辨率平方成正比 |
| 分析能力 | 拓扑、网络、叠加分析 | 坡度、坡向、水文分析 |
| Python库 | GeoPandas, Shapely | Rasterio, Xarray |
案例拆解:洪水淹没分析中的混合使用
在一次洪水风险评估项目中,你拥有:① 河流的矢量线数据(用于提取河道中心线);② 数字高程模型DEM(栅格数据,分辨率30米)。分析流程如下:
- 使用
rasterio读取DEM,并转换为NumPy数组。 - 使用
GeoPandas读取河流矢量,并栅格化(Rasterize)为与DEM相同分辨率的栅格。 - 设定水位阈值(如50米),在DEM中标记所有低于阈值的像元为淹没区。
- 将淹没区栅格转换为矢量多边形,以便与行政区划叠加统计受灾人口。
这个案例中,矢量数据提供了精确的河流位置,栅格数据提供了连续的地表高程,两者结合才能完成完整的分析。在Python中,栅格转矢量可以使用rasterio.features.shapes(),矢量转栅格可以使用rasterio.features.rasterize()。
2.4 空间参考与拓扑:数据一致性的“守护者”
核心原理
空间参考(Spatial Reference)是一个综合概念,它包含了坐标系(GCS和PCS)、分辨率(Resolution)和容差(Tolerance)。在Python中,GeoPandas的crs属性就是空间参考的简化表示。拓扑(Topology)则是研究空间实体之间关系(邻接、连通、包含、相交)的规则集合。拓扑关系不随坐标变换而改变,例如“A多边形与B多边形相邻”这一事实,无论坐标系如何转换都成立。
操作流程:拓扑检查与修复
在GIS分析中,常见的拓扑错误包括:多边形重叠(Overlap)、缝隙(Gap)、未闭合线(Unclosed Line)等。使用Python的shapely库可以进行基础检查:
from shapely.geometry import Polygon
from shapely.validation import explain_validity
# 创建一个有重叠的多边形
poly1 = Polygon([(0,0), (2,0), (2,2), (0,2)])
poly2 = Polygon([(1,1), (3,1), (3,3), (1,3)])
print(poly1.intersects(poly2)) # True,存在重叠
# 检查多边形是否有效
print(explain_validity(poly1)) # Valid Geometry
对于更复杂的拓扑规则(如“面不能重叠”、“线必须在端点处连接”),建议使用PostGIS数据库或ArcGIS的拓扑工具。在Python生态中,geopandas的overlay()函数可以检测并处理重叠,但无法自动修复所有拓扑错误。
案例拆解:行政区划数据的拓扑修复
某项目需要合并两个相邻省份的行政区划数据,但发现边界处存在细小的缝隙和重叠。这些误差会导致后续的“面积汇总”出现重复或遗漏。处理步骤:
- 使用
gdf.buffer(0)方法消除多边形之间的微小缝隙(注意:buffer(0)可以修复部分无效几何)。 - 使用
gdf.overlay('union')将重叠区域合并为一个整体。 - 使用
gdf.geometry = gdf.geometry.buffer(0)再次检查有效性。 - 最后,使用
gdf.geometry = gdf.geometry.make_valid()(Shapely 2.0+)强制修复所有无效几何。
修复后,重新计算面积,确保与官方统计数字一致。这个案例说明,拓扑错误如果不处理,会直接导致分析结果不可信。
make_valid()虽然能修复几何,但可能会改变几何的形状(如将自相交多边形拆分为多个多边形)。修复后务必进行可视化检查,确保没有引入新的逻辑错误。
2.5 本章知识结构总览
| 概念 | 核心组成 | Python对应操作 | 典型应用 |
|---|---|---|---|
| 地理坐标系 | 椭球体、基准面、本初子午线 | gdf.crs查看 | 全球定位、数据采集 |
| 投影坐标系 | 投影方法、中央经线、标准纬线 | gdf.to_crs() | 面积测量、地图制图 |
| 矢量数据 | 点、线、面 + 属性表 | GeoDataFrame | 网络分析、地址匹配 |
| 栅格数据 | 像元矩阵、波段、分辨率 | rasterio.open() | 遥感分类、地形分析 |
| 空间参考 | GCS + PCS + 容差 | pyproj.Transformer | 数据集成、坐标转换 |
| 拓扑 | 邻接、连通、包含规则 | shapely谓词 | 数据质量检查、编辑 |