GMT6.1地形起伏图绘制:从DEM数据到光照阴影的完整指南
2026/9/21 0:08:32 网站建设 项目流程

1. 为什么选择GMT6.1来画地形起伏图

地形起伏图这东西,说白了就是把DEM数据里的高程值,用颜色、阴影和光照效果“翻译”成一张能让人一眼看出哪里是山、哪里是谷、哪里是平原的图。我最早接触这类图的时候,用的是ArcGIS那一套,后来转到QGIS,再后来因为要批量出图、要精确控制每一个像素的颜色和光照角度,才彻底投奔了GMT。GMT全称Generic Mapping Tools,在海洋地球物理和地学圈子里是公认的“出图神器”,到了6.1版本,它的现代模式(Modern Mode)已经非常成熟,一条命令就能完成从数据到成图的全流程,不用像老版本那样手动管理一堆中间文件。

你可能会问,现在Python的matplotlib、cartopy也能画地形图,为什么还要折腾GMT?我的体会是:GMT在栅格数据的渲染质量和投影精度上,依然是独一档的存在。尤其是画地形起伏图时,GMT的grdimage配合grdgradient做光照阴影,出来的效果非常自然,山体的立体感很强,不会像某些工具那样把山脊线画得跟刀切的一样生硬。而且GMT支持超过30种地图投影,从常见的墨卡托到兰勃特等角圆锥,再到各种方位投影,基本上你能想到的它都有。

这篇文章面向的读者,是那些手里已经有了DEM数据、或者知道去哪里下载DEM数据,但面对GMT那一堆参数不知道从何下手的人。我会从数据下载开始讲,一直讲到出图时怎么避开那些让人抓狂的坑。整个过程我会尽量用“人话”来解释每个参数背后的逻辑,而不是甩给你一堆命令让你自己猜。

提示:GMT6.1的安装方式有很多种,Windows下推荐用官方提供的安装包,Linux下可以用conda或者apt,macOS用Homebrew。安装完成后在终端输入gmt --version,如果显示6.1.x就说明装好了。

2. DEM数据下载与预处理

2.1 主流DEM数据源对比与选择

画地形起伏图,第一步永远是搞到DEM数据。DEM就是数字高程模型,简单理解就是一张巨大的表格,每个格子记录了一个高程值。目前公开可下载的全球DEM数据主要有这么几种:

数据源分辨率覆盖范围获取方式适用场景
SRTM30m/90m全球60°N~56°S美国地质调查局网站中大比例尺地形图
ASTER GDEM30m全球日本METI/NASA区域地形分析
ALOS World 3D30m全球日本JAXA高精度地形
Copernicus DEM30m/90m全球欧洲空间局全球任意区域
NASADEM30m全球60°N~56°SNASA LP DAACSRTM改进版

我平时用得最多的是Copernicus DEM的30米数据,原因是它的覆盖范围真正做到了全球无死角,连极地地区都有,而且数据质量比早期的SRTM干净不少,空洞和噪声少。下载地址在欧空局的Copernicus Data Space Ecosystem上,注册一个账号就能免费下载。如果你只是做一个小区域的教学演示,SRTM 90米数据也够用,文件小、下载快。

下载的时候有个细节要注意:不要一次性下载太大范围的数据。我见过有人直接下载整个亚洲的30米DEM,结果文件好几个GB,GMT读进去之后内存直接爆掉。正确的做法是先确定你的研究区域范围,用经纬度框定一个矩形,只下载这个矩形内的数据。比如你要画青藏高原东缘的地形,大概范围是东经95°到105°、北纬28°到35°,那就只下载这个范围。

2.2 数据格式转换与裁剪

下载下来的DEM数据通常是GeoTIFF格式,GMT6.1可以直接读GeoTIFF,但为了后续处理方便,我习惯先把它转成GMT自己的网格格式(NetCDF)。转换命令很简单:

gmt grdconvert input.tif output.grd -V

-V是打开详细输出,让你看到转换进度。如果数据量比较大,这一步可能需要等几分钟。转换完成后,用gmt grdinfo output.grd查看一下网格的基本信息,包括行列数、经纬度范围、高程最大最小值。这个信息很重要,后面设置颜色表的时候要用到。

有时候下载的DEM范围比你实际需要的要大,这时候需要裁剪。GMT里裁剪网格用gmt grdcut

gmt grdcut input.grd -R95/105/28/35 -Gcut.grd

