简介:这是一份云南省土壤类型空间分布数据,以标准shape文件交付,面向GIS从业者、土壤学研究人员及自然资源规划人员,解决省级尺度土壤类型底图获取与分类体系对接问题。数据基于1:400万中国土壤图分类系统编码,三位数字码中前两位为土类、第三位为亚类,制图单元涵盖土属、土种等层级,并对照FAO体系,便于国际对标。压缩包共15个文件、仅1.47MB,以shp/dbf/shx矢量文件为核心,含prj投影定义与mxd制图工程、tif成图,配套xlsx分类编码表和docx说明文档。属性表SOIL_ID与编码表亚类一一对应,随附云南省级行政区划shape文件,可直接用于裁剪、叠加分析与专题制图。已有61人学习下载,适合需要快速获取标准土壤类型空间数据、开展区域研究与GIS实训的用户。
1. 打开云南土壤shape文件之前,先搞清楚这三件事
做农业适宜性评价、生态区划或者工程选址时,最常被问到的基础数据就是云南土壤类型空间分布。网上下载的shape文件很少是打开即用的:坐标系写错、字段乱码、多边形自相交,这些问题在ArcGIS里看不出来,换到QGIS或写脚本统计时就集体翻车。这篇笔记把标准shape文件的格式边界、生产流程、校验清单和常见坑位一次讲透,适合手里已经拿到数据却不太敢直接投入使用的GIS工程师、土地规划人员和科研工作者。先记住一句话:shape文件的标准,不取决于坐标系选哪个,而取决于文件是否完整、字段是否可靠、几何是否经得起交叉验证。
2. shape文件的格式边界:为什么土壤分布数据得按这套规则存
2.1 shapefile不是「一个文件」,是「一组文件」
很多从业者第一次接触shapefile时,以为只要拿到.shp就够了。实际上shapefile是ESRI在1990年代定义的一组文件格式,主文件.shp存几何,索引文件.shx存几何位置偏移,属性文件.dbf存字段值。三者缺一不可:少了.shx,有些库还能读,但遍历性能会明显下降;少了.dbf,只见图形不见属性,土壤类型名称和代码全丢。除此之外,.prj存坐标参考描述,.cpg存属性编码字符集,.sbn/.sbx是空间索引,后三者不是必需,但对标准shape文件来说,.prj和.cpg是强烈建议补齐的。
土壤类型数据的shape文件,要素量通常在几十到几百个面之间。以云南省省级1:50万或1:100万土壤图为例,按土类级别整理,常见大类包括红壤、砖红壤、黄壤、紫色土、石灰土、水稻土等;如果拆到亚类级别,要素数会膨胀到数百个。文件组里的.dbf字段表,需要能支撑这种粒度。建议的标准文件组至少包含:yunnan_soil.shp、yunnan_soil.shx、yunnan_soil.dbf、yunnan_soil.prj、yunnan_soil.cpg。
2.2 DBF字段与精度限制:土壤类型代码和名称怎么塞得下
.dbf格式是老古董,字段名最长10个字节,中文名会被截断或显示成乱码。设计标准shape文件的属性表时,我一般用英文短字段名加中文别名的方案:
| 字段名 | 类型 | 长度 | 说明 |
|---|---|---|---|
| CODE | String | 10 | 土壤类型编码,如A01表示红壤 |
| T_NAME | String | 20 | 土类名称,如红壤、黄壤 |
| S_NAME | String | 30 | 亚类名称,如红壤属下的黄红壤 |
| AREA_HA | Real | 18.4 | 面积(公顷) |
| SOURCE | String | 40 | 数据来源或图幅编号 |
字段名超过10字节会在某些老库中被截断,比如TYPE_NAME正好10字节没问题,SUB_TYPE_NAME就超了,会被截成SUB_TYPE_。所以能用短代码就用短代码,名称列只做展示。AREA_HA用双精度浮点,投影坐标下面积计算误差小于0.1公顷,够用。CODE不建议用纯数字,因为土壤分类历史上经历过多次修正,纯数字编码容易和旧标准混淆,用带字母的层次编码更灵活。
2.3 坐标参考与投影:云南的shape文件该用哪套坐标
云南约在东经97.5度到106.2度、北纬21.1度到29.3度之间,东西跨度接近9个经度,跨UTM 48N和49N两个分带。一个不可回避的现实是:很多历史土壤数据来自第二次土壤普查的纸质图矢量化,坐标系可能是北京54或西安80,也可能是无投影的经纬度。标准化的第一件事不是转投影,而是先确认原始数据的坐标参考。
如果面向省级总量统计和制图,常见做法是用CGCS2000地理坐标(EPSG:4490)作为交换格式,出图时再转Albers等积投影或Lambert等角圆锥投影。如果面向县域级叠加分析,应该用高斯-克吕格3度分带投影,云南主要落在33、34、35带。这里有一条血泪经验:不要把原始投影当玄学,直接用.prj文件里写的EPSG代码做判断,而是先看坐标值的量级,再反推投影。经纬度坐标的X在97到106之间,Y在21到29之间;高斯投影坐标的Y是带号开头的6到7位数,X是200万到300万的量级。两者一眼就能区分。
3. 从原始资料到标准shape文件:生产流程与可复现命令
3.1 原始数据形态与标准shape文件的差距在哪
市面上能拿到的云南土壤数据,原始形态大概有三种。第一种是纸质土壤图的扫描件或者栅格图,需要配准后手工矢量化,工作量最大,常见做法是在QGIS中用配准插件加上矢量编辑工具,逐面描出多边形并录入属性。第二种是已有矢量数据但字段混乱,比如土类名称混在备注里、代码列有大量空值、多边形边缘有明显锯齿。第三种是有区域的栅格分类图,比如基于遥感影像解译的土壤类型网格,需要通过栅格转面再融合碎斑。
无论哪种形态,距标准shape文件都差三件事:几何拓扑要修复、属性字段要统一、坐标参考要对齐。矢量化过程中最常见的问题是相邻多边形不共享边界,留下细小缝隙或重叠带,这些问题在放大到1:1万时才会暴露。合理的目标不是做成完美的拓扑无缝面,而是把缝隙和重叠控制在可接受的容差范围内,比如经纬度数据控制在0.0001度以内。
3.2 用Python GDAL/OGR做几何修复与字段规整
拿到一批混乱的矢量数据后,我一般先用Python的GDAL/OGR跑一遍批量检查与修复脚本。下面的代码先列出字段,再遍历所有要素做几何有效性修复。
from osgeo import ogr path = "yunnan_soil_raw.shp" # 打开数据源,True代表可写 ds = ogr.Open(path, True) layer = ds.GetLayer(0) # 查看现有字段,确认哪些字段可用 defn = layer.GetLayerDefn() print("字段列表:") for i in range(defn.GetFieldCount()): fld = defn.GetFieldDefn(i) print(fld.GetName(), fld.GetTypeName()) # 遍历要素,修复无效几何 fixed_count = 0 for feat in layer: geom = feat.GetGeometryRef() if geom is None: continue # IsValid检查自相交、退化多边形等拓扑错误 if not geom.IsValid(): # MakeValid是GDAL 3.0提供的方法,返回修复后的新几何 fixed_geom = geom.MakeValid() feat.SetGeometry(fixed_geom) layer.SetFeature(feat) fixed_count += 1 print(f"修复几何数量:{fixed_count}") ds = None这段代码里,ogr.Open(path, True)的第二个参数是关键,设置为True才能进入编辑模式,否则SetFeature不会生效。IsValid()对土壤这种多边形面数据,能检查出自相交、重复点、退化成线或点的几何。MakeValid()不是万能后悔药,它会把自相交的复杂多边形拆成多个面,并保留原始属性;但要注意,拆出来的子要素面积之和与原来相同,如果后续要做面积统计,必须重算面积字段,不能沿用旧值。
字段规整是另一件事。如果旧数据里土壤名称列叫name,代码列叫code1,需要把它们重命名为统一的T_NAME和CODE。GDAL中重命名字段没有直接API,常见的做法是用layer.SetFieldDefn或者干脆复制一个新的属性表。实际操作中,我更推荐在下面的ogr2ogr步骤里用SQL完成,比Python逐要素改字段省事得多。
3.3 ogr2ogr裁剪与合并:一步到位的常用命令
GDAL自带的ogr2ogr命令行工具,是生产标准shape文件最顺手的工具。它支持字段映射、空间裁剪、坐标转换和属性过滤,一次执行完成多步操作。
# 先按经纬度矩形范围做粗裁剪,去掉省外的碎要素 ogr2ogr -f "ESRI Shapefile" yunnan_soil_clip.shp yunnan_soil_raw.shp \ -clipsrc 97.0 21.0 107.0 30.0 \ -t_srs EPSG:4490 \ -overwrite # 合并多个县市的土壤shape文件 ogr2ogr -f "ESRI Shapefile" yunnan_soil_merge.shp kunming_soil.shp ogr2ogr -f "ESRI Shapefile" yunnan_soil_merge.shp dali_soil.shp \ -update -append # 按土类字段溶解碎斑,减少要素数量 ogr2ogr -f "ESRI Shapefile" yunnan_soil_dissolve.shp yunnan_soil_merge.shp \ -dialect sqlite \ -sql "SELECT T_NAME, ST_Union(geometry) AS geometry FROM yunnan_soil_merge GROUP BY T_NAME"-clipsrc接受x_min y_min x_max y_max四个参数,按矩形范围过滤,这是最不容易出错的写法。注意这里只是矩形裁剪,并没有严格沿云南省界切割。如果要求不覆盖省外区域,我一般在QGIS中用Clip工具,或者写空间求交SQL。-update -append是ogr2ogr合并多个文件的固定套路,第一次执行生成新文件,后续执行追加写入,同时保留前一次已经写入的属性。
ST_Union(geometry) GROUP BY T_NAME这一步是溶解操作,把相同土类的碎面合并成连续的大面,要素数量可能从上千降到几十,性能提升明显。这里有个参数注意点:溶解之后,除了T_NAME和geometry,其他字段全部丢失。如果你需要保留CODE和AREA_HA,必须把它们也加进SELECT,并且在聚合时用MAX(CODE)或SUM(AREA_HA)处理。
4. 交付前自查:空间参考、属性完整性与几何质量三件套
4.1 空间参考是最大黑匣子:坐标量级一验便知
许多从业者拿到shape文件第一件事是拖进ArcGIS看渲染效果,这恰恰是最容易踩坑的做法。渲染正常只能说明几何能画出来,不能说明坐标参考是对的。我习惯先用ogrinfo快速读取图层信息。
ogrinfo -so yunnan_soil_standard.shp yunnan_soil_standard输出里会包含Extent、Layer SRS WKT和Geometry三块,Extent直接给出坐标范围。对照下表判断坐标类型:
| 坐标值特征 | 对应系统 | 判断方法 |
|---|---|---|
| X在97~106,Y在21~29,都是6位以内小数 | 经纬度(WGS84/CGCS2000) | 合理 |
| X是带号开头的6~7位数,Y是200万~300万 | 高斯-克吕格3度带 | 投影坐标,需确认带号 |
| X是50万左右,Y是200万~300万 | UTM 48N/49N | 投影坐标,注意中央经线 |
| X和Y都是2~5位的奇怪值,或出现负数 | 可能已损坏或地理坐标被错误偏移 | 需要重检查 |
如果.prj文件写着WGS84但Extent显示X是500000,说明有人改了投影描述文件却没有转换坐标值,这是最常见的翻车现场。遇到这种情况,唯一的修复路径是把原始坐标按正确的投影参数转回经纬度,再重新定义投影,千万不要在原数据上直接改.prj。
4.2 属性表的完整性检查:类型代码映射不丢要素
几何没问题后,下一步是检查属性表。用ogrinfo的SQL功能可以快速统计各土壤类型的要素数量和面积。
ogrinfo -dialect sqlite -sql "SELECT T_NAME, COUNT(*) AS cnt, SUM(AREA_HA) AS area FROM yunnan_soil_standard GROUP BY T_NAME" yunnan_soil_standard.shp这个统计能暴露出三类问题:一是存在空值,比如T_NAME为空的要素,通常是从栅格转面时自动生成的边缘碎块;二是同名不同码,同一个T_NAME对应多个CODE,说明分类代码在矢量化时录入不一致;三是面积异常,某些要素的AREA_HA为0或过大,多半是溶解操作后没有重算面积。
针对空值,建议直接删除或降级为「未分类」:删除的操作在QGIS里用表达式选中空值要素即可,降级则要改代码字段。针对同名不同码,需要对照云南省第二次土壤普查的分类口径,整理一份代码映射表。常见做法是把旧数据里所有出现过但代码不一致的名称列出来,人工对照国标土壤分类系统逐条修订,这个过程没有捷径,但值得做扎实,因为后续任何统计分析都依赖这个字段的一致性。
4.3 几何质量把关:自相交、重复面与拓扑容差
几何质量是标准shape文件最容易被忽略的环节。很多数据肉眼看上去没问题,放大到1:5万才看到相邻多边形的公共边是两条并不重合的线,中间夹了一条细长缝隙。要批量检查自相交和重复要素,可以用Python加shapely库。
from osgeo import ogr from shapely.geometry import shape ds = ogr.Open("yunnan_soil_standard.shp") layer = ds.GetLayer(0) invalid_fids = [] overlap_issues = [] # 第一遍:检查几何有效性 features = [] for feat in layer: geom = feat.GetGeometryRef() if geom is None: continue shapely_geom = shape(geom) features.append((feat.GetFID(), shapely_geom)) if not shapely_geom.is_valid: invalid_fids.append(feat.GetFID()) # 第二遍:两两检查重复面 for i in range(len(features)): for j in range(i + 1, len(features)): if features[i][1].equals(features[j][1]): overlap_issues.append((features[i][0], features[j][0])) print("无效几何FID:", invalid_fids[:20]) print("重复面FID对:", overlap_issues[:20])shapely的is_valid比OGR的IsValid()更严格,会额外检查环的闭合性和外环内环的关系。重复面检查是O(n^2)复杂度,对几百个要素的省级数据完全可接受,但如果要素数上万,建议改用空间索引或专业拓扑工具。
拓扑容差是另一个概念。修几何时不要追求绝对无缝,而是设置一个合理容差。经纬度数据常见的容差设0.0001度,投影数据设0.5米。在这个范围内的小缝隙,可以通过QGIS的v.clean工具(GRASS)自动捕捉;超过容差的边缘断裂,就要回到原始的矢量化流程补画边界。容差设太大也有风险,会把真实的地理边界抹平,比如两条相邻的河流岸线被并到一起。
5. shape文件落地避坑:五条最常翻车的记录
5.1 文件完整性与编码:数据还没开始分析就卡住
坑一:只拷贝了.shp主文件,没有带.dbf和.prj,结果对方软件只显示一片空白或干脆报文件不存在。
现象:在ArcGIS中加载shp,图层面板出现但地图上什么都没有;用ogrinfo读取报错,提示找不到对应的.dbf。
原因:shapefile是一组文件,任何GIS软件打开时都同时依赖.shp和.dbf。拷贝传输时只抓了主文件,这是最常犯的低级错误。
解决:统一用压缩包传递整个目录,不要传输单个文件。接收方收到数据后先检查文件清单:必须有.shp、.shx、.dbf、.prj、.cpg五件套。我自己现在的习惯是上传下载走GIS数据管理工具或网盘时,永远打包成zip再传。
坑二:在老系统中打开的字段名和属性值中文乱码,显示成「锟斤拷」或者方框。
现象:T_NAME字段里的土壤名称全部变成乱码,但几何显示正常。
原因:历史数据在Windows环境下用GBK编码写入.dbf,而现代软件默认按UTF-8读取;.cpg文件缺失时,读取程序只能猜编码,猜错就乱码。
解决:用文本编辑器打开.cpg,把内容改成UTF-8,保存后重新加载。如果改完仍乱码,请把.cpg改成GBK,因为原数据可能是GBK编码。稳妥的方案是用ogr2ogr转换一次,明确指定编码:
ogr2ogr -f "ESRI Shapefile" yunnan_soil_utf8.shp yunnan_soil_gbk.shp \ -lco ENCODING=UTF-85.2 坐标系与几何:数据看着对,一算面积全错
坑三:.prj文件里写的是WGS84,但坐标值量级明显是高斯投影坐标。
现象:在QGIS中打开数据能显示,但叠加OSM底图时,图层跑到非洲几内亚湾附近,完全不和底图重合。
原因:原始数据是高斯投影坐标,有人在属性编辑器里直接改写了.prj文本,把坐标系从高斯改成WGS84,但没有做坐标值转换。软件读取.prj后以经纬度解释投影坐标,自然错位到离谱的位置。
解决:先按坐标量级确认真实投影(参考4.1中的判断表),用gdalwarp或QGIS的重投影工具做坐标转换,再重新定义投影。操作顺序必须是先转坐标值,再改投影描述,顺序反了等于数据白转。
坑四:多边形自相交,渲染时出现怪异的三角缺口,用Buffer缓冲区分析时结果明显失真。
现象:某一要素在ArcMap里看着正常,但在PostGIS里做ST_Intersects时返回错误结果;或用shapely做buffer(0)修复时报坐标错误。
原因:手工矢量化时节点顺序错乱,或者使用简化工具时抽稀阈值过大,导致多边形环自相交。这类几何错误不会让软件启动崩溃,但会在空间分析时静默地产生错误结果。
解决:批量跑一遍MakeValid(),修复后再做buffer(0)清理微小断裂。注意修复后的几何必须重算面积,并重新检查是否产生多面体(MultiPolygon),如果后续系统只支持单面要素,还需要做多面转单面。
5.3 属性与业务口径:标准文件也会被业务问题卡住
坑五:两份同样叫「红壤」的数据,一个是土类,一个是亚类,合并后统计面积出现严重偏差。
现象:把昆明和普洱两地的土壤数据合并后,T_NAME字段里出现两个「红壤」代码,但面积一栏数值差了5倍以上。
原因:不同来源数据的分类粒度不一致。第二次土壤普查成果里,昆明图幅的「红壤」是土类级,普如图幅的「红壤」可能是亚类级,两个层级包含的范围完全不同,直接合并等于把苹果和橘子加在一起。
解决:在合并前先对每个输入文件的分类口径做检查。用上一章的SQL统计每一份数据的T_NAME和CODE,对照云南省土壤分类检索表建立映射关系,统一到同一层级后再合并。这个过程常需要业务专家参与,不能只靠数据工程师自己拍板。
6. 把标准shape文件用起来:点线面叠加与符号化出图
数据标准化的最终目的不是存档,而是投入分析。以省级生态评价为例,标准shape文件最常见的用法是叠加地形、水系和土地利用数据,识别土壤类型与高程、降水的关联。操作上,我一般先按T_NAME字段做分类符号化,再用透明度叠到DEM之上,最后输出带指北针和比例尺的打印布局。
符号化建议按照土壤类型的颜色规范来配,红壤系用红色系、黄壤系用黄色系、水稻土用蓝绿色系。QGIS中右键图层进入样式面板,分类选择「唯一值」,字段选T_NAME,手动调一组专有色板,比软件默认的随机色可靠得多。叠加打印布局时,记得把坐标系信息写进图例下方,这样看图的人才知道数据落在哪个参考系统里。
更进阶的用法是把shape文件导入PostGIS,转成.sql脚本或GeoPackage,让多个项目组共用同一套数据,避免每人手里一份过期副本。导出GeoPackage时注意,字段名不再受10字节限制,但对齐原有属性表结构仍然建议沿用旧的字段命名,减少业务方的修改成本。
我现在拿到任何一份云南土壤shape文件,头三步永远是看文件清单抓dbf和prj,用ogrinfo确认坐标量级,再用shapely批量跑一遍几何有效性。这套顺序帮我挡掉了至少一半的无用功,希望帮到你。
本文还有配套的精品资源,点击获取