简介:压缩包提供黄土高原地区DEM高程数据及四大类生态分区成果,面向地理信息、水土保持与生态规划方向的从业者和研究者,适用于ArcMap环境下的流域分析、地貌制图与生态修复区划。包内共12个文件,压缩包约4.78MB,含tif格式高程栅格、可编辑mxd工程文档、docx数据说明,以及配套shp/shx/dbf/prj等标准shapefile组件,可直接加载或二次制图。已有136人下载学习。生态分区依据气候、地形及治理模式差异,将黄土高原划分为高塬沟壑区、丘陵沟壑区、沙地与农灌区、土石山区及河谷平原区,并细分子区,附面积与涉及县域信息。DEM数据可支撑水文分析、坡面提取等研究,分区成果可作为水土流失治理、土地整治与生态保护规划的基础依据。
1. 从一份真实需求说起:黄土高原DEM高程与4大类生态分区,为什么必须三件套一起交付
一个做生态修复立项的朋友来找我,说评审专家要求提供「带地形背景的生态分区底图」。他手上有DEM高程栅格、一张cad格式的分区草图、还有一份打印出来的分区图jpg——三样东西互相对不上,坐标不统一、格式不一样,根本没法在一张图里叠起来看。我帮他整理成了三件套:一个可编辑的mxd工程文件、一份标准shapefile、一份标准成图TIF。所谓黄土高原DEM高程及4大类生态分区,核心就是这个数据组织问题:高程地形做底,生态分区做面,工程文件做状态保存,矢量格式做入库交换,栅格成图做汇报交付。这篇文章面向GIS数据处理、水土保持、国土空间规划方向的从业者,讲清楚这三样东西分别是什么、怎么做出来、哪里最容易翻车。
2. 拆开看数据:DEM高程、生态分区与三种交付格式的本质
2.1 DEM高程数字化:高程栅格放进TIF前必须确认的四个属性
DEM高程本质上是一张单波段栅格,每个像元的值代表该处的地面海拔,单位通常是米。它本身没有任何颜色,你在ArcMap里看到的绿色到棕色的渐变,是符号化渲染的结果,不是数据自带的属性。这一点很多人一开始会弄混:拿到一个TIF,打开发现是灰色或者黑色,就以为数据坏了,其实只是没有做拉伸或者色带渲染。
我一般在处理DEM时会确认四个属性:像素类型、NoData背景值、坐标系、范围。像素类型常见是浮点型或整型,浮点型保留小数高程,整型则会有取舍;NoData背景值决定范围外区域是否参与渲染和计算;坐标系决定它能和什么数据叠合;范围则决定了栅格的边界和面积统计是否准确。这四个属性只要有一个不对,后续做坡度分析、填挖方、面积统计都会出问题,而且问题往往藏得很深,表面看不出来。
拿到一套黄土高原的DEM数据时,我通常先做一次「体检」:用gdalinfo看坐标系和像素信息,再叠加一幅自己信得过的边界矢量,看一眼范围对不对。很多公开DEM的数据范围比你实际需要的范围大得多,直接拿去出图会有大片无数据区,图面难看不说,面积统计也是错的。
2.2 标准shapefile:4大类生态分区在属性表里如何组织
shapefile是GIS里最通用的矢量交换格式,所谓「标准」,主要体现在属性表字段设计和几何类型上。标题里的4大类生态分区,常见口径是水土保持功能类、植被覆盖类、地形地貌类、土地利用类,每一类下面还可以细分二级类型。你可以根据项目实际口径替换,但字段结构是通用的。
我建分区属性表一般按这组字段来设计:
| 字段名 | 类型 | 说明 |
|---|---|---|
| FID | 整型 | 要素编号,系统自带 |
| type_code | 文本或整型 | 分区代码,建议用数字排序,如101、102 |
| type_name | 文本 | 分区名称,如「黄土塬水土保持区」 |
| area_km2 | 双精度 | 分区面积,单位平方公里,出图时可以直接用 |
| data_src | 文本 | 数据来源或划分依据,便于追溯 |
为什么要把type_code和type_name分开?因为shapefile的属性表格式DBF对字段名长度有限制,而且有些老旧软件对中文支持不好。用一个短代码做主键,中文名称只在显示层面用,这是行业里最常见的做法,后面讲坑的时候会细说。几何类型上,生态分区用面要素(Polygon),每个分区的边界要闭合,不能有自相交。
我一般会在出图前先把area_km2字段算好,用正确的投影坐标系算面积,然后在属性表里校验一次:所有分区面积之和应该等于整个研究区总面积,误差不超过0.5%。这步不用脚本,ArcMap里就能做,但它能挡掉很大一部分几何错误。
2.3 可编辑mxd的真正职责:它不存数据,只存「图纸状态」
mxd是ArcMap的工程文件,很多交付方和接收方都对它有误解。mxd本身不包含任何数据,它只记录了三件事:数据源的路径、图层的符号化设置、图版要素的位置和样式。你可以把mxd理解成一份「菜谱」,数据是食材,菜谱只写怎么搭配和烹调,菜谱丢了食材还在,但做出来的菜就未必是你想要的样子了。
所以当标题写「可编辑mxd文件」时,它的价值在于:接收方打开mxd,看到的是一张已经配好符号、修好图例、摆好比例尺的图纸,不需要自己再花半天去调。DEM的色带渐变、4大类和二级分区的配色、标注的字号、图例的排列顺序,全部在这个mxd里保存着。
这三种交付物对照关系大概是这样的:
| 文件 | 类型 | 用途 | 可编辑性 |
|---|---|---|---|
| mxd工程文件 | 工程文件 | 保存符号化与图版状态 | 高,打开即改 |
| shapefile | 矢量数据 | 数据入库、空间分析、数据交换 | 属性可编辑 |
| TIF栅格 | 栅格成图 | 汇报、打印、做底图 | 低,改起来麻烦 |
一个容易踩的误区是把mxd当数据备份,觉得mxd在就万事大吉。实际上mxd里的路径一旦失效,打开就是一片红色感叹号。所以我在交付时一定会连同整套数据一起打包,并且把mxd的路径设置为相对路径,这部分在避坑章节细讲。
3. 从散数据到三件套:用脚本把坐标系、字段与图层状态一次调齐
3.1 先搭目录规范:一个工程文件夹撑起所有数据
动手处理数据之前,我建议先建一个标准目录结构,因为mxd的路径管理直接和目录结构绑定,后面省下的时间远大于现在多花的两分钟。我常用的结构是:project文件夹下分data、mxd、output三个子目录,data里再分dem和shp两类。
# 建立标准工程目录 mkdir -p loess_project/data/dem mkdir -p loess_project/data/shp mkdir -p loess_project/mxd mkdir -p loess_project/output/tif # 目录结构说明: # data/dem 放原始DEM与重投影后的DEM # data/shp 放生态分区shapefile及配套文件 # mxd 放工程文件 # output/tif 放最终导出的标准成图这段命令没有技术含量,但值得你养成习惯。我见过太多人把shp、mxd、tif散落在桌面和各个下载文件夹里,等交付的时候才发现某个关键文件被移动过,mxd整个失效。把目录先立住,后面所有脚本都基于这个相对结构去写,mxd的相对路径才能稳定。
3.2 统一坐标系与矢栅对齐:GDAL脚本一次跑完
接下来处理最核心的一步:把DEM和生态分区shp统一到同一个坐标系下。黄土高原横跨多个投影带,如果使用低精度地理坐标或默认的Web墨卡托,面积统计和坡度分析会严重失真。我一般使用适合全国中纬度地区的Albers等积投影,或CGCS2000下按区域就近分带的高斯投影,具体选哪个取决于你要不要算面积——算面积就用等积投影。
下面这个Python脚本使用GDAL库,完成重投影、重采样和按矢量范围裁剪:
from osgeo import gdal, ogr, osr # 目标投影:Albers等积投影,适合面积统计和区域制图 target_srs = osr.SpatialReference() target_srs.ImportFromEPSG(9822) # EPSG 9822为Albers等积投影 # 打开矢量分区,获取其范围作为裁剪边界 shp_path = "data/shp/ecotype.shp" ds_vec = ogr.Open(shp_path) lyr = ds_vec.GetLayer(0) extent = lyr.GetExtent() # (minX, maxX, minY, maxY) # 打开原始DEM src_path = "data/dem/raw_dem.tif" src_ds = gdal.Open(src_path) # 重投影并裁剪:目标像元大小设为90米,接近SRTM/ALOS常用分辨率 gdal.Warp( "data/dem/dem_albers.tif", src_ds, dstSRS=target_srs, outputBounds=(extent[0], extent[2], extent[1], extent[3]), # 用分区范围裁剪DEM xRes=90, yRes=90, resampleAlg="bilinear", # 高程用双线性内插,保留平滑过渡 srcNodata=-32768, # 原始DEM的NoData值 dstNodata=-32768, creationOptions=["COMPRESS=LZW"], # 无损压缩,缩小文件体积 ) print("DEM已重投影并裁剪完成")逻辑说明:脚本先拿到分区shp的范围,用这个范围去裁剪DEM,这样DEM和shp在空间范围上完全一致,后续做任何叠合分析都不会出界。重采样方法选了bilinear,这是因为高程是连续表面,用最近邻会产生明显的锯齿边界,用双线性更平滑。如果你要拿DEM做汇水分析,可以换用cubic,但普通出图和叠合显示bilinear就够了。
两个参数值得你注意:target_srs直接指定了Albers投影,这不是「顺便选的」,等积投影能保证图斑面积与实际相符,做生态分区面积统计时不会被投影变形干扰;dstNodata必须要和源数据一致,否则裁剪后的DEM会出现一圈假的小值,渲染出来就是一片不合理的深色。
3.3 构建可编辑mxd:挂图层、配符号、摆图版
坐标系统一之后,下一步是构建mxd工程文件。用arcpy有两种思路:一是用ArcMap界面手动搭建一次,存成mxd模板,后续用脚本替换数据源;二是完全用arcpy从零创建。我推荐前者,因为界面调的符号更直观,但为了让读者能抄作业,这里给出一个用arcpy创建mxd并挂接图层、设置符号化的可运行脚本:
import arcpy # 设置工作空间与数据路径 mxd_path = "mxd/loess_eco.mxd" dem_path = "data/dem/dem_albers.tif" shp_path = "data/shp/ecotype.shp" # 创建空白地图文档,添加图层 mxd = arcpy.mapping.MapDocument("CURRENT") df = arcpy.mapping.ListDataFrames(mxd, "Layers")[0] # 先加分区矢量,再加DEM作为底图,保证图层顺序为DEM在下、分区在上 arcpy.mapping.AddLayer(df, arcpy.mapping.Layer(shp_path), "BOTTOM") arcpy.mapping.AddLayer(df, arcpy.mapping.Layer(dem_path), "AUTO") # 给DEM渲染渐变高程色带 dem_lyr = arcpy.mapping.ListLayers(mxd, "dem_albers", df)[0] sym = dem_lyr.symbology if sym.classes: # 按海拔分8级,颜色由低到高渐变 sym.updateClassification("EQUAL_INTERVAL", 8) sym.classBreakValues = [0, 500, 800, 1000, 1200, 1500, 2000, 2500, 3000] dem_lyr.symbology = sym # 给分区图层按type_code做唯一值渲染 eco_lyr = arcpy.mapping.ListLayers(mxd, "ecotype", df)[0] eco_lyr.symbology.renderer = "UNIQUE_VALUES" eco_lyr.symbology.valueField = "type_code" eco_lyr.symbology.addAllValues() eco_lyr.symbology.sortValues("type_code", ascending=True) # 按代码排序,而非拼音或字典序 mxd.saveACopy(mxd_path) print("mxd已生成:" + mxd_path)逻辑说明:脚本先从当前ArcMap会话创建地图文档,然后按顺序添加图层。注意添加顺序用了AddLayer的placement参数,确保DEM在下面做底,分区在上面做主题。符号化部分,DEM用等间隔分成8级,高程范围按黄土高原常见海拔来分段;分区图层按type_code用唯一值渲染,这部分决定了图例的显示顺序。
这个脚本我建议在ArcMap的Python窗口里运行,而不是直接跑在外部IDE。因为arcpy.mapping.MapDocument("CURRENT")需要一个打开的ArcMap会话。如果你是完全批量化场景,可以改成不依赖会话的方式,但对于绝大多数项目,一次搭建好mxd模板比每次都跑脚本要实用得多。
脚本跑完后,你还需要在图版视图中手动加上图例、指北针、比例尺、标题和来源注记。这些要素用脚本也能加,但调整位置很费劲,推荐在ArcMap界面里用Layout视图摆一次,然后把mxd存档。摆图版消耗的是审美和耐心,脚本帮不了你。
3.4 导出标准成图TIF:栅格化的是图纸,不是地形
标题里的「标准成图TIF」和原始DEM数据TIF是两回事。成图TIF是把整个地图版面栅格化之后得到的图片,它包含的是渲染后的地图内容——色带DEM、分区边界、图例、比例尺、标题、指北针全都在一个文件里。别人拿到这个TIF可以直接放进PPT,也可以用看图软件打开就得到完整信息,不需要装任何GIS软件。
用arcpy从mxd导出成图TIF的标准流程:
import arcpy mxd_path = "mxd/loess_eco.mxd" out_tif = "output/tif/黄土高原生态分区成图.tif" # 打开mxd,按页面尺寸导出 mxd = arcpy.mapping.MapDocument(mxd_path) # 导出参数:分辨率300dpi,背景白色,LZW压缩 arcpy.mapping.ExportToTIFF( mxd, out_tif, resolution=300, geotiff=False, # 成图不需要地理配准信息,关掉避免文件过大 world_file=False, color_mode="RGB", compression="LZW", background_color=(255, 255, 255) # 白色背景,避免透明底变黑 ) print("成图TIF已导出:" + out_tif)参数说明:resolution设为300dpi是为了保证打印和PPT放大都清晰,低于150dpi时图上的小字会虚。geotiff参数这里特意设成了False,原因和很多人直觉相反——成图是给人看的,不是用来做空间分析的,带地理坐标只会让文件体积变大,而且有些看图软件对带坐标的tif另眼相看。背景色设成白色,是防止导出时背景透明,在部分软件里显示成黑底。
实际操作中,我建议在导出前先打开mxd确认一遍图版没有要素出界。你可以在Layout视图里切换到预览模式看看整页效果,这一步虽然传统,但比任何脚本都可靠。
4. 排查避坑:五处最容易翻车的位置,按这个顺序查
4.1 叠合不上:坐标系「黑匣子」问题
现象:把DEM和生态分区shp放进同一张图,两者位置差了几百米甚至几公里,zoom to layer也救不回来。
原因:最常见是DEM是WGS84地理坐标,而shp是CGCS2000投影坐标,或者两个数据用了不同的投影带。ArcMap的「动态投影」能在显示层面临时对齐,但它不会改动你的源数据,一旦导出或做分析,错位还会回来。
解决:在动手做三件套之前,先做一次坐标系体检。用gdalinfo读取两个数据源的坐标系,再统一执行第3章的GDAL重投影脚本。记住一个原则:源数据不做原地修改,全部通过脚本输出到data/dem和data/shp目标文件夹,这样原始数据保留,排查问题时还能溯源。
4.2 mxd打开一片红感叹号,所有图层链接全部断裂
现象:把交付包解压后,打开mxd,图层面板里全是红底白色感叹号,一个图层都加载不出来。
原因:mxd记录的是数据源的绝对路径。如果对方把mxd和数据放在不同盘符,或者解压目录结构和压缩包内不一致,绝对路径就失效了。很多初学者打包交付时只拷了mxd和几个关键文件,却漏掉了同级的gdb或栅格数据集。
解决:在保存mxd之前,打开文档属性,勾选「存储数据源的相对路径」,然后重新保存。相对路径让mxd按自身所在位置找数据,只要mxd和数据文件夹的相对位置不变,整个包挪到任何机器都能打开。交付前再做一个测试:把文件夹复制到另一个位置,打开一遍mxd,确认没有感叹号再发出去。
4.3 DEM背景在成图TIF里显示为黑色方块
现象:DEM数据本身没问题,在ArcMap里显示正常,但导出成图TIF后,研究区边界外围是一大片黑块,整个图面很难看。
原因:DEM范围外是NoData值,在ArcMap里你设置了NoData显示为透明,但导出成图时背景颜色处理逻辑不同,NoData区域被渲染成了黑色。如果你用的是透明背景导出,这部分就会变成黑。这属于符号化设置没有传递到导出环节。
解决:有两个办法,推荐组合使用。第一步在DEM图层符号化里把NoData颜色显式设为白色或无色感;第二步在导出时按第3章的参数,明确background_color为白色。这样即使NoData区域被渲染,出的图也是干净的白色底。
4.4 shapefile字段名被截断或中文乱码
现象:在ArcMap属性表里建好了一个字段叫「水土保持功能区」,保存关闭再打开,字段名变成「水土保持」,或者打开时出现问号乱码。
原因:shapefile的属性文件DBF对字段名长度限制很严格(一般按字节算,中文占用较多),而且不同编码环境下中文兼容性很差,换个软件打开就乱码。这不是单个软件的问题,是shapefile这种老格式的固有限制。
解决:字段设计时全部用短英文代码,如type_code、type_name、area_km2,中文含义放到单独的分区代码对照表里,交付时附一份Excel或CSV即可。属性表里的type_name字段存中文没问题,只要字段名是英文短代码就行。这是所有shapefile数据都该遵守的纪律,和本次项目无关也要坚持。
4.5 图例顺序乱套:唯一值渲染的顺序是玄学
现象:mxd里图例的顺序不是按业务逻辑排列的,比如「水土保持区」排在了「植被覆盖区」前面,或者二级分区顺序错乱,怎么拖都拖不对。
原因:唯一值符号化默认按代码排序,如果你的type_code设计成了中文(如「一类」「二类」)或者没有考虑业务顺序,图例就会按字典序、拼音序或者入库顺序排。ArcMap的图例排序逻辑有时不符合直觉,手动调整后一旦刷新又变回去。
解决:从根本设计上解决——type_code设计成数字编码,如101、102、201、202,第一位是大类,后两位是二级类。数字排序天然符合业务顺序,图例和符号化都会按这个顺序走。如果mxd已经做完了,可以通过arcpy脚本对图层的valueField排序,或者在图例属性里手动上移下移。但我建议回到字段设计去改,一劳永逸。
5. 交付前做这三件事:数据核验、审图清单与「相对路径」收尾习惯
5.1 跑一遍数据一致性核验脚本
交付之前,我建议用一段简单的Python脚本对三个交付物做最后体检。它不会修复任何问题,但能在你打包之前发现「坐标系不一致」「范围对不上」「字段缺失」这类硬伤,避免交付后再被打回。
from osgeo import gdal, ogr import json report = {} # 1. 检查DEM是否已重投影、是否有NoData dem = gdal.Open("data/dem/dem_albers.tif") dem_srs = dem.GetProjection() dem_extent = dem.GetGeoTransform() # 栅格范围 report["dem_srs"] = dem_srs.split('"')[3] if dem_srs else "NONE" report["dem_nodata"] = dem.GetRasterBand(1).GetNoDataValue() # 2. 检查shp是否与DEM在同一坐标系、范围能否对上 vec = ogr.Open("data/shp/ecotype.shp") lyr = vec.GetLayer(0) vec_srs = lyr.GetSpatialRef().ExportToWkt().split('"')[3] vec_extent = lyr.GetExtent() # 3. 检查mxd文件是否存在、大小是否正常 import os mxd_size = os.path.getsize("mxd/loess_eco.mxd") if os.path.exists("mxd/loess_eco.mxd") else -1 report["mxd_exists"] = mxd_size > 0 # 4. 范围对齐判断:矢量范围是否落在DEM范围内 dem_min_x, dem_min_y, dem_max_x, dem_max_y = \ dem_extent[0], dem_extent[3] + dem_extent[5]*dem.RasterYSize, \ dem_extent[0] + dem_extent[1]*dem.RasterXSize, dem_extent[3] range_ok = (vec_extent[0] >= dem_min_x - 100 and vec_extent[2] <= dem_max_x + 100) report["range_aligned"] = bool(range_ok) print(json.dumps(report, ensure_ascii=False, indent=2))逻辑说明:脚本读取DEM的坐标系、NoData设置和四至范围,读取shp的坐标系和四至范围,比对两者在100米容差内是否对齐,最后确认mxd文件存在且非空。输出一份JSON结果,一目了然。100米容差的来源是我们重投影时允许的边界偏移,如果shp比DEM范围大太多,说明裁剪步骤没做对。
5.2 对照审图清单看一遍图纸
数据检查过了,不代表图能直接交付。我出图前会按下面这张清单过一遍:
- 图例是否包含全部分区类型,顺序是否与业务口径一致
- 比例尺数值是否合理,放在图面不被其他要素遮挡
- 指北针方向是否与地图实际方向一致
- 标题是否包含区域名称、专题名称和日期
- DEM色带有没有被压缩得层次不清,彩色打印是否友好
- 分区边界线和标注在成图TIF里是否清晰,分辨率300dpi下不虚
- 图外空白处是否干净,有没有残留的十字丝或编辑辅助点
这张清单也是mxd「可编辑」价值的一种体现——审图发现问题,直接改mxd的图版要素,重新导出TIF,三分钟搞定。如果没有mxd只有一张成品图,改一个错别字都要找源文件从头来。
5.3 收尾习惯:交付前把mxd路径「相对化」一次
最后分享一个血泪换来的习惯。有次我给别人交了一套数据,文件夹结构是这样的:根目录下放mxd,data子目录放shp和dem,我自认为没有问题,结果对方解压后打开,红感叹号一片。后来排查发现,我在存mxd的时候没有勾选相对路径,所有图层记录的都是本机的绝对路径,换一台机器必然失效。
从那以后我给自己定了一条规矩:无论是不是自己用,交付前都重设一遍数据源路径。在ArcMap里打开文档属性,勾选「存储数据源的相对路径」,保存,然后把这个文件夹完整复制到另一个位置重新打开测试一次。测试通过才打包交付。这条规矩看着简单,但能挡掉绝大多数「我明明都放进去了你为什么打不开」的扯皮。
三件套的价值最后都落在「别人拿到就能用」这五个字上。mxd保存的是图纸状态,shp是可交换的数据本体,TIF是零门槛可查看的成果表现;三样东西缺一样,接收方就会多花时间自己补。补的东西可能和你的原意有偏差,来回沟通的精力远大于整理时的半小时。希望这篇笔记能帮你一次就把三件套做齐,希望帮到你。
本文还有配套的精品资源,点击获取