-R后面跟的是西经/东经/南纬/北纬,注意GMT里经度范围是-180到180,如果你研究的是西半球,经度要写成负数。裁剪完之后再grdinfo看一眼,确认范围对了再往下走。

注意:有些DEM数据的高程值是整数,有些是浮点数。如果你发现出图后地形看起来“台阶感”很重,多半是数据精度不够。这时候可以考虑用gmt grdsample做一次重采样,把网格加密,但要注意重采样不会增加真实信息,只是让视觉上更平滑。

2.3 数据空洞处理与异常值剔除

DEM数据里经常会有空洞,尤其是SRTM数据在陡峭山区和水体区域。空洞在GMT里表现为NaN(Not a Number),出图时这些区域会显示为白色或者透明。如果你不想看到这些空洞,可以用gmt grdfill来填充:

gmt grdfill input.grd -An -Gfilled.grd

-An表示用周围有效值的平均值来填充空洞。还有一种情况是数据里存在异常值,比如某些像素的高程是-9999或者32767,这些是标记值不是真实高程。处理方法是先用grdclip把超出合理范围的值截断:

gmt grdclip input.grd -Sa-500/0 -Sb9000/9000 -Gclipped.grd

这条命令的意思是:小于-500的值设为0,大于9000的值设为9000。为什么是这两个阈值?因为地球表面最低点死海大约在-430米,最高点珠峰8848米,留一点余量就够了。

3. 地形起伏图的核心原理与参数解析

3.1 颜色表:地形的“翻译词典”

地形起伏图好看不好看,颜色表(Color Palette Table,CPT)至少占一半功劳。GMT自带了很多经典的颜色表,比如geotopoetopo1relief,这些都在GMT的share/cpt目录下。你可以用gmt makecpt命令基于这些内置颜色表生成自己的CPT文件:

gmt makecpt -Cgeo -T-8000/9000/500 -Z > topo.cpt

-Cgeo指定用geo颜色表,-T-8000/9000/500表示高程范围从-8000到9000,每500米一个色阶,-Z表示连续渐变而不是分块。这里的高程范围要根据你实际数据的最大最小值来定,不要照搬。比如你画的是某个小流域,高程范围可能只有200到3000米,那就写成-T200/3000/100

我个人的经验是:色阶间隔不要太小。有人为了追求“平滑”,把间隔设成10米,结果颜色表里几千个色阶,出图时颜色过渡反而显得脏。一般来说,间隔设在100到500米之间比较合适,具体看你的高程跨度。如果跨度是5000米,间隔500米就是10个色阶,视觉上层次分明;如果跨度只有1000米,间隔100米就是10个色阶,同样合理。

还有一个技巧是-I参数反转颜色表。默认情况下,低海拔是绿色、高海拔是白色或红色,但有时候为了配合特定的视觉风格,你可能想要反过来。gmt makecpt -Cgeo -I就能实现反转。

3.2 光照阴影:让山“立”起来

光有颜色还不够,地形图要让人看出立体感,必须加光照阴影。GMT里做阴影用gmt grdgradient

gmt grdgradient input.grd -A45 -Ne0.6 -Gshadow.grd

这三个参数是核心:

  • -A45:光照方位角,45度表示光源从西北方向打过来。为什么是西北?因为这是地图制图的传统惯例,人眼已经习惯了这种光照方向,如果改成东南方向,山体会看起来像凹陷的坑而不是凸起的山。
  • -Ne0.6-N表示用梯度模的指数归一化,e表示指数,0.6是归一化因子。这个参数控制阴影的强度,值越大阴影越重。0.6是一个比较温和的设置,适合大多数场景。
  • -Gshadow.grd:输出阴影网格文件。

有时候你会看到别人用-Nt0.5t表示用梯度模的平方根归一化。这两种归一化方式的区别在于:e是指数归一化,t是平方根归一化。实测下来,e方式在陡峭山区表现更好,t方式在平缓地区更自然。你可以两种都试试,看哪个顺眼就用哪个。

提示:如果你觉得阴影太重,山体看起来像被墨泼过一样,可以把归一化因子从0.6降到0.4或者0.3。反之如果觉得太平淡,就往上加。这个参数没有绝对标准,多试几次找到你满意的效果。

3.3 投影选择:不同场景用不同投影

GMT支持的地图投影非常多,画地形起伏图常用的有这几种:

  • 墨卡托投影(-JM):适合低纬度地区,高纬度变形严重。如果你画的是赤道附近区域,用这个没问题。
  • 兰勃特等角圆锥投影(-JL):适合中纬度东西延伸的区域,比如中国全图。标准纬线一般设在区域南北边界的1/6和5/6处。
  • 阿尔伯斯等面积圆锥投影(-JB):适合需要保持面积准确的场景,比如计算某个区域的面积。
  • 通用横轴墨卡托(-JU):适合南北延伸的区域,比如南美洲西海岸。

