地圖/統計圖/3d 函數圖/實驗報告圖 -- Gnuplot 純畫圖


* * * 也請參考 教學短片 * * *

簡介

GNUPLOT 可以匯入各種文字座標檔, 也可以匯出各種圖檔 是一套跨平臺的數學繪圖自由軟體, 可以繪製數學函數圖形, 也可以從純文字檔讀入大量數據 (例如座標資料), 繪製統計圖表等等。 它不是統計軟體, 也不是數學軟體, 它純粹只是一套函數/資料繪圖軟體。 它只專心做一件事 - 畫圖 - 但是把這件事做得非常完整。 最重要的是, 它與其他軟體保持良好的溝通: 可以產生 png, svg, ps, hpgl, ... 等等開放的圖形檔案格式的輸出, 供文書處理/簡報/試算表/... 等等軟體匯入。 如果再學一點 regular expression, 更可以將任何有規律的文字座標檔轉換成 gnuplot 認得的簡單格式, 滿足你任何資料繪圖的需求。 這種 「組合式學習」 的設計, 在加上它歷久不衰的特性, 使它具有 長遠學習投資價值, 大力推薦給所有理工科系的同學, 及其他任何科系需要做統計繪圖的同學。

Windows 用戶, 下載 時請注意: 如果您的系統已有 cygwin 或 XLiveCD, 則下載 gp400win32x11.zip ; 一般人應該沒有 cygwin/XLiveCD, 因此應下載 gp400win32.zip。

另外, 我還幫它寫了一個 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 軸有兩個交點。

如果你下以上畫圖的命令, 卻有錯誤訊息: use 'set term' to set terminal type first 那麼應先設定繪圖模式。 在 X-Window 下可以設定: set term x11 而在 MS Windows 下可以設定: set term windows 如果怎麼試都失敗, 至少可以下: set term dumb 拿文字模式下的字元來畫圖, 雖然有點醜, 至少可以練習. (如果你透過 pietty 連到 Linux 主機, 就必須這樣設。) 拋物線 -x*x+6*x+3

請自己畫畫看:

當然, 學任何一套軟體, 最先要學的就是:

另外, 命令列的快速鍵也很值得學。 gnuplot 用的並不是真正的 readline 介面, 只提供其中少數幾個最常用功能, 但已經很方便。 詳見 help line-editing

人口成長史

請先跳出 gnuplot, 再重新進來一次, 以確定所有設定還原。 (所有 set 回復到 default 值) 這份資料 popgrowth.txt 記載著美國加州與阿拉斯加州的人口成長史。

plot "popgrowth.txt" # 繪製加州人口成長史。
show style data # 如果你用的版本比較舊, 請下 set data style
set style data 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 軸標示吧。
plot "popgrowth.txt" using 1:2,
"popgrowth.txt" using 1:3
# 同時畫兩圖 (請打在同一列)
set logscale y; replot # 像這種情況, 用 logscale 畫圖最合適了
set output "growth.png" ; set term png ; replot
set output ; set term x11 ; replot
unset logscale # 改回正常 (非 logscale) 顯示

美國加州與阿拉斯加州的人口成長史 很多設定可以用 set 命令更改。 建議用對應的 show 命令查看一下更改前後的設定。 這裡的 set term ... 用來選取不同的輸出方式 (螢幕或圖檔? 那一種圖檔?) set output ... 則選取輸出的檔案名稱。 倒數第二列的那三句用來將圖存檔; 最後一列的那三句將輸出切回螢幕, 以免等一下所畫的圖全部都跑錯地方, 覆蓋掉先前畫好的圖檔。

又, 這個例子說明了: 如果數據資料裡面含有數量級相差極大的值 (例如藍鯨, 人, 老鼠的身長體重) 可以用 logscale 的設定來提高圖的可讀性。

立體圖形

用 splot 畫空間曲面。 可以用滑鼠抓著圖形旋轉, 詳細研究它的長相, 這比老師在黑板上畫圖要好玩而且有感覺多了! 像是這個馬鞍面: splot x*x-y*y 再加上等高線, 正好可以上一點國中地理/地科: [馬鞍面的等高線] 圖案

        reset   # 清除之前所有的設定
        set contour base
        set cntrparam levels 20
        unset key
        unset ztics
        splot x*x-y*y

