14.14 制作动画¶
GMT自身只能生成静态图片,并不具备制作动画的功能。但动画的本质就是将一系列静态的图片(每张静态图片称为动画的一帧)按照顺序快速切换。因而可以利用GMT绘制多张静态图片,再利用外部工具将这些静态图片转换成单个动画文件。
使用GMT制作动画时,通常需要考虑如下问题:
- 一张动画需要多少帧?帧数太少会导致动画存在不连续感,帧数太多可能导致绘制/播放很长时间、文件过大。因而通常将相关参数定义为变量,方便根据实际情况进行微调
- 不变的元素有哪些?通常一张动图中有些元素是不变的,比如底图、海岸线、图例等等。如果在每一帧静态图片中都重复绘制这些元素,则会浪费大量时间。在绘制静态图片时,可以将这些不变的元素先绘制完,然后将未关闭的PS文件复制到新文件中,并在新文件中绘制余下的部分
- 确定文件名。由于要生成一系列静态图片,且将静态图片转换为动图时图片需要按照固定顺序排列,因而必须使得每张静态图片的文件名唯一且依次递增。通常的做法是设定一个帧计数器,其值初始化为0,并随着循环不断递增。文件名则由文件名前缀和帧计数器共同决定,例如
plot_0001.ps
。需要注意,文件名中0001
的前置 0 不可省略,否则在转换成动图时各帧之间的先后顺序会出错 - 每一帧生成的PS文件均需要使用 psconvert 将其转换为PNG等格式
- ImageMagick的
convert
命令可以将图片转换成gif或者avi等格式
14.14.1 绘制正弦函数动画¶
#!/bin/bash
n_frames=18 # 帧数
name=anim01 # 文件名前缀
. gmt_shell_functions.sh
# 绘制静态的底图
angle_step=`gmt math -Q 360 ${n_frames} DIV =`
angle_inc=`gmt math -Q ${angle_step} 10 DIV =`
gmt psbasemap -R0/360/-1.2/1.6 -JX3.5i/1.65i -P -K -X0.35i -Y0.25i \
-BWSne+glightgreen -Bxa90g90f30+u\\312 -Bya0.5f0.1g1 \
--PS_MEDIA=4ix2i --FONT_ANNOT_PRIMARY=9p > $$.map.ps
mkdir -p $$ # $$是当前进程的ID,用于构建唯一的文件夹和文件名
frame=0
# 开始循环生成静态图片
while [ ${frame} -le ${n_frames} ]; do
# 文件名格式为 name_##
file=`gmt_set_framename ${name} ${frame}`
cp -f $$.map.ps $$.ps
angle=`gmt math -Q ${frame} ${angle_step} MUL =`
if [ ${frame} -gt 0 ]; then # 第一张图不绘制曲线
# 绘制曲线
gmt math -T0/${angle}/${angle_inc} T SIND = $$.sin.d
gmt psxy -R -J -O -K -W1p,blue $$.sin.d >> $$.ps
gmt math -T0/${angle}/${angle_step} T SIND = $$.sin.d
gmt psxy -R -J -O -K -Sc0.1i -Gdarkred $$.sin.d >> $$.ps
fi
# 绘制红点
sin=`gmt math -Q ${angle} SIND =`
gmt psxy -R -J -O -K -Sc0.1i -Gred >> $$.ps <<< "${angle} ${sin}"
printf "0 1.6 a = %03d" ${angle} | gmt pstext -R -J -F+f14p,Helvetica-Bold+jTL \
-N -Dj0.1i/0.05i -K -O >> $$.ps
gmt psxy -R -J -O -T >> $$.ps
# 将生成的PS文件转换为TIF文件
gmt psconvert -E125 -Tt -F$$/$file $$.ps
echo "Frame ${file} completed"
# 递增frame
frame=`gmt_set_framenext ${frame}`
done
# 将静态图片转换为动图
gm convert -delay 20 -loop 0 $$/${name}_*.tif ${name}.gif
# 清理
gmt_cleanup .gmt