自由軟體與資訊公民聯網
2004/05/11
GNUPLOT 是一套跨平臺的數學繪圖自由軟體, 可以繪製數學函數圖形, 也可以從純文字檔讀入簡單格式的座標資料, 繪製統計圖表等等。 它不是統計軟體, 也不是數學軟體。 它的設計符合 組合學習 的理念: 專心做一件事 -- 純畫圖 -- 就好, 但是把這件事做得非常完整, 並且與其他軟體保持良好的溝通管道。 大力推薦給所有理工科系的同學, 及其他任何科系需要做統計繪圖的同學。 如果再學一點 regular expression, 更可以將任何有規律的文字座標檔轉換成 gnuplot 認得的簡單格式, 滿足你任何資料繪圖的需求。 這, 才是不會退流行, 具有長遠投資價值, 值得用心學習的技術。
另外, 我還幫它寫了一個 GUI 控制前端 dynagpt-0.4, 非常適合國中到大學程度的解析幾何教學, 可惜還沒有時間寫手冊。
現在就讓我們直接在命令列打 gnuplot 進入它的命令列環境。
plot x*x-4*x+3 |
# 畫一條拋物線。 注意它的對稱軸在 x=2。 |
a=1; b=-2; c=3 |
# 設定一些變數。 |
plot a*x*x+b*x+c |
# 畫另一條拋物線。 注意它的對稱軸在 x=1。 |
b=6; replot |
# 第三條拋物線。 它的對稱軸則是在 x=-3。 |
show xzeroaxis |
# 目前的設定, 並不會顯示 x 軸。 |
set xzeroaxis |
# 那麼將這個設定打開吧。 |
replot |
# 重畫一次, 可以看到它與 x 軸有兩個交點。 |

請自己畫畫看:
不必擔心, 這只是起個頭, 等一下大部分的例子與數學都沒有直接的關係。 我們有興趣的是 gnuplot 的操作, 不是數學; 而且下面的例子多半使用資料檔, 較少畫數學函數。
當然, 學任何一套軟體, 最先要學的就是:
exit 或 quit 或直接按 ^D
help replot 當然像 set 或 plot
這種複雜的指令, 進入 help set 或 help plot 之後, 還有子選單。 另外, 命令列的快速鍵也很值得學。 gnuplot 用的並不是真正的 readline 介面, 只提供其中少數幾個最常用功能, 但已經很方便。
這份資料 popgrowth.txt 記載著美國加州與阿拉斯加州的人口成長史。
plot "popgrowth.txt" |
# 繪製加州人口成長史。 |
show data style |
# 現在看起來醜醜的, 因為沒有連線。 |
set data style lines |
# 設定成連線模式。 |
set grid |
# 模擬方格紙效果。 |
set title "population growth" |
# 加上標題。 |
replot |
# 重畫一遍, 好多了。 |
plot "popgrowth.txt" using 1:3 |
# 改繪製阿拉斯加州人口成長史。 |
show ytics |
# 看看 y 軸標示。 |
set ytics 100000 |
# 將 y 軸標示改設定成每 10 萬一格。 |
show ytics |
# 再看一次 y 軸標示。 (以下不再囉嗦) |
replot |
# 重畫一遍。 |
plot "popgrowth.txt" |
# 回頭看加州人口成長史... 怎麼會這樣? |
set ytics autofreq |
# 還是讓它自動設 y 軸標示吧。 |
set logscale y |
# 像這種情況, 用 logscale 畫圖最合適了 |
plot "popgrowth.txt" using 1:2, "popgrowth.txt" using
1:3 | |
set output "growth.png" ; set term png ;
replot | |
set output ; set term x11 ;
replot | |

很多設定可以用 set 命令更改。 建議用對應的 show 命令查看一下更改前後的設定。
接下來我們從美國 Census Bureau 的 TIGER/Line 網站 下載加州與內華達州諸郡的邊界座標檔, 稍微修改格式後, 用 gnuplot 畫出地圖。 沒辦法, 我也想以臺灣為例, 可是在網路上找不到類似的, 關於臺灣的資訊。
從上述網頁出發, 循著 "Cartographic Boundary Files" ==> "Download Boundary Files" ==> "County and County Equivalent Areas", 最後找到 加州諸郡的邊界座標檔。 注意我們要的是簡單的 ascii 格式, 不是 e00 格式。 解壓縮之後, 用 vim 看一下, 發現有兩個問題:
於是借用 regular
expression 將之轉換成 gnuplot 認得的格式: perl -pe
's/^\s*\S+\s+\S+\s+\S+\s*\n//; s/END//' co06_d00.dat > california.txt。
又, 我想把檔案變小, 所以進一步用 一個簡單的
perl script 刪除太接近的點, 產生 california_reduced.txt;
讀者可省略此步驟, 直接用原本的 california.txt, 畫出來的圖反而比較漂亮。
以同樣的方式, 下載並處理 Nevada 州的地圖, 產生 nevada_reduced.txt。
然後進入 gnuplot 並下指令 : plot "california_reduced.txt",
"nevada_reduced.txt" 結果發現畫出來有點醜, 比例不太對。 在緯度 38 度附近, 經度每一度的距離, 大約是緯度每一度距離的
4/5, 或者更精確地說, 這個比例是 cos(38度)。 所以設定新的比例 set size ratio
1/cos(38/180.0*pi) 重畫一遍。 倒不是我記得很清楚是誰比誰, 反正不是 cos(...) 就是 1/cos(...)
試試看就知道了啦。 如果你想知道比例究竟設成多少, 可以下 print 1/cos(38/180.0*pi) 把這個比值印出來。
注意數學運算當中, 兩個整數相除, 會無條件捨去, 所以這裡的 180 寫成 180.0。