這裡的 reset 效果像是跳出 gnuplot 再進來, 把之前的 (絕大部分) set 設定改回內定值。

如果希望將等高線畫在曲面本來在空間中的位置上, 可以用: set contour surface 取代 set contour base; 如果只想從正上方看等高線, 不想看原始的曲面, 則需要補兩句: unset surface; set view 0,0 或乾脆不准旋轉: set view map

更多有趣的數學函數 3d 圖形請見另一篇講義: 「Gnuplot 十分鐘的 3d 曲面奇航」

當然, 它不只可以畫 3-d 函數, 也可以畫 3-d 資料。 美國太空總署 JPL 實驗室的 Shuttle Radar Topography Mission 提供全球的地面高度資訊。 我下載北緯 23 度東經 121 度附近的資訊, 並寫了一個小程式 hgt2txt 將之轉換成 gnuplot 認得的純文字格式, 存成檔案 taiwan.txt:

        ./hgt2txt -s 100 > taiwan.txt

然後進入 gnuplot 畫圖:

        reset
        splot "taiwan.txt"              # 連線會比較清楚
        set style data lines; replot    # 比例怪怪的, 調一下...
        set xrange [0:60]
        set zrange [0:1e4]; replot
        set pm3d; replot                # 著色。
        set palette model HSV functions gray, 1, 1
        replot                          # 換個調色盤看看
        set palette model HSV functions gray>0.01?gray*0.9:0, gray>0.01?1:0, 1
        replot                          # 海面畫白色; 陸地由紅到紫
        set view map; replot            # 如果改畫平面圖呢?
        set palette model XYZ functions gray**0.35, gray**0.5, gray**0.8
        splot "taiwan.txt" lt 3         # 另外一個由黑到金的調色盤

最後一個 「黑金調色盤」 (呵呵 跟臺灣的政治無關, 請不要想太多) 來自 這份講義 (在本頁搜尋 "gold palette") 關於調色盤的使用, 也請見我的另一篇講義: 「Gnuplot 十分鐘的 3d 曲面奇航」

臺灣 3d 地形圖 臺灣 2d 地形圖

注意到資料檔 taiwan.txt 的格式:

Regexp 與資料繪圖

如果您對資料繪圖有興趣, 這裡 還有更多例子; 不過需要學一點 regular expressions。 略過這部分, 對 gnuplot 的學習無甚影響; 但 regular expressions 真的超級有用, 不妨順便一起學。

示範集錦: 以世界地圖為例

Demo scripts for gnuplot 有很多範例。 也可以下載整套的壓縮檔 (版本可能不同於上述網頁) demo.zip, 解壓縮後, 在該目錄下進入 gnuplot, 下指令: load "all.dem" 。 在原先下指令的終端機視窗 (而不是繪圖視窗) 按 Enter, 可以一口氣逐一檢視所有範例。

我們就拿其中的 cylindrical/spherical coordinates 為例來多學一些資料繪圖的指令。 開另一個分頁, 用 less 檢視 world.dat 的內容; 又在 gnuplot 分頁當中 reset; plot "world.dat" ... (待續)

匯出 svg 以製作漫畫/海報/插圖等等

向量繪圖軟體 Inkscape 可以用來製作漫畫/海報/插圖等等, 有 Linux 版, Mac 版, Windows 版, ...。 它所產生的 svg 檔, 是一種開放的 xml 格式, 且可以任意縮放而不失真。 我常拿它來為我的部落格文章畫一些插圖, 例如 反盜版文宣的正當性, 中間選民的力量, 數學不及格的公投法, ... 等等。

gnuplot 的輸出可不可以拿來給 inkscape 用呢? 這裡就是一個例子:

        unset key
        unset border
        unset xtics
        unset ytics
        unset mouse
        bell(x) = exp(-x*x)/sqrt(2*pi)
        f1(x) = (x > -1 && x < 1) ? bell(x) : 0
        plot [-3:3] bell(x) lt 1 with filledcurve, f1(x) lt 2 with filledcurve
        set output "normal.svg"; set term svg; replot
        set output; set term x11; replot