选投影的核心原则是:你的研究区域是什么形状,就选什么投影。东西长南北短,用圆锥投影;南北长东西短,用横轴墨卡托;接近方形,用等距圆柱或者墨卡托都行。不要小看投影选择,选错了会让你的地图看起来“歪”得很别扭。

4. 完整出图流程与命令详解

4.1 现代模式下的脚本结构

GMT6.1的现代模式让出图流程变得非常清晰。一个完整的脚本通常长这样:

#!/bin/bash gmt begin topo_map png,pdf gmt set FONT_ANNOT_PRIMARY 10p,Helvetica gmt set MAP_FRAME_TYPE plain gmt makecpt -Cgeo -T-500/6000/200 -Z > topo.cpt gmt grdgradient dem.grd -A45 -Ne0.6 -Gshadow.grd gmt grdimage dem.grd -Itop shadow.grd -Ctopo.cpt -JM15c -R95/105/28/35 -Bafg gmt colorbar -DJBC+w10c/0.5c+h -Baf+l"Elevation (m)" gmt end

gmt begingmt end之间的所有命令会自动共享状态,不需要像老版本那样手动指定输出文件。gmt begin topo_map png,pdf表示同时输出PNG和PDF两种格式,PNG用于快速预览,PDF用于印刷或投稿。

4.2 关键参数逐个拆解

gmt grdimage是出图的核心命令,它的参数比较多,我逐个解释:

  • dem.grd:输入的DEM网格文件。
  • -Ishadow.grd:指定阴影网格。注意这里写的是-I后面直接跟文件名,不是-I+shadow.grd。有些教程会写错,导致阴影加载不上。
  • -Ctopo.cpt:指定颜色表文件。
  • -JM15c:墨卡托投影,图幅宽度15厘米。15c表示15厘米,你也可以用15i表示15英寸。
  • -R95/105/28/35:地图范围,西经95度到东经105度,南纬28度到北纬35度。
  • -Bafg:边框和网格线设置。a表示标注间隔自动,f表示边框,g表示网格线。更精细的写法是-B5/5:."Title":,表示经纬度标注间隔5度,标题写在底部中间。

gmt colorbar是色标命令:

  • -DJBC:位置在底部居中(Bottom Center),J表示图外。
  • +w10c/0.5c:色标宽度10厘米,高度0.5厘米。
  • +h:水平放置。
  • -Baf:标注间隔自动。
  • -l"Elevation (m)":色标标签。

4.3 出图后的检查与调整

第一版图出来之后,不要急着收工。我通常会检查这几个方面:

第一,颜色过渡是否自然。如果发现某个高程段颜色跳变太厉害,说明色阶间隔设得不合理,回去调整makecpt-T参数。

第二,阴影方向是否一致。有时候因为数据范围跨了多个投影带,阴影方向会看起来不统一。这时候可以考虑用grdgradient-D参数指定方向网格,而不是用固定的方位角。

第三,标注是否清晰。如果经纬度标注太密或者太疏,调整-B参数里的间隔值。标注字体大小用gmt set FONT_ANNOT_PRIMARY来改。

第四,色标是否遮挡地图内容。如果色标压住了地图上的重要区域,用-DJBC+o0c/1c把色标往下移1厘米。

注意:GMT的现代模式里,所有gmt set命令必须在gmt begin之后、第一个绘图命令之前执行,否则不生效。这个坑我踩过好几次,明明设了字体大小但出图还是默认值,后来才发现是gmt set写在了gmt begin前面。

5. 常见问题与排查技巧实录

5.1 数据读不进去怎么办

最常见的问题是grdimage报错说“无法读取网格文件”。排查顺序是这样的:

  1. 先用gmt grdinfo dem.grd确认文件本身没问题。如果grdinfo都读不了,说明文件损坏或者格式不对。
  2. 检查文件路径。GMT对相对路径和绝对路径都支持,但如果你在脚本里用了~表示家目录,有时候会解析失败。建议统一用绝对路径。
  3. 检查文件权限。Linux下如果文件没有读权限,GMT会报错但错误信息可能很模糊。用ls -l看一眼权限位。
  4. 如果是从GeoTIFF转过来的,确认转换过程中没有报错。有时候GeoTIFF的坐标系信息不完整,转换出来的grd文件范围会不对。

