14.14 制作动画

GMT自身只能生成静态图片,并不具备制作动画的功能。但动画的本质就是将一系列静态的图片(每张静态图片称为动画的一帧)按照顺序快速切换。因而可以利用GMT绘制多张静态图片,再利用外部工具将这些静态图片转换成单个动画文件。

使用GMT制作动画时,通常需要考虑如下问题:

  1. 一张动画需要多少帧?帧数太少会导致动画存在不连续感,帧数太多可能导致绘制/播放很长时间、文件过大。因而通常将相关参数定义为变量,方便根据实际情况进行微调
  2. 不变的元素有哪些?通常一张动图中有些元素是不变的,比如底图、海岸线、图例等等。如果在每一帧静态图片中都重复绘制这些元素,则会浪费大量时间。在绘制静态图片时,可以将这些不变的元素先绘制完,然后将未关闭的PS文件复制到新文件中,并在新文件中绘制余下的部分
  3. 确定文件名。由于要生成一系列静态图片,且将静态图片转换为动图时图片需要按照固定顺序排列,因而必须使得每张静态图片的文件名唯一且依次递增。通常的做法是设定一个帧计数器,其值初始化为0,并随着循环不断递增。文件名则由文件名前缀和帧计数器共同决定,例如 plot_0001.ps。需要注意,文件名中 0001 的前置 0 不可省略,否则在转换成动图时各帧之间的先后顺序会出错
  4. 每一帧生成的PS文件均需要使用 psconvert 将其转换为PNG等格式
  5. 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
../../_images/anim01.gif