進 inkscape, 匯入 normal.svg, 選取圖形, 並用 Object 選單底下的 ungroup 功能將群組拆開, 就可得到常態分佈的向量圖。

數學圖形

用 gnuplot 畫數學函數, 其實比畫資料檔更簡單。 我們看過如何單純地以直角座標表示法畫圖, 像這樣: plot sin(x)/x; 但 gnuplot 還可以畫極座標圖:

        set polar               # 改以極座標畫圖
        plot 1+cos(t)           # 心臟線
        plot sin(5*t)           # 五瓣花
        plot [0:6*pi] t         # 阿基米德螺線
        unset polar             # 切換回直角座標
  

有些圖形嚴格說來不是函數, 因為一個 x 對到兩個或兩個以上的 y; 但又不一定能用很簡單的極座標表示。 這時可以改用最一般的 "參數式" 表示。 先用 set parametric 指定以下使用參數式, 以後就可以用 t 當做自變量。 當然用參數式畫圖時, 就必須給 plot 兩個數值, 例如 plot [-3:3] t*t, t*t*t 畫出一條有 cusp (有尖角) 的曲線。 又如 plot sin(t),sin(t)*cos(t) 畫一條 "8" 字線。 現在請用 unset parametric 還原。

畫空間曲面時, 一樣可以用參數式; 此時用 u, v 當做自變量。 例如: [從中間被掐住的紙] 圖案

        set parametric
        set hidden3d
        splot v*v, -u, v*(u*u+1)

splot 有支援用球面坐標與柱面坐標畫外部數據資料, 但並沒有直接支援球面坐標與柱面坐標畫函數。 沒關係, 參數式比這些座標更一般, 所以一樣可以畫出來, 例如 hyperboloid of one sheettorus ("甜甜圈"):

        set isosamples 30, 10
        splot [-pi:pi] [-2:2] sqrt(1+v*v)*cos(u), sqrt(1+v*v)*sin(u), v
        set isosamples 50, 30
        splot [-pi:pi] [-pi:pi] cos(u)*(5+cos(v)), sin(u)*(5+cos(v)), sin(v)

更多有趣的數學函數 3d 圖形請見另一篇講義: 「Gnuplot 十分鐘的 3d 曲面奇航」

自訂函數

使用者可以自己定義函數。 例如訊號處理當中經常出現的 sinc 函數 可以這樣定義: sinc(x) = sin(x)/(x) 之後如果要畫它的立體版就比較簡單了: splot sinc(sqrt(x*x+y*y)) [sinc 函數, 立體版] 圖案

可以用 show functionsshow variables 查詢先前定義的函數及變數。

Fitting

其實 gnuplot 不只可以繪圖, 也可以做一點數值運算。 Fitting 的功能很好用, fit 完成之後, 把成果函數和原始資料畫在一起, 可以很清楚地看到手邊的資料與心中的模型與是否吻合。

先看一個簡單的例子。 首先進入 octave 用亂數產生一些資料:

        x=[-10:10]/8*pi; x=x'
        y=3.2*sin(0.7*x+0.4)+1.4*x-2.3+(rand(21,1)-0.5)*0.7
        z = [x,y]
        save -text fit-ex1.txt z     # 存檔

再進入 gnuplot, 用一個三次式去近似:

        f(x) = a*x*x*x + b*x*x + c*x + d        # 定義函數 (含待估參數)
        a=-1; b=1; c=10; d=0                    # 設定參數的初始猜測值
        fit f(x) "fit-ex1.txt" via a,b,c,d      # fit
        plot "fit-ex1.txt", f(x)                # 畫出, 對照比較

不過這題正好也可以用最小方差 (least square) 的方式來解。 回到 octave 很容易就可以驗算答案:

        load "fit-ex1.txt"
        x = z(:,1)
        y = z(:,2)
        A = [x.*x.*x,x.*x,x,x-x+1]
        (A'*A)\(A'*y)