美國中情局網站有一個檔案可以下載, 叫做 CIA Fact Book 裡面有世界各國簡介, 對地理老師應該有一些用處。 解壓縮之後有一個 factbook/print 目錄。 我寫了一支小程式 ciafbxf 從那個目錄下的所有檔案裡面, 將一些最基本的資料擷取出來成為 all_countries.txt。 以下我們要從這個檔案裡面抓出亞洲各國的資訊, 以人口當做 x 軸, 土地面積當做 y 軸, 用 gnuplot 將各國名稱畫在座標平面上。
首先用 grep 過濾, 只取出亞洲國家資訊; 其次用 cut 過濾, 只取出國名, 人口, 與土地面積; 最後把這些資訊化成一堆 set
label ... 指令, 存成一個 gnuplot 命令稿。 注意: 最後一句話太長了, 所以用倒斜線 "\" 告訴 shell
我們的命令還沒有打完。 如果把整個命令打在同一列, 就不必打倒斜線。 語法請參考 regular expression
講義。
grep -i asia < all_countries.txt > tmp1.txt
cut -d : -f 2,5,8 < tmp1.txt > tmp2.txt
perl -ne 'print qq(set label "$1" at $2,$3 center\n) \
if /(.*):(\d+):(\d+)/' < tmp2.txt > asia_countries.gpt
然後進入 gnuplot, 用 load 命令載入剛才產生的 gnuplot 命令稿 asia_countries.gpt, 並且以臺灣的人口密度與不丹的人口密度畫兩條線方便比較。 下 plot 畫圖的時候, 可以同時用 title 選項改變 「圖例」 所顯示的字串。 又, 因為 「圖例」 的內定位置是右上角, 與圖中資訊混雜, 所以我們將它移到空空的左上角去, 比較清爽。
load "asia_countries.gpt"
set logscale
set xrange [3e2:3e7]
set yrange [3e5:3e9]
set key top left
plot x*628.21 title "Taiwan", x*45.52 title "Bhutan"

plot sin(x)/x 又如 plot
-2*x*x+7*x+5
set xrange [-2:6]; set yrange [-6:14]
其中分號用來把兩個命令放在同一列上.
replot
set xrange [-1:1]
set yrange [-1:1]
set autoscale z
splot x*x-y*y
(馬鞍面)
splot [-1:1] [-1:1]
x*x-y*y
set term x11set term windowsset term dumbplot sin(x)/x 以下摘要說明中,
(no)xzeroaxis 表示你可以下 set noxzeroaxis; replot 看看不要畫 x 軸的效果, 或下
set xzeroaxis; replot 看看要畫 x 軸的效果. 有些選項 (例如 arrow) 比 "要/不要"
還要複雜, 必須看手冊 (例如 help set arrow) 查看詳細的用法.
show xzeroaxis 可以查詢在目前的設定下, x
軸會不會畫出來; 用 show xrange 可以查詢目前 x 軸方向的數值範圍.
set hidden3d
set isosamples 40
set size 0.5, 0.7
set ztics -1, 0.5
set view 60, 20
splot [-1:1] [-1:1] (x*x-y*y)/(x*x+y*y)
set parametric 指定以下使用參數式, 以後就可以用 t 當做自變量. 當然用參數式畫圖時, 就必須給 plot
兩個數值, 例如 plot t*t, t*t*t 要還原, 可用 set noparametric
("cusp", 有尖角的曲線)
set parametric
set hidden3d
set isosamples 30,50
set view 70, 20
splot v*v, -u, v*(u*u+1)
set polar 指定以下使用坐標表示法,
以後就可以用 t 當做自變量. 例如 plot [0:pi*6] 1/sqrt(1+t*t) 要還原, 可用
set nopolar (向內長的螺旋線)
set parametric 來達成, 要寫成: plot [0:pi*6]
1/sqrt(1+t*t)*cos(t), 1/sqrt(1+t*t)*sin(t)
set parametric
set isosamples 30, 10
set hidden3d
splot [-pi:pi] [-2:2] sqrt(1+v*v)*cos(u), sqrt(1+v*v)*sin(u), v
(但 splot 有支援用球面坐標與柱面坐標畫外部數據資料. 見下節)
plot "apache.dat"
./torus >
torus.dat 產生資料檔, 然後回 gnuplot 內下: set hidden3d
splot [-15:15] [-15:15] [-5:5] "torus.dat" with lines
或者直接在 gnuplot 內下:
set hidden3d
splot [-15:15] [-15:15] [-5:5] "< ./torus" with lines
set contour base
set nosurface
set view 0,0
set cntrparam levels 20
set nokey
splot x*x-y*y
等高線也可以畫在曲面本來在空間中的位置上 (set contour surface); 畫等高線時, 原曲面也可以同時畫出來
(set surface).