用户工具

站点工具


doc:a:add_labels2contours

利用 AWK 给 GnuPlot 绘制的等高线加标记

GnuPlot 是强大的函数绘图工具,是科学计算不可多得的利器,也是目前最好的免费绘图软件。有人会说,MatLab 的绘图能力也很强啊。是滴,MatLab 多贵啊,除了单位给装的,没几个人能用得起正版的。说个题外话,如果 MatLab 打击盗版到没人敢用它,估计 MatLab 离死也不远了。MatLab 的替代品 Octave 一直在等这一天……

GnuPlot 里三维绘图的函数是 splot,它也能够绘制等高线。有个小小的遗憾,splot 目前还不能在等高线上标注其所处的高度。当然,这个小小的遗憾并不是严重的,至少在我眼里,它算不上什么,也不影响理解等高线。

这个帖子的意义,并不在于弥补了 splot 的等高线功能,而在于 UNIX 哲学的一个小小的实践。工具之间良好的接口为它们的相互利用提供了便利,使得众多小巧精致的工具,经过组装就能够形成新工具。

GnuPlot 脚本:绘制等高线并标注其高度

使用方法:在终端键入命令

gnuplot PlotContours.gp

其中,PlotContours.gp 是一个 GnuPlot 的脚本,内容是绘制函数 exp(sin(x))+x*y*y 的 10 条等高线,具体如下。

f(x,y) = exp(sin(x))+x*y*y       # target surface
set samples 100                  #   
set isosample 200                # grid for plot function
set contour base                 # plot contours
NumOfLevels=10                   # number of levels for contours
set cntrparam levels NumOfLevels # set the contour parameter
unset surface                    # no draw of points or lines
set table "contours.dat"         # tabular output to the named file
splot f(x,y)                     # plot the surface
unset table                      # go back to normal plotting
!awk -f add_labels2contours.awk contours.dat > contours.gp
reset
set key outside                  #   
load 'contours.gp'
pause -1 "Hit any key to continue!"

这个脚本中调用了 AWK 脚本,它的主要功能是标注等高线的高度。splot 的等高线输出结果 contours.dat 是一个带格式的文本,大致结构如下所示。AWK 擅长对付这样带格式的文本,从中提取有用的信息或者输出一定格式的报表。也可以用其他语言来完成同样的任务,在目前的情况下,用 AWK 是恰到好处的,不至于大才小用,也不至于力不从心。

# Surface 0 of 1 surfaces

# Curve title: "f(x,y)"
# Contour 0, label:    1e+03
 10  9.99708  1000 
 9.99416  10  1000 

 9.99416 -10  1000 
 10 -9.99708  1000 


# Contour 1, label:      800
 10  8.94089  800  
 9.87957  8.99497  800  
 9.79798  9.03196  800  
 9.66066  9.09548  800  
 9.59596  9.1257  800  
 9.44847  9.19598  800  
 9.39394  9.22223  800  
 9.24272  9.29648  800  
 9.19192  9.3217  800  
 9.04321  9.39698  800  
 8.9899  9.42429  800  
 8.84984  9.49749  800  
 8.78788  9.53027  800  
 8.66255  9.59799  800  
 8.58586  9.63997  800  
 8.48131  9.69849  800  
 8.38384  9.75379  800  
 8.30606  9.79899  800  
 8.18182  9.87222  800  
 8.13669  9.8995  800  
 7.9798  9.99574  800  
 7.97303  10  800  

 7.97303 -10  800  
 7.9798 -9.99574  800  
 8.13669 -9.8995  800  
 8.18182 -9.87222  800  
 8.30606 -9.79899  800  
 8.38384 -9.75379  800  
 8.48131 -9.69849  800  
 8.58586 -9.63997  800  
 8.66255 -9.59799  800

下面的任务就是从 contour.dat 里导出一个 GnuPlot 脚本,其中标注了各条等高线的高度。简单地说,就是在一些坐标点处给出标记(完成这个任务需要了解一些 GnuPlot 编程)。该 AWK 脚本的具体内容如下。

AWK 脚本:标注等高线的高度

这个 AWK 脚本部分参考了 Petr Mikulik 的代码,是原有代码的简化版本,但其效果基本相当。读者可以继续改进,譬如加入 option 选项等。

#!/usr/bin/awk -f
#
# Filename    : add_labels2contours.awk
# Author      : Jiangsheng Yu
# Last update : Feb 10, 2012
# License     : GPLv2
# Description : A simplified Petr Mikulik's AWK script for GnuPlot, to 
#               label the contours generated by "splot" function.
#               The shell command is "gnuplot PlotContours.gp", where
#               the file of PlotContours.gp is as follows.
##################################################################
#   f(x,y) = exp(sin(x))+x*y**2      # target surface
#   set samples 100                  #   
#   set isosample 200                # grid for plot function
#   set contour base                 # plot contours
#   NumOfLevels=10                   # number of levels for contours
#   set cntrparam levels NumOfLevels # set the contour parameter
#   unset surface                    # no draw of points or lines
#   set table "contours.dat"         # tabular output to the named file
#   splot f(x,y)                     # plot the surface
#   unset table                      # go back to normal plotting
#   !awk -f add_labels2contours.awk contours.dat > contours.gp
#   reset
#   set key outside                  #   
#   load 'contours.gp'
#   pause -1 "Hit any key to continue!"
##################################################################

BEGIN {
    contour_index = -1       # initialization of contour index
    step = 20                # distance between labels on the same contour
    print "########## Set labels and their coordinates ##########"
}

# Output format of each line, for instance: set label "10" at 2.4,3.5
NF == 3 && mod(NR,step)==0 { # the data lines that are labelled
    printf("set label \"%s\" at %s,%s\n", $3, $1, $2) 
}

# Add the labels on the original contours generated by GnuPlot
NR == 1 { 
    plotcmd = "plot '"FILENAME"'"
}

# Set the linetype for each contour
$2=="Contour" {
    contour_index++
    if ($3!="0,") plotcmd = plotcmd ",\\\n\t''"   # non-first contours
    plotcmd = plotcmd sprintf(" index %i title '%s' w l lt %i", contour_index, $5, contour_index)
}

END {
    print "\n########## Plot contours and titles ##########"
    print "\n" plotcmd
}

# Definition of function x mod y, i.e., remainder of x/y
function mod(x,y){
    return x-y*int(x/y)
}

########## End of AWK script ##########

至于生成的 contours.gp 的具体内容是什么,读者可以具体尝试一下看看。

几个例子

f(x,y) = exp(sin(x))+x*y**2

f(x,y) = atan(-x**2+y**3/4)

/data/vhosts/wiki-data/pages/doc/a/add_labels2contours.txt · 最后更改: 2013/03/21 01:49 由 IOU