地圖/統計圖/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

美國加州與阿拉斯加州的人口成長史 很多設定可以用 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 導讀
  2. 用自由的工具學習計算物理 (文化大學物理系鄒忠毅老師)

銘謝

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