简介:面向GIS初学者、地理信息专业学生及区域规划研究者的江苏省矢量地理数据包,以Shapefile标准格式整理,可用于地图制作、空间分析与专题制图练习。压缩包共83个文件,约974KB,涵盖shp几何数据、dbf属性表、shx索引及prj投影等配套文件,并附sbn、sbx空间索引与xml元数据,保证在ArcGIS、QGIS等软件中直接读取。内容覆盖河流、湖泊、县域、地级市、高速公路、国道、铁路、长江、丘陵、湿地及经纬网等要素,可支撑洪水风险叠加评估、地区发展差异分析、交通网络优化等典型场景。已有2386人学习下载,说明其在教学与项目实践中具备一定参考价值。数据分层清晰、要素齐全,便于读者快速搭建江苏地理底图,开展空间查询、统计与可视化表达,为区域研究与决策提供基础支撑。
1. 江苏省河流湖泊县域高速等矢量数据的落地用法:从拿到 shp 到能上图能算量
手里有一份江苏省的河流、湖泊、县域、高速 shp 数据,第一反应往往不是“太好了”,而是“这堆文件到底怎么用”。我见过太多人拿到 shp 之后卡在第一步:双击打不开,拖进软件报坐标系错误,图层叠上去位置偏到海里。这类基础地理矢量数据真正的价值,不在于“有”,而在于能不能稳定地做空间叠加、面积量算、缓冲区分析和出图。它适合做区域规划、水利分析、交通可达性评估、专题制图的人,也适合需要给业务系统准备底图数据的开发者。这一篇就按我实际处理这类数据的顺序,把坐标系、字段、拓扑、叠加和验证一条线讲透,让你拿到同类数据能直接复现。
2. 先搞清 shp 到底是什么:五个文件缺一不可
2.1 shp 不是单个文件,是一组同名文件
很多人以为 shp 就是一个文件,复制的时候只拷了.shp,结果到另一台机器上属性全没了。Shapefile 是一套同名不同后缀的文件集合,少一个就残废。常见组成如下:
| 后缀 | 作用 | 缺失后果 |
|---|---|---|
| .shp | 存几何坐标 | 直接打不开 |
| .shx | 几何索引 | 部分软件无法定位要素 |
| .dbf | 属性表 | 能显示图形但没有字段 |
| .prj | 坐标系定义 | 坐标数值在,但不知道是什么坐标系 |
| .cpg | 字符编码 | 中文属性乱码 |
我一般拿到数据先做一件事:按文件名分组,确认每个图层都是完整的一套。河流、湖泊、县域、高速通常是四个独立图层,每个图层各自一套文件。如果.prj缺失,不要急着猜坐标系,先看坐标数值范围:经纬度一般是小数点后带多位、范围在 70 到 140 之间;投影坐标往往是六位或七位的大数。这个判断能帮你避开后面一大半的偏移问题。
2.2 用命令行先做一次体检
图形界面打开之前,我习惯先用命令行把基本情况摸清楚,速度快且不依赖软件。GDAL 的ogrinfo是最稳的入口:
# 查看单个图层的概要信息,包括几何类型、要素数、坐标系 ogrinfo -so -al jiangsu_county.shp # 查看属性表前几条记录,确认字段和编码 ogrinfo -al -geom=NO jiangsu_county.shp | head -60-so表示只输出摘要不读几何,-al表示所有图层,-geom=NO跳过几何只读属性。输出里重点看三样:Geometry 是 Polygon 还是 LineString,Feature Count 是否和预期一致,Layer SRS 是否带 EPSG 编号。如果 SRS 显示(unknown),说明.prj缺失或损坏,后面必须手动指定。
提示:
ogrinfo读中文属性乱码时,加环境变量SHAPE_ENCODING=GBK再执行,能解决大部分老数据集的编码问题。
2.3 几何类型决定你能做什么分析
河流和高速是线要素,湖泊和县域是面要素,这个区别不是学术问题,直接决定分析手段。线要素能做长度量算、缓冲区、网络连通性;面要素能做面积、叠加、包含判断。把线当面试图算面积,或者把面当线做路径分析,结果一定是错的。我在处理高速数据时踩过一次坑:某份高速图层里混进了互通立交的面要素,几何类型不纯,导致后续按长度统计时多出一批零长度记录。所以体检时一定要确认几何类型是否单一,混合类型要么拆分要么过滤。
3. 坐标系这一步错了,后面全白干
3.1 地理坐标系和投影坐标系别混用
江苏地处东经 116 到 121 度、北纬 30 到 35 度之间,常见的地理坐标系是 WGS84(EPSG:4326)或 CGCS2000(EPSG:4490),单位是度。做面积和长度量算时,必须转到投影坐标系,单位才是米。江苏常用的投影有 UTM 50N(EPSG:32650)或高斯克吕格 3 度带。我一般统一转到 CGCS2000 的 3 度带投影,EPSG 用 4547 到 4554 这一组里对应中央经线的那个,具体看数据覆盖范围。
判断当前坐标系最直接的办法是看.prj内容,或者用ogrinfo输出的 SRS 字段。如果显示经纬度但你要算面积,先投影;如果显示投影坐标但你要和在线底图叠加,先转回经纬度。混用的典型症状是:图层叠上去整体偏移几百米到几公里,或者面积算出来是零点零几,明显不对。
3.2 用 ogr2ogr 批量统一坐标系
四个图层坐标系不一致是常态,手工一个个转容易漏。我一般写一条循环命令统一处理:
# 把所有 shp 统一转到 CGCS2000 3度带投影(以 EPSG:4547 为例) for f in *.shp; do base="${f%.shp}" ogr2ogr -f "ESRI Shapefile" -t_srs EPSG:4547 \ "reproj/${base}.shp" "$f" \ -lco ENCODING=UTF-8 done-t_srs是目标坐标系,-lco ENCODING=UTF-8让输出的 dbf 用 UTF-8 编码,避免中文乱码。源坐标系如果.prj存在会自动读取,不存在就得加-s_srs手动指定。转完之后不要只看命令有没有报错,一定要抽一个已知地物核对坐标数值量级:投影坐标应该是几十万到几百万的米制数值,不再是 118、32 这种度数。
注意:
-s_srs指定错了不会报错,只会默默把数据转到错误位置。不确定源坐标系时,宁可先不转,用已知控制点反推,也不要凭感觉填。
3.3 投影选择对面积量算的影响
同一个湖泊,用不同投影算出来的面积能差百分之一到百分之几。对一般专题图无所谓,对水利统计、用地平衡这类要报数的场景就不能含糊。我的做法是:全省尺度用等积投影或对应中央经线的高斯投影,局部小区域用 UTM 对应带。判断标准很简单,量算结果和官方公布的控制面积对一下,偏差在可接受范围内就固定用这套参数,别每次换。
4. 字段、编码和拓扑:属性对了图才可信
4.1 中文属性乱码的三种修法
dbf 的编码问题几乎是这类数据的标配。表现是属性表里中文变成问号或方块。修法分三层:第一层看有没有.cpg文件,里面写着UTF-8或GBK;第二层用ogrinfo加SHAPE_ENCODING环境变量试读;第三层实在不行用 Python 直接读 dbf 探测编码再重写。我一般优先用 GDAL 重写一遍带 UTF-8 的输出,比在软件里手动改编码稳。
from osgeo import ogr, gdal gdal.SetConfigOption("SHAPE_ENCODING", "GBK") # 源数据按 GBK 读 src = ogr.Open("jiangsu_river.shp") driver = ogr.GetDriverByName("ESRI Shapefile") dst = driver.CreateDataSource("river_utf8.shp") # 复制图层时显式指定 UTF-8 输出编码 dst_layer = dst.CreateLayer("river_utf8", src.GetLayer(0).GetSpatialRef(), ogr.wkbLineString, ["ENCODING=UTF-8"])这段的关键是SHAPE_ENCODING控制读入解码,ENCODING=UTF-8控制写出编码,两头对齐才不会乱。参数上,源编码不确定时可以先用chardet之类工具对 dbf 做一次探测,但别完全信自动探测,中文短字段容易误判,最终还是要人工抽几条看。
4.2 县域面数据的拓扑检查
县域图层最常见的两个问题:相邻县之间有缝隙或重叠,边界不闭合。缝隙会导致按县汇总面积时总和小于全省面积,重叠会导致重复计算。检查方法是用拓扑规则跑一遍,或者简单点,把所有县合并成一个面,和全省边界对比面积差。差得离谱就说明拓扑有问题。
# 合并所有县为一个面,用于和全省边界做面积对比 ogr2ogr -f "ESRI Shapefile" county_union.shp jiangsu_county.shp \ -dialect SQLite -sql "SELECT ST_Union(geometry) AS geometry FROM jiangsu_county"ST_Union会把所有面合并,如果存在缝隙,合并结果里会保留内部空洞。参数上注意 SQLite 方言下几何字段名通常就是geometry,不同数据源可能叫SHAPE,报错时先ogrinfo看字段名。合并后算面积和官方全省面积对一下,偏差超过千分之几就值得回头查边界。
4.3 河流线要素的方向和连通性
河流数据如果要做网络分析,线的方向(起点到终点)和端点是否相接很关键。很多公开数据的河流线是分段采集的,相邻段端点差几米没接上,网络分析就会断。检查办法是统计悬挂端点数量,或者直接建网络看连通分量。我一般先用缓冲区把端点吸附一下再建网,容差取几米到十几米,具体看数据精度。高速数据同理,出入口和主线是否拓扑相连,直接决定可达性分析能不能跑通。
5. 叠加分析与出图:把四类数据用起来
5.1 用县域面裁剪河流和高速
最常见的需求是“每个县有多少公里河流、多少公里高速”。做法是用县域面去裁剪线要素,再按县分组统计长度。命令行用ogr2ogr配合 SQL 就能完成,不必打开桌面软件。
# 按县裁剪高速线,输出带县名的分段线 ogr2ogr -f "ESRI Shapefile" highway_by_county.shp jiangsu_county.shp \ -dialect SQLite -sql " SELECT c.name AS county, ST_Intersection(h.geometry, c.geometry) AS geometry FROM jiangsu_county c, 'jiangsu_highway.shp'.jiangsu_highway h WHERE ST_Intersects(c.geometry, h.geometry) "这里ST_Intersection求交得到每县境内的线段,ST_Intersects先做粗筛减少计算量。参数上要注意两个图层必须同一坐标系,否则求交结果为空或错位。输出后按county字段分组求长度,就得到每县高速里程。河流同理,只是把高速图层换掉。
5.2 湖泊与县域的包含关系判断
湖泊跨县是常态,需要知道每个湖涉及哪些县、各占多少面积。用ST_Intersection求交后按湖和县分组算面积即可。判断包含关系时注意用ST_Within还是ST_Intersects:前者要求完全在内部,后者只要沾边就算。跨县湖泊用ST_Intersects才不会漏。算完面积记得核对各分块之和是否等于湖泊总面积,差太多说明几何有问题。
5.3 出图前的样式和标注处理
出图阶段最容易翻车的是标注压盖和线宽随缩放变化。我的习惯是:河流按等级分线宽,高速用双线或粗线加颜色区分,县域只描边不填充或浅填充,湖泊填充蓝色。标注用县域名称,设置最小显示比例,避免小比例尺下糊成一片。导出前把图层顺序理清:面在下、线在上、标注最上。这些是制图常识,但数据本身字段不全时,得先补一个名称字段再标注,否则只能显示 FID。
6. 避坑与排查:这几处翻车最多
6.1 现象:图层叠加整体偏移几百米
原因:两个图层坐标系不同,一个是地理坐标一个是投影坐标,或者投影带选错。解决:统一转到同一投影坐标系,用已知地物(如某个湖心)核对坐标数值量级,确认不再是度数。
6.2 现象:面积算出来只有零点零几
原因:在地理坐标系下直接算面积,单位是“平方度”,没有物理意义。解决:先投影到米制坐标系再算,投影参数按区域选择,算完和已知面积对一下。
6.3 现象:属性表中文全是问号
原因:dbf 编码和读取端不一致,常见是源数据 GBK 被当 UTF-8 读。解决:用SHAPE_ENCODING指定源编码,输出时显式写 UTF-8,重写一遍数据。
6.4 现象:按县汇总面积总和小于全省
原因:县域之间存在缝隙,或者边界不闭合。解决:做一次合并对比面积,定位缝隙位置,必要时用容差做一次吸附或手工修边。
6.5 现象:网络分析跑不通,路径断裂
原因:河流或高速线端点未相接,存在悬挂点。解决:建网前做端点吸附,容差按数据精度取几米,吸附后重新检查连通分量。
7. 一套可复用的验证脚本与参数习惯
处理完数据,我最后一定会跑一遍验证,不靠肉眼。核心是三件事:坐标系对不对、面积长度量级对不对、拓扑有没有明显断裂。下面这段 Python 把前两件做了,第三件用前面的合并对比法补上。
from osgeo import ogr import os def check_layer(path): ds = ogr.Open(path) lyr = ds.GetLayer(0) srs = lyr.GetSpatialRef() print(f"图层: {os.path.basename(path)}") print(f" 要素数: {lyr.GetFeatureCount()}") print(f" 几何类型: {ogr.GeometryTypeToName(lyr.GetGeomType())}") if srs: print(f" 坐标系: {srs.GetAuthorityName(None)}:{srs.GetAuthorityCode(None)}") else: print(" 坐标系: 缺失,需手动指定") # 抽第一个要素看坐标量级,判断是经纬度还是投影 feat = lyr.GetNextFeature() if feat: geom = feat.GetGeometryRef() x, y = geom.GetX(), geom.GetY() scale = "经纬度" if abs(x) < 180 and abs(y) < 90 else "投影坐标" print(f" 首点坐标量级: {scale} ({x:.2f}, {y:.2f})") for f in ["jiangsu_river.shp", "jiangsu_lake.shp", "jiangsu_county.shp", "jiangsu_highway.shp"]: check_layer(f)这段脚本的价值在于把“感觉没问题”变成“有输出可核对”。参数上,GetAuthorityCode返回 None 就说明.prj里没有 EPSG 编号,需要人工确认;首点坐标量级判断只是粗筛,最终还是要看 SRS 字段。我一般把这套检查固化成习惯,每批数据进来先跑一遍,比事后返工省时间。
再补一个参数习惯:所有中间成果单独放一个目录,文件名带坐标系后缀,比如_4547,避免不同版本混在一起。投影参数、编码、容差这些值记在一个文本里随数据走,换人接手也不用猜。这套做法不复杂,但能挡住大部分“数据看着对、一算就错”的问题。希望帮到你。
本文还有配套的精品资源,点击获取