
简介中国30米分辨率土壤类型栅格数据覆盖东三省与全国除东三省、港澳台两套区域并附土壤类型代码表面向GIS、生态环保、农业规划等领域的从业者与研究者可直接服务于土壤资源调查、土地利用分析和生态评估等场景。包内共15个文件以tif栅格主数据、tfw坐标配准文件、dbf属性表、ovr金字塔、xml元数据及xlsx土壤类型代码表为主压缩包整体249.54MB数据结构完整加载至ArcGIS或QGIS即可使用。已有130人学习下载。借助代码表中的分类码使用者可快速完成土壤类型可视化、面积统计与专题制图为区域土壤研究和政策规划提供可靠的基础底图。1. 一张30米的中国土壤图先回答“它到底解决了什么”做GIS的人手里最不缺的是矢量边界和DEM最缺的往往是能直接出图、能进模型、能算面积的土壤数据。这份中国土壤类型数据把分辨率做到了30米覆盖全国而且随数据带了一份土壤类型代码表——这意味着你不需要自己翻文献硬编码拿到手就能把数字代码映射成中文土类、亚类直接做符号化和重分类。适合三类人做国土空间规划要出土壤专题图的做生态评价需要土壤因子进模型的以及做农业区划想按土类统计面积的。它解决的核心问题不是“有多精细”而是“口径统一、开箱可用”。2. 先读懂数据再动手分类体系、坐标与代码表的三个前提2.1 数字代码不是乱编的先看懂土壤分类层级土壤类型数据最怕的不是精度不够而是你根本不知道属性表里那个数字代表什么层级。常见的数据里代码可能对应到土纲、土类、亚类、土属四个层级中的某一级。如果代码表给的是亚类你在图上用土类去归类统计结果就会糊成一团。拿到代码表的第一件事是先看它的字段结构。一般会有三列代码、中文名称、层级说明。例如代码“1152”如果对应“棕壤”那你要确认它是不是亚类层级因为棕壤还可能继续分出“典型棕壤”“白浆化棕壤”等亚类。我一般会先按“土纲-土类-亚类”三层把代码表透视一遍看看这份数据到底停在哪一层再决定后面怎么用。另一个关键点是代码表的编码规则。国内土壤数据常见的编码方式有两种一种是连续编号一种是有规则的层级编码比如第一位表示土纲、前两位表示土类、前三位表示亚类。如果是有规则的编码你甚至不需要翻说明文档直接从代码值就能判断分类层级这对批量处理非常有用。拿到手先用Excel或Python读一遍代码表确认编码规律能省掉后面很多返工。2.2 拿到手先做三件事gdalinfo、统计唯一值、核对NoData我拿到任何一份栅格数据第一步永远是打开终端跑一条gdalinfo先把数据的基本属性钉死。不要打开ArcGIS或QGIS就开始拖图层那样你连坐标系都可能看错。gdalinfo soil_type_30m.tif | grep -E Size is|Origin|Pixel Size|EPSG|NoData这条命令会输出四个关键参数栅格的行列数、原点坐标、像元大小、坐标参考系和NoData值。注意看两个地方。第一像元大小必须是30米如果是经纬度单位比如0.0003度说明数据原始投影不是投影坐标系你要先在心里有个预期后面算面积时必须转成等积投影。第二NoData值必须记下来如果文件里没有定义NoData后面做重分类时默认值可能会被当成一种土壤类型参与统计这是最容易翻车的坑之一。第二步是统计属性唯一值。用gdalinfo加直方图选项或者干脆用QGIS打开图层面板看一眼属性表里实际有多少个取值。gdalinfo -hist soil_type_30m.tif | grep -A200 0: | head -20这条命令能列出栅格每个值的像元数量。它的意义在于让你快速发现数据里除了土壤代码之外是否混入了0、255、-999这类填充值。如果出现了这些非土壤代码的数值说明数据在预处理时留了背景值或掩膜值统计前必须排除。我见过有人在没检查的情况下做面积统计结果“水域”和“裸地”中间混着一个-999的巨无霸图斑最后报表怎么都对不上。第三步是确认代码表的覆盖范围。把属性里的唯一值集合和代码表的代码集合做一次差集这一步在QGIS里用字段计算器就能完成也可以用Python快速比对import subprocess, re info subprocess.check_output( [gdalinfo, -json, soil_type_30m.tif] ).decode(utf-8) # 实际处理中建议改用rasterio等库直接读取唯一值 code_table set([1152, 1153, 1154, 1211]) # 从代码表读入 raster_values set([1152, 1153, 1154, 1211, -999]) print(代码表有但栅格没有:, code_table - raster_values) print(栅格有但代码表没有:, raster_values - code_table)两个集合不一致时停下来排查。栅格有而代码表没有的数值多半是数据在制作阶段代码发生了更新或者某些小类别被合并了代码表有而栅格没有的说明数据里确实不存在这类土壤不用管。这个校验做完数据才算真正能用。2.3 栅格还是矢量决定你后面用什么工具同样是30米分辨率的土壤数据交付格式可能是两种一种是分块的TIFF栅格一种是面状矢量Shapefile。标题写了“分辨率”通常默认是栅格但很多从行业渠道流转出来的数据其实是矢量面栅格化后的产物或者反过来栅格被矢量化成了图斑。这两种形态决定了你后续完全不一样的处理路径。栅格数据的优势是结构简单、进模型方便缺点是不能直接编辑属性表——你要改的每个属性都得通过重分类或栅格计算器重新生成。矢量数据的优势是支持字段计算、属性连接、按行政区裁剪后直接出统计表缺点是文件大、小图斑碎30米分辨率下栅格化的锯齿边界在矢量化后会形成大量细碎多边形文件动辄几个G。建议开工前先按下面的路径选工具数据形态符号化方式面积统计方式适合场景栅格TIFF唯一值渲染或重分类Zonal Histogram / 区域制表进模型、生态评价、批量分析矢量面属性连接代码表后唯一值渲染按字段汇总面积出专题图、国土规划制图、勘界报告如果拿到的是栅格但你的最终成果要求矢量图斑不要直接转矢量化。30米栅格转出来的矢量面会有大量锯齿边界和碎斑看起来很不专业。更稳的做法是栅格重分类后在GIS里做一次聚合消除小于最小制图面积的图斑再做矢量化。反过来矢量转栅格时要用“代码字段”作为像元值而不是用FID或者自建序号否则转完栅格你还要再查一遍对应关系。3. 在GIS里把数据用起来关联代码表、符号化与重分类3.1 矢量面数据的正确打开方式属性连接三步矢量形态的土壤数据属性表里通常只存一个数字代码没有中文名称。这时候关键一步是把代码表通过字段连接挂进来。第一优先用的是“代码”字段注意不是“名称”字段名称在两张表里可能因为空格、全半角不一致而连不上。在ArcGIS Pro里操作路径是右键图层 → Joins and Relates → Add Join输入图层字段选择“code”关联表选择代码表匹配字段也选择“code”连接类型保留默认的Keep All。在QGIS里则是图层属性 → Joins → 点击加号 → Join layer选代码表Join field和Target field都选“code”。这步没什么技术难度但有个细节值得注意连接完成后立刻导出为新图层而不是直接拿着连接状态继续干活。因为连接关系在ArcGIS里是动态的重命名代码表或移动路径后连接就断了导出成独立字段就断了这个依赖。连接之后做一次随机抽查。怎么抽在属性表里按代码排序随机挑三个不同类型的图斑用Identify工具点一下核对图上位置、属性代码、名称三者是否一致。这一步不是走过场我有一次就是没抽查结果代码表里的“棕色钙积土”和“棕色砂土”因为编码位错位整张图图例倒挂开会时被底下的人当场指出。3.2 栅格数据的正确打开方式按代码表重分类栅格形态的土壤数据没有属性表可以连接面对代码表正确的处理是重分类。所谓重分类就是把原始像元值按照代码表重新映射到一组新的值上比如把“1152、1153、1154”归并为“11-棕壤类”再给“11”赋上符号系统。在QGIS里可以用栅格计算器写表达式完成映射也可以用SAGA和GDAL的组合批量处理。我一般推荐用GDAL的reclassify思路配合Python脚本做映射会很清晰import rasterio import numpy as np mapping { 1152: 11, # 典型棕壤 → 棕壤类 1153: 11, # 白浆化棕壤 → 棕壤类 1154: 11, # 潮棕壤 → 棕壤类 1211: 12, # 暗棕壤 → 暗棕壤类 } with rasterio.open(soil_type_30m.tif) as src: profile src.profile.copy() data src.read(1) nodata src.nodata reclassified np.full_like(data, 0, dtypenp.uint8) for old_val, new_val in mapping.items(): reclassified[data old_val] new_val if nodata is not None: reclassified[data nodata] 0 # 保持NoData profile.update(dtypeuint8, count1, nodata0) with rasterio.open(soil_class_11.tif, w, **profile) as dst: dst.write(reclassified, 1)注意三个参数映射表、NoData处理、输出数据类型。映射表建议直接由代码表程序化生成不要手敲代码表往往有几百行手敲必出错。NoData值在重分类后要保留原语义不能被归入某类土壤。输出数据类型按分类数量选如果归并后不超过255个类别用uint8即可文件体积会小很多。还有一种更省事的做法如果重分类只是为了出图不需要生成新栅格那直接在QGIS里用栅格渲染的“Paletted/Unique values”就能解决从代码表复制颜色值过来视觉效果一样但底层数据没变。这个方法适合赶进度不适合做分析。我自己的习惯是出初稿用渲染骗骗眼睛正式成果和面积统计一律重分类。3.3 从“看得见”到“讲得清”唯一值符号化与图例整理把代码表挂上或重分类完成后还不能直接出图。直接出的图有两个问题一个是图例顺序混乱代码表里的类目是按编码排的但图上需要按地理意义或面积大小排序另一个是颜色随机分配相邻土类的颜色可能极其相似图面无法区分主次。我的做法是三步先按分类体系构建一个分组结构土纲→土类→亚类三层然后按土纲分配色系例如淋溶土用暖色系、钙积土用冷色系、盐碱土用黄色系最后在图层符号系统里手动固定每类的颜色值不让GIS自动分配。这一步在ArcGIS里是右键图层Properties → Symbology → Unique Values在QGIS里是Layer Properties → Symbology → Categorized。关键是把分类值的显示名称改成“代码 中文名称”比如“1152 棕壤”而不是只有代码。出图时图例会自动带上这些名称审图的人不需要翻代码表就能读懂图。图例的“标题”我建议写“土壤类型亚类”而不是笼统的“土壤类型”。因为不同层级的名目相差很大标题里写清楚层级能避免看图的人误把你归并后的结果当作国家级分类口径的成果。4. 避坑排查那些“看着对、用着错”的细节4.1 五条踩坑记录现象、解决路径坑一代码表层级对不上图例错位。现象按代码表连接后图面上出现同一个名称对应两个不同代码或者明显的土壤类型出现在完全不合理的位置比如热带砖红壤出现在西北干旱区。原因代码表提供的是亚类级分类而数据属性字段存的是土类级代码二者根本不是同一列的映射关系。解决先对代码表做唯一值透视搞清楚每个字段的语义再决定连接用哪个字段。如果数据是土类、代码表是亚类必须先用代码表把亚类聚合到土类再做连接。坑二投影坐标系被忽略面积越算越离谱。现象和同一坐标系的行政区边界叠加时完全吻合但统计出来的土壤面积比上报的国土面积大出百分之十几。原因数据本身的坐标系是地理坐标系GCS_WGS_1984你直接拿它算面积用的是经纬度做的伪面积计算。解决做面积统计前先看Layer Properties里数据的坐标系如果显示GCS开头用“Project Raster”转成Albers等积投影或UTM投影后再计算。我一般习惯统一转成CGCS2000_3_Degree_Gauss_Kruger或Albers等积投影取决于项目要求在哪个带。坑三NoData值被当成土壤类型参与统计。现象面积统计报表里突然冒出一个数十万平方公里的“类型”代码显示为0或255。原因重分类时没有保留NoData掩膜把NoData像元统一赋了一个代码值。解决重分类脚本里强制先提取NoData掩膜再执行映射最后把掩膜叠回去。具体代码在3.2节的参考实现里已经处理了关键是每套数据都要先确认NoData值到底是什么不同来源的数据可能是255、-999或0没有一个固定值。坑四字段类型不匹配连接后全是NULL。现象连接代码表之后中文字段全部为空但代码字段看起来一模一样。原因栅格的属性表代码是整型而代码表的代码列被读成了字符串型肉眼看不出来但底层类型不一致连接条件永远不成立。解决连接前用字段类型转换工具统一成整型在QGIS里是Refactor Fields在ArcGIS里是Calculate Field把它强转为Long。转换后再跑连接问题立刻消失。坑五30米分辨率被误用在地块尺度决策上。现象叠加高分辨率影像后发现一个明确的种植地块在土壤数据里横跨三种类型网格边界呈锯齿状。原因30米栅格在平地能反映土壤亚类的宏观分布但在地形过渡带、河谷窄条地带一个像元可能混合了两种土壤。解决不要在小于30米×30米的地块上做土壤类型的精确判定把数据当作区域统计和空间分异的依据而不是地块级处方图的数据源。这个预期最好在一开始就给甲方说清楚省得后面扯皮。4.2 交付前必须跑完的四项检查Output图层生成后我建议强制自己走一遍四步检查流程每一步都有明确的终止条件不满足就回炉。第一项唯一值数量对比。把输出图层按代码字段统计频数和代码表做一次集合求差确认没有多余代码、遗漏代码。第二项空值检查。选中所有属性为空或代码为空的要素确认它们在图上位于有效范围之外。第三项面积合理性。随机挑三个县级行政区把土壤类型面积加总和行政区面积对比误差超过2%就要查投影和NoData。第四项图例抽查。把图例随机取五个名称回到图上用Identify依次核对不要只看图例排序。这套流程不是官方要求的是我自己翻了三次车以后固化的习惯。每次大概多花十五分钟但这十五分钟能挡住绝大多数“数据没问题但汇报的时候跑出来一堆怪数字”的尴尬。注意如果发现某个图斑的土壤代码在代码表里找不到不要顺手把它改成最邻近图斑的代码。正确做法是保留原值在文档里标注“该代码未在代码表中收录建议向上游确认”像这样把问题暴露出来而不是用自己的脑补解决。5. 进阶实战把代码表变成统计表与专题图5.1 按行政边界裁剪并统计面积数据到手光出图是不够的很多项目要的是“某个县、某个流域内各类土壤面积各是多少”这种统计表格。栅格数据最稳的统计方法是分区统计而不是先裁剪再数像元。以省级边界统计各土壤类型面积为例用QGIS的Zonal Histogram工具即可工具输入分区图层省界矢量、分区字段NAME、栅格图层重分类后的土壤数据输出一张表每行是一个省每列是一种土壤类型代码单元格值表示像元数量乘以900平方米30m×30m就是面积。如果是更复杂的交叉统计——比如“每个县、每种土壤类型、每个坡度等级的三维组合面积”——我会直接上Pythonimport rasterio import numpy as np import geopandas as gpd from rasterio.mask import mask soil rasterio.open(soil_class_11.tif) boundary gpd.read_file(county.shp) result [] for _, row in boundary.iterrows(): geom [row.geometry] out_image, _ mask(soil, geom, nodata0) values, counts np.unique(out_image[out_image ! 0], return_countsTrue) for code, count in zip(values, counts): result.append({县名: row[NAME], 土壤代码: int(code), 面积_km2: count * 900 / 1e6}) summary pd.DataFrame(result).groupby([县名, 土壤代码])[面积_km2].sum().reset_index() summary.to_csv(soil_area_by_county.csv, indexFalse, encodingutf-8-sig)这条流程把三个数据处理动作合在一起掩膜裁剪、像元计数、面积换算。注意参数“nodata0”必须和重分类时保持一致如果重分类输出的NoData被赋成了别的值这里就会统计出虚假的“第0类土壤”。5.2 从数据里讲出故事一张能拿去开会的图统计表只是过程产物最后还是要落到一张图。30米土壤数据做制图时比例尺建议控制在1:50万到1:100万之间这个范围既能体现亚类分布的空间差异又不会因为图斑太碎导致版面脏乱。制图时叠加要素只保留三级河流、县级边界和少数地名注记一层DEM做背景晕渲会让图面更有立体感但注意晕渲的透明度要调到30%以下否则会干扰土壤类型的颜色识别。图例的排序不要按代码数字要按面积从大到小排列把占主导的类型放在最上面一眼就能传递“这个区域以什么土壤为主”的信息。同时加一个饼图或直方图辅助表达各省土壤构成这些可以在Excel里做也可以直接在GIS版面里插入统计图。做这张图时我吃亏最深的一次是图斑颜色和统计表的色卡没统一。图上显示棕壤是橙色统计表里棕壤对应的填充色也是橙色但两种橙色的RGB值略有差异主任在会上说“这个图跟表对不上”。从那以后我每次做土壤专题图都强制从统计表生成色卡再回填到GIS符号系统里保证颜色参数严格一致而不是靠肉眼“差不多就行”。还有一个习惯值得保留出完图后关掉所有辅助图层单独审一遍土壤图层和图例之间的对应关系然后导出一份200%比例尺的PDF用来检查锯齿和压盖问题确认没问题再提交。这份30米分辨率带代码表的土壤数据只要前面几步校验走完后面就基本不会出事故了。你拿到的每个代码都有名有姓每块颜色都能对上表这种确定感是做GIS项目最好的底气。希望帮到你。本文还有配套的精品资源点击获取