5.2 出图后一片空白或者全黑

这种情况通常是颜色表的问题。如果CPT文件里的高程范围和你数据的高程范围完全不重叠,GMT就不知道该给每个像素上什么颜色,结果就是一片空白或者全黑。解决办法是用gmt grdinfo看一下数据的实际最大最小值,然后重新生成CPT:

gmt grdinfo dem.grd # 假设输出显示最小200,最大4500 gmt makecpt -Cgeo -T200/4500/100 -Z > topo.cpt

还有一种可能是阴影网格的归一化因子设得太极端,导致整个图要么全白要么全黑。把-Ne后面的值调到0.5左右试试。

5.3 阴影效果不自然

阴影看起来“假”通常有几个原因:

  • 光照角度不对。默认的45度方位角在大多数情况下没问题,但如果你画的是南北走向的山脉,45度光照会让山脊线看起来很奇怪。这时候可以试试-A315,让光源从东北方向打过来。
  • 归一化因子太大-Ne0.8会让阴影非常重,山体看起来像被墨汁泼过。降到0.4到0.5之间会自然很多。
  • DEM分辨率太低。90米的数据画小区域地形,阴影会显得很“糊”。如果条件允许,尽量用30米数据。

5.4 色标和地图对不齐

色标和地图对不齐通常是因为色标的宽度和地图宽度不一致。gmt colorbar+w参数控制色标宽度,gmt grdimage-J参数控制地图宽度。把这两个值设成一样,色标就会和地图等宽。比如地图是-JM15c,色标就写+w15c/0.5c

5.5 输出文件太大

PDF输出如果包含高分辨率栅格,文件可能会非常大。解决办法是在gmt begin里指定PDF的压缩级别:

gmt begin topo_map png,pdf gmt set PS_MEDIA A4 gmt set PS_PAGE_ORIENTATION landscape # ... 绘图命令 ... gmt end

或者在gmt grdimage里用-Q参数降低栅格采样精度。但要注意,降低精度会影响出图质量,只建议在文件大小实在无法接受时使用。

6. 进阶技巧与效率提升

6.1 批量出图脚本模板

如果你需要为多个区域出图,手动改参数太慢了。我通常写一个bash脚本,用循环遍历区域列表:

#!/bin/bash regions=("95/105/28/35" "100/110/25/32" "90/100/30/38") names=("east_tibet" "southwest" "central_tibet") for i in "${!regions[@]}"; do gmt begin ${names[$i]} png gmt makecpt -Cgeo -T-500/6000/200 -Z > topo.cpt gmt grdgradient dem.grd -A45 -Ne0.6 -Gshadow.grd gmt grdimage dem.grd -Ishadow.grd -Ctopo.cpt -JM15c -R${regions[$i]} -Bafg gmt colorbar -DJBC+w10c/0.5c+h -Baf+l"Elevation (m)" gmt end done

这个模板的关键是把区域范围和输出文件名做成数组,循环的时候用索引对应。这样一次就能出好几张图,效率提升非常明显。

6.2 用grdview画三维地形

除了二维平面图,GMT还能画三维地形。gmt grdview命令可以生成带透视效果的三维地形图:

gmt grdview dem.grd -JM15c -R95/105/28/35 -JZ5c -Ctopo.cpt -Ishadow.grd -Qm -Bafg -p135/30

-JZ5c表示Z轴高度5厘米,-Qm表示用网格线而不是面来渲染,-p135/30表示视角方位角135度、仰角30度。三维图在展示地形起伏的宏观特征时非常直观,但细节不如二维图清晰,适合放在报告的概览部分。

6.3 叠加水系和断层线

地形起伏图如果只有DEM,信息量还是有限。我经常会在上面叠加水系和断层线。水系数据可以从公开的HydroSHEDS下载,断层线可以从全球活动断层数据库获取。叠加的方法是用gmt plot

gmt plot rivers.shp -W0.5p,blue -R95/105/28/35 -JM15c gmt plot faults.shp -W1p,red,- -R95/105/28/35 -JM15c

-W控制线宽和颜色,0.5p表示0.5磅,blue是颜色,,-表示虚线。叠加的时候要注意图层顺序:先画DEM,再画水系,最后画断层,这样断层线会压在水系上面,视觉层次更清晰。

6.4 自定义颜色表