一些有用的經驗分享

  1. 若希望畫出的文字有上下標小字的效果, 在 X Window 下可用 set term x11 enh, 然後用這樣的語法 set xlabel '{/Symbol D}_x (m)' 即可達成。 請參考 GNUPLOT 4.0 - A Brief Manual and Tutorial 並在頁面內搜尋 Greek。 感謝 小明提供!

以下是舊的講義尚未整合進來的部分


修飾圖案: set 與 show 的常用選項

  1. 進入 gnuplot 後請先畫好一個圖, 例如 plot sin(x)/x 以下摘要說明中, (un)set xzeroaxis 表示你可以下 set noxzeroaxis; replot 看看不要畫 x 軸的效果, 或下 unset xzeroaxis; replot 看看要畫 x 軸的效果. 有些選項 (例如 arrow) 比 "要/不要" 還要複雜, 必須看手冊 (例如 help set arrow) 查看詳細的用法.
  2. 要檢查目前的設定, 可以用 show 命令. 例如 show xzeroaxis 可以查詢在目前的設定下, x 軸會不會畫出來; 用 show xrange 可以查詢目前 x 軸方向的數值範圍.
  3. set xrange ...: 設定 x 軸方向的數值範圍. y 軸與 z 軸類似. (有些命令只對 x 與 y 有效, 有些對 z 也有效; 以下都只以 x 軸為例.)
  4. set title ...: 這張圖的標題.
  5. (un)set autoscale x: (不)要讓 gnuplot 自己推敲 x 軸方向的數值範圍 (range)
  6. (un)set xzeroaxis: (不)要畫 x 軸.
  7. (un)set border: (不)要畫外框.
  8. (un)set xtics ...: (不)要畫 x 軸上的刻度. 刻度之間的距離可以調整, 甚至可以不是常數; 刻度旁的文字可以自行指定. 欲單獨控制刻度旁的文字 (消除或改變列印格式) 見 help set format. 又, 如要以月份做為刻度旁的文字, 可以用 xmtics 選項.
  9. set function style ...: 用各種不同的方式來畫函數. 建議用 impulses 試一下, 可以畫出物理課本上常出現的圖式; 用 boxes 試一下, 可以畫出統計課本上常出現的圖式.
  10. set samples ...: 每一條曲線要由多少個點來近似 (取樣點數).
  11. (un)set grid: (不)要在背景上畫方格紙.
  12. (un)set key ...: (不)要在右上角顯示圖例 (因為一張圖上可以有好幾個函數) 另外 keytitle 可設定圖例的標題.
  13. set label ...: 到處亂寫文字.
  14. set arrow ...: 到處亂畫箭頭.
  15. (un)set logscale ...: 以對數比例顯示.
  1. Gnuplot 非常重要的用途之一是資料分析: 把搜集而來或其他程式所產生的數據資料拿來畫. 它需要的輸入格式非常簡單: 純文字檔; 每列代表一個點的坐標; # 開頭的當做註解忽略; 如果每列有兩個數字則代表 x 與 y 坐標; 如果每列只有一個數字則代表 y 坐標 (x 坐標自動指定為 1, 2, 3, ...). 例如我們可以建立一個數據資料檔叫做 apache.dat 然後下 plot "apache.dat"
  2. 與 set function style 相對應的, 有一個 set style data 可以用各種不同的方式來畫外部數據資料.
  3. 如果 data style 設定成 lines 或 linespoints, 則資料點之間會有線將它們連起來. 但若數據資料檔內有空列, 則空列前後的兩點之間不會有連線. 範例
  4. 使用者可以自行定義函數 (見 help user-defined)
  5. 常用設定可以放在 ~/.gnuplot 檔內, 每次進入 gnuplot 時, 會自動執行. 事實上也可以把相關的 gnuplot 命令與自行定義的函數寫在純文字檔內, 存成任何檔名, 只要用 load 命令就可以載進來.
  6. 連續畫好幾個圖時, 可用 pause 暫停, 讓看的人跟得上.

參考資料

  1. Gnuplot (Part I) (一些設定說明)
  2. 用自由的工具學習計算物理 (文化大學物理系鄒忠毅老師)
  3. 使用 gnuplot 科学作图 Gnuplot 中文教程 (88頁簡體中文詳細教學)

銘謝

本文件接受以下計畫補助: