Introducing Gnuplot
使用 Gnuplot
Gnuplot Interactive Environment
First Encounter
Gnuplot 有一个交互式命令界面,在 shell 里输入 gnuplot
回车,就会看到
Gnuplot 打印出一些版本信息,然后显示 gnuplot>
,这是它的命
令提示符。下面我们来输入第一个 Gnuplot 命令:
> plot sin(x)
注意第一个 >
字符表示提示符,不要输入。回车后应该会看到 Gnuplot 打开了
一个有工具栏的窗口,里面画着熟悉的正弦曲线。现在试着把这个窗口缩小到一
半大小,怎么样?字看不清了吧?点一下工具栏里的“Apply autoscale”按钮,
让 Gnuplot 重画窗口。
在上面的例子中,我们已经使用了 Gnuplot 的 plot
命令。在 Gnuplot 中,
只存在两个画图的命令:plot
和 splot
。其中 plot
用来画二维图形,
splot
用来画三维图形。同时我们还见识了 Gnuplot 的内置数学函数 sin。
再试一个复杂点的:
> plot sin(x) + sin(1.1*x)
貌似和前面的差不多?那是因为我们画出的范围太小。在 plot 命令中,我们可 以手动指定自变量的范围
> plot [-50:50] sin(x) + sin(1.1*x)
在 Gnuplot 中,我们使用 [min:max]
这样的语法来定义范围。这次能完整的看
到一拍了。但是有个问题:画出来的图都变成折线了。这是因为Gnuplot 默认取
点太少。对于变化比较平缓的曲线,默认的取点已经足够。如果需要手动指定采
样率的话,可以设置 samples
变量。变量的设置在 Gnuplot 中至关重要,在画
复杂图形的时候,往往会有几十行的变量设置,但画图的命令可能只有最后一行。
我们使用 set
命令设置变量。
> set samples 1000
Gnuplot 绘图需要使用一系列点,并把它们按顺序用直线连接起来。如果需要绘
制的是一个函数,他就会每隔一定的 x [三维是 (x, y)] 计算出一个函数值,作
为绘图的数据。变量 samples
指定在绘制函数时,我们在绘图区间内取的采样个
数。个数越多曲线越平滑。执行上面的命令后,你会发现曲线并没有变,还是原
来的德性。Gnuplot 不会自动更新曲线(因为如果变量设错了,绘制可能会很
慢),我们需要手动更新。
> replot
终于,我们的图形平滑了。
在实际使用的时候,绘制函数图形的需求不大,绘制数据才是最重要的。plot 命令可以读取空格(或 tab)分隔的数据文件,比如下面这个:
# Example data 1 1 1.5 2 2.1 2.5 3 2.3 3.2 2.1
注意第一行以 #
开头的是注释,会被 Gnuplot 忽略。把这段文本存为
data.txt
,然后在 Gnuplot 里执行
> reset
> plot "data.txt"
第一行 reset
命令把我们之前设置的所有变量全部设成默认值。执行后会看到
Gnuplot 画出了 5 个点(第一个在左边的纵坐标轴上,红色的,仔细找)。这
个图很丑,数据之间的关系也不明确。你可能会希望把点和点之间用线连起来。
这可以用两种方式完成:
> plot "data.txt" with linespoints
选项 with
指定 Gnuplot 对数据的表示方法,“linespoints
”
是其中的一种。如果希望以后的所有对数据的 plot 都是用这种方式,可以设定
style
变量:
> set style data linespoints
> replot
在 Gnuplot 中有许多 style,比较特殊的是 errorbars
和 candlesticks
style,这些 style 需要数据中附加的列来表征多出的维度。
获取帮助
Gnuplot 包含大量的命令和变量,一般的地球人不可能把它们的用法全部记住。
当你忘记了一个变量的用法时,可以查阅手册,但一个更快捷的方法是使用
Gnuplot 的在线文档。Gnuplot 的在线文档包含手册的全部内容,并且方便程度
不亚于 Emacs 的 info-mode。假设我们要查 style
命令的用法,
只需执行
> help style
Gnuplot 就会给出 style
的详细信息。现在假设我们看完后决定试用一种新的
style: impulses
。我们对这个 style 一无所知,只是看名字比
较诡异。怎么办?按 q
退出试试,看到了吧?Gnuplot 提示你输入 style
的
subtopic。输入 impulses,就会看到它的介绍了。看完后按 q
退出一层,再按
Ctrl+C
退回提示符。如果一个条目有好几层 subtopics 的话(比如 plot
命
令),Gnuplot 就会一层一层的提示你,知道你狂按 C-c
退到提示符为止。
曲线拟合
恐怕大部分人对 Origin 最深刻的体会就是不知道在哪里拟合,即使碰巧打开了 一个拟合的窗口,也会发现里面只能线性拟合,然后郁闷地关上。拟合是 Gnuplot 的强项,凭借先进的 UI,gnuplot 的拟合功能可以在两条命令之内完 成,而且可以拟合为任何函数。假设我们想把上面那个数据文件拟合为抛物线, 只需执行
> y(x) = a*x**2 + b*x + c
> fit y(x) "data.txt" via a,b,c
第一条命令定义了一个叫 y 的函数,注意在 Gnuplot 里,求幂的操作符是
**
。第二条命令就是传说中的 fit
了。其中的 via
是关键字,
后面跟着需要拟合的变量列表。回车后 Gnuplot 会打印出一大票信息,我们只
需要关心结尾的几行,这里把它贴出来:
Final set of parameters Asymptotic Standard Error `=====================` `========================` a = -0.807933 +/- 0.04386 (5.428%) b = 3.87664 +/- 0.1894 (4.887%) c = -2.04687 +/- 0.179 (8.747%) correlation matrix of the fit parameters: a b c a 1.000 b -0.992 1.000 c 0.948 -0.979 1.000
其中 “Final set of parameters” 和 “Asymptotic Standard Error” 是我 们想要的,最后还打印了数据的关联矩阵。
怎么样?简单吧?我们已经完成了拟合,现在可以把它画出来了。
> plot "data.txt", y(x)
结果很 PP 吧? :-) 这个命令虽然简单,也引入了一些新的东西。现在我们知道怎么在一个图里画 100 条曲线了:用 99 个逗号分隔。
做出专业的图
上面的图虽然很 PP,但是如果你做个这样的图拿给导师,一定会被暴扁一顿然 后到教室/实验室后面罚站 100 天。因为这个图还缺少图例、坐标名称和标题。 当然,严格地说图例已经有了,只是很搓而已。先把这个图例搞好:
> set key right bottom
> plot "data.txt" title "Some Data", y(x) t "~x^2"
第一行设置图例的位置在右下角,第二行和前面的 plot
命令的不同就是给每一
个曲线都设置了一个标题,显示在图例中。注意在 Gnuplot 中,很多关键字都
有简写,比如这个 title
选项就可以简写为 t
。有人说了,你那个 x^2
太呆了,就不能搞成 \(x^2\) 么?当然可以了!Gnuplot 怎么可能那么
弱智… 不过这个问题要放到后面讲 terminal 的时候再说。下面设置坐标名
称和标题:
> set xlabel "t"
> set ylabel "A"
> set title "A Dumb Figure"
这个都能看懂,就不说了。赶快 replot
一下,好看多了吧?赶快
拿给导师。“叔叔… 这是我最新画的图,你看漂漂不?”
Gnuplot Scripting
Terminal
现在我们已经做出了 PP 图,下一步是什么?有人说了,发给审稿人显摆一下^^。
发个毛啊!你存成 EPS 了么?!所以下一步是把图保存成某种格式。怎么保存呢?
你是不是开始在工具栏里找“保存”按钮了?如果是的话,说明你已经被 M$ 洗
脑了。在 Gnuplot 中,我们设置 terminal
变量(可以简写为
term
)来指定“保存”的格式。这个变量告诉 Gnuplot 你要以什
么方式/格式来展示图形,默认值为 wxt
,表示使用一个
WxWidget 窗口来显示图形。要设置格式为 EPS,我们只需把这个变量设为
postscript
(可以简写为 post
):
> set term post eps
> replot
你是不是看到了一坨乱七八糟的代码?对了。那个就是 Gnuplot 生成的
postscript 代码。term
的选项 eps
指示 Gnuplot 生成一个
Encapsulated Postscript 文件。当然我们会希望把它保存到一个文件里,这个
可以通过设置 output
变量实现:
> set output "test.eps"
> replot
用一个 postscript 查看器/打印机看看生成的文件。
第一个 Gnuplot Script
现在我们已经设置了很多变量,如果你不幸关闭了 Gnuplot,想在下次启动时实 现现在的效果,就要把这些变量重新设置一遍。能不能把这些东西都存到文件里, 让 Gnuplot 一下一起搞定呢?当然可以,而且我一般都是这样使用 Gnuplot 的。 Gnuplot 文件就是一个纯文本,可以用普通的文本编辑器编写。格式也很简单, 只要把我们在 Gnuplot 提示符后面输入的东西照抄一遍就行了。下面是一个简 单的 Gnuplot script:
# test.gnu
set term post eps color
set output "test.eps"
set size 0.5, 0.5
set xlabel "t"
set ylabel "A"
set title "A Dumb Figure"
plot "data.txt"
在这个文件中,有一个我们没见过的变量 size
,这个变量的作用
是设置输出图形的大小为设置前的一定比例。比如 Gnuplot 的 Postscript 格式
的默认大小是 10in x 7in,设置 size
为 0.5,0.5
以后的大小变为 5in x
3.5in。变量 terminal
的选项 color
指示 Gnuplot 生成带颜色的图形,和在窗
口中看到的一样;也可以指定为 monochrome
,不同的曲线将以不
同的线型加以区分。要执行这个文件,只需在 shell 中输入 gnuplot test.gnu
即可。
Teminal, Enhanced
现在我们可以开始解决原来的 "x^2" 问题了。Gnuplot 提供了一种 enhanced
termianl 机制来输入这些数学符号,开启后输入 x^2
就会输出成
\(x^2\)。开启 enhance 的方法是在 terminal
变
量的后面加上选项 enhanced
。比如
set term postscript eps color enhanced
set output "test.eps"
set title "x^2 Against {/Symbol b}"
plot "data.txt" t "x^2"
其中 {/Symbol b}
输出为一个 β。Enhanced termianl 还有很多
其他用法,基本可以满足对数学符号的各种需要。使用方法简单,功能强大,非
Origin 之流可比。详细的解释请见 Gnuplot 源码包中附带的
ps_guide.ps
。
Gnuplot for Real
在这一节,我们将使用一个实际科研中碰到的例子来讲解 Gnuplot 的使用方法。 考虑这个数据文件,它表征了一个磁性系 统的标度行为,在理想情况下应该满足 \$y = Ax^{\beta}\$ 的函数关 系,其中 A 为常数。我们的目标是 —— 没有蛀牙!噢,错了,是求出指数 β, 并把它清晰的表示出来。
在一开始,我们还不知道该怎样画这个图,先在 Gnuplot 的交互命令行里试着 plot 一下吧^^ 噼里啪啦,感觉还行,只是左边挤得太扁了,什么都看不出来。 如果你对这种幂函数比较了解,应该知道如果使用双对数坐标画图,幂函数的曲 线是一条直线,斜率即为幂指数,貌似符合我们的要求,那就试试双对数坐标吧。
> set logscale xy
> replot
变量 logscale
的用法就不说了,作为作业吧^^。现在我们开始拟合:
> y1(x) = A1*x**b1
> y2(x) = A2*x**b2
> fit [0.01:0.3] y1(x) "data.txt" via A1,b1
> fit [3:30] y2(x) "data.txt" via A2,b2
> plot "data.txt", y1(x), y2(x)
看起来还不错,现在我们可以开始写 Gnuplot 脚本了。开头先把变量设了。
set term postscript eps enhanced color
set size 0.8,0.8
set output "figure.eps"
set logscale xy
set style data linespoints
set xrange [0.007:40]
set yrange [1:50]
set key left top
其中 xrange
和 yrange
设置绘图的范围。现在拟合,并把曲线画出来。
y1(x) = A1*x**b1
y2(x) = A2*x**b2
fit [0.01:0.3] y1(x) "data.txt" via A1,b1
fit [3:30] y2(x) "data.txt" via A2,b2
plot y1(x) t "{/Symbol b} in low-{/Symbol w} regime" lt 2, \
y2(x) t "{/Symbol b} in high-{/Symbol w} regime" lt 3, \
"data.txt" t "Exponential" lw 2 lt 1
注意在 Gnuplot 中,如果一条命令分成了多于一行,要在除最后一行的行末加
一个 \
。lw
参数设置曲线宽度为 2,lt
设置曲线的 linetype,一般来
说 lt 1
是醒目的红色,以上的 plot
参数保证 data.txt
的曲线在两条
直线的上方,并且是红色的实线。现在图画出来了,效果不错,但是光看这个图
还是不知道指数 β 到底是多少,最好是直接把它指明。Gnuplot 提供了
label
变量(!居然是个变量!),用来在指定的位置添加一段文字。
set label 1 sprintf("{/Symbol b} = %.2f", b1) at 0.09,10 right
set label 2 sprintf("{/Symbol b} = %.2f", b2) at 4.5,8 right
在这里我们使用了 Gnuplot 的内置函数 sprintf
,用法就不说啦,相信有 C
语言经验的同学都明白。注意这段要添加在 plot
命令的前面,否则无效,以
下所有的变量设置都是如此。
现在我们的图已经很像回事了,可以最后添加一些装饰~~
set xlabel "{/Symbol w}"
set ylabel "A"
set title "Exponential relation between A and {/Symbol w}"
大功告成,你可以拿着这个图对用 Origin 的人显摆一下 :-)。
现在,我们对 Gnuplot 提一个难题:把坐标上的数值改成 \$10^n\$ 这种形式,就是说 1 这个刻度显示成 \$10^0\$,10 显示成 \$10^1\$,点点点。这种形式看起来很清晰,很爽快,很装逼。我们的思路是让 Gnuplot 自己对每一条数据的两个分量都求以 10 为底的对数,然后把坐标刻度的显示方式变一下。这个好像很变态,其实在Gnuplot里是一件再简单不过的事:只要设一下 format
变量和 plot
的 using
选项就行了:
set format "10^{%.1f}"
plot "data.txt" using (log10($1)):(log10($2))
这里把那两条拟合的直线省略了。选项 using
的使用比较复杂,这里很难说清楚,
请参阅 Gnuplot 手册。注意这时的坐标应该是线性的,而且我们应该调整绘图范
围:
unset logscale
set xrange [-2.2:2]
set yrange [0:1.6]
命令 unset
删去一个变量的值。注意如果一个变量的默认值不是空的,那么
unset
和设为默认值是不一样的。如果你把 xtics
这个变量给 unset 了,画出
来的图就会没有 x 轴刻度,而不是把刻度设为默认的样子。