GMT内置的颜色表虽然好用,但有时候你需要根据特定的视觉风格自定义。CPT文件其实就是文本文件,格式是“高程值 红 绿 蓝 高程值 红 绿 蓝”。你可以用文本编辑器直接改,也可以用gmt makecpt生成后再微调。我常用的一个技巧是:在低海拔用深绿色,中海拔用浅绿色到黄色,高海拔用棕色到白色,这种配色方案在展示植被-地形关系时特别直观。

7. 我踩过的那些坑

第一个坑是忘记设置gmt set的位置。前面提过,gmt set必须在gmt begin之后。我一开始不知道,把字体设置写在了脚本最前面,结果出图字体一直是默认的12磅,改了跟没改一样。

第二个坑是阴影网格和DEM网格范围不一致。有一次我用裁剪后的DEM出图,但阴影网格还是用原始DEM生成的,结果阴影和地形对不上,山脊线错位了。后来养成习惯:每次裁剪DEM之后,重新生成阴影网格。

第三个坑是色标标签里的单位没加-l"Elevation"-l"Elevation (m)"看起来差别不大,但后者明显更专业。审稿人或者读者看到没有单位的色标,会觉得你不够严谨。

第四个坑是输出格式选错。PNG适合屏幕预览,但分辨率有限;PDF是矢量格式,放大不糊,但文件大。如果是投稿用,建议同时输出PDF和PNG,PDF用于印刷,PNG用于在线预览。

第五个坑是没有检查数据的坐标系。有些DEM数据用的是地理坐标系(经纬度),有些用的是投影坐标系(米)。GMT默认按经纬度处理,如果你拿到的数据是投影坐标,需要先用gmt grdproject转回地理坐标,否则出图范围会完全不对。

提示:GMT的官方文档非常详细,但全是英文,而且命令参数太多,初学者容易迷失。我的建议是:先照着能跑通的脚本改,改一个参数看一个效果,慢慢就摸清每个参数的作用了。不要试图一次搞懂所有参数,那不现实。

8. 数据下载的替代方案

如果你在Copernicus或者USGS下载数据时遇到网络问题,还有一些替代方案。比如OpenTopography网站提供了多个DEM数据集的在线裁剪和下载服务,你只需要框选区域,它就会帮你裁好并打包下载。另外,一些大学和科研机构也会在GitHub上分享处理好的区域DEM数据,搜索“区域名+DEM+download”往往能找到惊喜。

对于国内用户,清华大学地球系统科学系维护了一个不透水面数据平台,虽然主要是城市不透水面数据,但他们的数据下载页面也提供了一些基础地理数据的链接。另外,国家青藏高原科学数据中心提供了青藏高原区域的DEM数据下载,注册后即可获取。

下载数据时要注意数据许可协议。大多数科研DEM数据允许免费用于非商业用途,但如果你要用于商业项目,需要仔细阅读许可条款。有些数据要求你在发表成果时引用特定的论文,这个引用格式一般在数据下载页面会有说明。

9. 出图效率的优化建议

最后分享几个提升出图效率的实操经验。第一,把常用的参数写成GMT的配置文件。GMT支持在~/.gmt.conf里设置默认参数,比如字体、边框样式、网格线颜色等。这样你就不用每次都在脚本里写一堆gmt set了。

第二,用gmt begin-V参数控制输出详细程度。默认情况下GMT会输出很多中间信息,如果你只想看错误信息,用-Vq(quiet模式)。调试的时候用-Vd(debug模式),能看到每个命令的详细执行过程。

第三,把DEM数据和阴影网格缓存起来。如果你需要反复出图,每次重新生成阴影网格很浪费时间。可以在第一次生成后把shadow.grd保存好,后续出图直接加载。

第四,用GMT的-c参数指定多面板布局。如果你要在一张图上放多个子图,比如不同区域的地形对比,用gmt subplot可以自动排列,不用手动计算每个子图的位置。

第五,输出前用gmt psconvert做最终转换。虽然gmt begin已经自动处理了格式转换,但如果你需要更精细的控制,比如设置DPI、裁剪空白边缘,gmt psconvert提供了更多选项。比如gmt psconvert -A -Tg -E300表示自动裁剪边缘、输出PNG、分辨率300 DPI。

我在实际使用中发现,GMT6.1的现代模式虽然方便,但有时候自动生成的中间文件会留在当前目录里,时间长了目录会很乱。建议在脚本开头加一行rm -f gmt.*清理旧的临时文件,或者在gmt begin里用-C参数指定一个专门的缓存目录。这个细节虽然小,但能让你的工作目录保持整洁,找文件的时候不至于抓狂。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询