GMT4 脚本风格指南
文章目录
这篇博文会介绍写 GMT 脚本时需要遵循的一些风格与习惯。本文的目的是,希望遵循本风格指南的 GMT 脚本能够更易读、易改、更健壮、可移植性更高。
使用脚本来执行 GMT 命令
GMT 遵循了 UNIX 的设计思想,将不同的功能分别放在不同的命令中,因而在绘图时需要执行一系列命令。
若使用命令行来执行一系列命令,很容易弄混前一个命令是什么。将所有的绘图命令放在脚本中可以很方便地重复执行一系列命令,以对绘图的细节进行微调。
除非是一两个命令就可以解决的图,否则应一律使用脚本而非命令行。
Windows 下常用的脚本是 bat,Linux 常用的是 Bash、Perl 和 Python。使用什么脚本语言完全依赖于用户个人的需求与喜好,这里以 Bash 脚本为例,其他脚本同理。
#!/bin/bash
psxy ...
pscoast ...
grdraster ...
grdimage ...
psxy ...
不要跨平台写脚本
不要在 Windows 下写 Bash 脚本然后复制到 Linux 下运行;也不要在 Linux 下写 Bat 脚本放在 Windows 下运行。这其中会遇到很多坑,包括但不限于:
- 默认编码不同,Windows 用 GBK,Linux 用 UTF8;
- 换行符不同,Windows 用
\r\n
,Linux 用\n
;
如果你真的跨平台写了脚本并遇到各种奇怪的问题时,尝试着新建一个文件,然后把脚本重新手敲一遍。
使用变量
脚本不仅仅只是将一系列命令放在一个文件而已。绘图时有很多需要在多个命令中重复使用的东西,比如设置投影方式的 -J
、设置绘图范围的 -R
、文件名 xxx.ps
。
关于如何使用变量,一般有两种定义方式,这两种方法各有利弊,尚待权衡:
将参数作为变量的值
#!/bin/bash J=M6i R=0/360/-60/60 B=60/30 PS=map.ps pscoast -J$J -R$R -B$B -W1p -A1000 -K > $PS psxy -J -R -Sa0.5c -Gred -O >> $PS << EOF 160 20 150 30 EOF
将选项和参数作为变量的值
#!/bin/bash J=-JM6i R=-R0/360/-60/60 B=-B60/30 PS=map.ps pscoast $J $R $B -W1p -A1000 -K > $PS psxy -J -R -Sa0.5c -Gred -O >> $PS << EOF 160 20 150 30 EOF
不要省略参数
GMT 的一个特性是后面的命令可以继承前面命令的一些参数,比如前面的命令中指定了
-JM10c -R0/360/-60/60
,后面的命令可以直接使用 -J -R
而不用重复给出更多的参数。
这样的设计减少了用户的键入。
省略参数虽然带来了一点点方便,但也可能会造成一些麻烦:
- 写 GMT 脚本时由于需要经常修改、增添命令或调整各个命令之间的顺序。在省略了部分参数的情况
下,调整各个命令之间的顺序就可能导致
-J -R
出现在第一个,有时会造成意想不到的错误。 - 参数可以省略本质上是因为之前的命令将参数写到了文件
.gmtcommands
中,因而当在同 一个目录里同时运行两个相同或不同的脚本时,两个脚本就会读写同一个.gmtcommands
文件, 进而可能导致一个脚本读到的内容是另外一个脚本写的。
因而,尽量不要省略参数。相同的参数在多个命令里要写很多遍,这样很麻烦,但是因为前面已经把这些 参数定义成变量了,所以只是多敲了几个字符而已,因此带来的好处可不少。
#!/bin/bash
J=M6i
R=0/360/-60/60
B=60/30
PS=map.ps
pscoast -J$J -R$R -B$B -W1p -A1000 -K > $PS
psxy -J$J -R$R -Sa0.5c -Gred -O >> $PS << EOF
160 20
150 30
EOF
开始与结束
多个绘图命令会将 PS 代码依次写入到一个 PS 文件中。绘图命令的顺序有时会影响到成图的效果,
最常见的例子就是,如果先 pscoast
再 grdimage
,则 grdimage
的效果就会覆盖
pscoast
的效果。因而在绘制一张稍复杂的图时,经常需要在原有的代码中增添、删除或修改
已有命令的顺序,这个时候尤其需要注意 -K
、 -O
以及重定向符号的使用。
下面的代码解决了这个问题:
#!/bin/bash
J=M6i
R=0/360/-60/60
B=60/30
PS=map.ps
# 写入 PS 文件头
psxy -J$J -R$R -T -K > $PS
# 一系列绘图命令
pscoast -J$J -R$R -B$B -W1p -A1000 -K -O >> $PS
# 写入 PS 文件尾
psxy -J$J -R$R -T -O >> $PS
此处使用了专门的两个命令用于开始和结束一个 PS 绘图。这样做的好处在于:中间的所有绘图命令都使用 -K -O >>
,不必再考虑这个命令是第一个还是最后一个了,也可以随意删除或修改任何一个命令而不必担心造成其它效果。
因而,实际写绘图脚本时,先把开始和结束这两个命令写对,然后在两个命令的中间写入真正的绘图命令。每新增一个绘图命令,都可以执行一下脚本,以检查绘图效果,若效果正确,则继续添加下一个绘图命令。
使用 SI 单位制
GMT 支持 SI 单位制和 US 单位制,默认是 SI 单位制。由于 GMT 的开发者是美国人,官方的文档使用的是 US 单位制,因而国内的 GMT 用户在学习的过程中也就习惯性地使用了 US 单位制。
实际上,国内用户对于 US 单位制没有太多的概念, -X1i
远远没有 -X2.5c
直观。
SI 单位制是国际标准单位,也是中国人熟悉的单位,使用 SI 单位制会使得微调更简单。
不要依赖于 GMT 的系统设置
你所写的每一个脚本,将来都可能传给后来人使用,可能在任一台机器上使用。要保证脚本每次运行的结果完全一致,并不是一个简单的事情。
不要修改 GMT 系统设置
有些人喜欢使用特定字体,或者喜欢使用特定尺寸的纸张,这可以通过修改 $GMTHOME/share/conf
下的一堆系统配置文件来实现。但是,不要这样做,这会导致脚本在别人的机器上跑出来完全不一样的结果。
不要省略单位
当使用 -JM10
时,GMT 会默认使用当前的系统默认单位(一般来说是 c
,也就是厘米),当脚本在另一台系统默认单位为 i
的机器上运行时,绘图的结果会完全不同。
default 文件的使用
不要手动修改 default 文件!
GMT 中提供了 gmtset
命令可以用于修改缺省参数,比如标题的字体、大小等等。该命令会在当前工作目录下生成一个 .gmtdefaults4
文件,进而影响到接下来绘图命令的执行效果。
合理的使用方式如下:
#!/bin/bash
# 用 gmtset 修改默认参数
gmtset BASEMAP_TYPE plain
# 绘图
psxy ...
pscoast ...
psxy ...
# 删除参数文件
rm .gmt*
在脚本的最后 rm .gmt*
至少删除了两个临时文件,一个是 .gmtcommands
,其记录了
通用选项的一些信息,另一个是 .gmtdefaults4
,记录了当前的缺省参数。
删除这些文件的原因在于:
- 临时文件,应该删除。
- 脚本已经执行完毕,不应该遗留下无用的文件。
- 保留
.gmtdefaults4
文件,可能会导致下次执行脚本时产生不同的效果。例如,脚本中首先使用了默认字体 0,然后绘制了一部分图,再使用gmtset
修改字体为字体 1,又绘制了一部分图,若忘记删除.gmtdefaults4
文件,则该文件会成为下次执行脚本时的默认参数文件,导致默认字体变成 1,因而出现不同的绘图效果。
有这样一种可怕的情况:假如你在 $HOME
下执行了 gmtset
命令,然后画了一个简单的图,但是却忘记删除 $HOME
下生成的 .gmtdefaults4
文件,这会影响到其它目录中几乎所有 GMT 脚本的执行效果,而且这个问题很难排查。要避免这种情况的发生需要遵循几个原则:
- 尽量不要在
$HOME
下执行 GMT 命令(可能会产生临时文件,难以清理) - 尽量不要使用命令行执行 GMT 命令(因为你很可能会忘记你刚刚执行过哪些命令)
- 使用
gmtset
的脚本,最后一定要记得删除.gmtdefaults4
-P 选项的使用
只有第一个绘图命令中的 -P
选项是起作用的,所以不需要在每个绘图命令里都使用 -P
选项,
当然若是每个绘图命令都使用了 -P
选项也没有问题,只是不够简洁而已。
两种推荐的使用方式:
在开始 PS 文件时使用该选项:
#!/bin/bash J=M20c R=0/360/-60/60 B=60/30 PS=map.ps psxy -J$J -R$R -T -K -P > $PS pscoast -J$J -R$R -B$B -W1p -A1000 -K -O >> $PS psxy -J$J -R$R -T -O >> $PS
修改
PAGE_ORIENTATION
,不使用-P
选项#!/bin/bash J=M20c R=0/360/-60/60 B=60/30 PS=map.ps gmtset PAGE_ORIENTATION portrait psxy -J$J -R$R -T -K > $PS pscoast -J$J -R$R -B$B -W1p -A1000 -K -O >> $PS psxy -J$J -R$R -T -O >> $PS rm .gmt*
不要滥用 - B 选项
-B
选项用于绘制边框并控制边框的绘制效果。
即每个使用 -B
选项的命令都会绘制一次边框,在没有使用 -X
和 -Y
的情况下,多个命令重复使用 -B
选项会绘制多次边框,但由于边框是重合的,所以会看不出来区别。
对于 -B
选项,合理的用法是仅在第一个命令中使用。
verbose 模式
GMT 命令的输出信息常用于在写脚本时判断命令执行是否正确,而在真正执行时过多的输出信息反而会扰乱用户的屏幕输出。合理的使用 verbose 模式的方式有三种:
写脚本时每个命令都加上
-V
选项,待确认脚本正确无误之后删除所有-V
。定义 Verbose 变量
#!/bin/bash J=M20c R=0/360/-60/60 B=60/30 PS=map.ps V=-V # 调试时用这个 #V= # 调试完成用这个 psxy -J$J -R$R -T -K -P $V > $PS pscoast -J$J -R$R -B$B -W1p -A1000 -K -O $V >> $PS psxy -J$J -R$R -T -O $V >> $PS
修改缺省参数
#!/bin/bash J=M20c R=0/360/-60/60 B=60/30 PS=map.ps gmtset VERBOSE TRUE psxy -J$J -R$R -T -K > $PS pscoast -J$J -R$R -B$B -W1p -A1000 -K -O >> $PS psxy -J$J -R$R -T -O >> $PS rm .gmt*
从使用上的简洁来看,最简单的是第三种方法。
慎用 - X 和 - Y
使用这两个选项会导致坐标原点的移动。因而使用的时候需要相当慎重。
- 除极个别的情况外,
-X
和-Y
选项应该仅在绘制组合图(即一张图多个子图)时使用; - 对于非组合图,也可以在第一个绘图命令中使用
-Xc -Yc
使得整个绘图框架位于纸张的中央; - 不要仅仅为了将某个符号或文字移动到某个位置就使用这两个选项,如果真的有这种需求的话,应该使用绝对坐标
-Xa1c -Ya1c
,其仅影响当前命令的绘图位置。
网格文件后缀
GMT 主要使用 netCDF 格式作为网格数据的格式,其标准后缀名为 .nc
。
需要注意以下两个事实:
- GMT 不会对后缀进行检测,所以后缀是什么都不重要
- GMT 之前的版本中曾经自定义了一种网格数据格式,并使用后缀
.grd
,因而很多脚本中都使用了.grd
作为后缀。
修订历史
- 2014-05-13:初稿;
- 2014-05-16:关于 “网格文件后缀” 的说明;
- 2015-03-17:不要跨平台写脚本;
- 2015-08-08:省略参数可能导致的两种问题;
文章作者 SeisMan
上次更新 2015-08-08