自由軟體與資訊公民聯網
首頁 ] / 上一層 ] 上一篇 ] 下一篇 ]


Gnuplot:餵我統計資料成果,為你產生圖形報表

洪朝貴(朝陽科技大學資訊管理系教授)

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 軸有兩個交點。

拋物線 x*x-6*x+3

請自己畫畫看:

不必擔心, 這只是起個頭, 等一下大部分的例子與數學都沒有直接的關係。 我們有興趣的是 gnuplot 的操作, 不是數學; 而且下面的例子多半使用資料檔, 較少畫數學函數。

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

另外, 命令列的快速鍵也很值得學。 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 看一下, 發現有兩個問題:

  1. 每個郡的最前面, 有一個 「郡的整數代號」, 而且其後的座標不知道是什麼東東, 並不在邊界上, 應該整列刪除。
  2. 每個郡的最後面, 有一個 "END", 也應該刪除。

於是借用 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"

  

亞洲各國人口密度圖



以下是舊版

  1. 簡介
    1. gnuplot 可以畫出數學函數或畫出由使用者提供的大批數據資料; 可以顯示平面曲線 (直角坐標或極坐標), 空間曲面 (直角坐標, 球面坐標, 柱面坐標), 等高線圖; 可以用參數式繪圖; ... 適合國中生到大學生用來學習數學, 也適合工程師或研究人員用來分析數據資料.
    2. 進入 gnuplot 後, 最重要的兩個命令: help 救助; ^D 或 quit 或 exit 離開.
    3. 最常用的命令: plot 畫曲線. 例如 plot sin(x)/x 又如 plot -2*x*x+7*x+5
    4. 指定 x 軸與 y 軸範圍: set xrange [-2:6]; set yrange [-6:14] 其中分號用來把兩個命令放在同一列上.
    5. 用新設定的範圍重新把剛才的圖 (即 -2*x*x+7*x+5) 再畫一遍: replot
    6. 用 splot 畫空間曲面:
                  set xrange [-1:1]
                  set yrange [-1:1]
                  set autoscale z
                  splot x*x-y*y
              
      


      (馬鞍面)

    7. plot 和 splot 都可以直接在命令列上指定變數範圍, 如: splot [-1:1] [-1:1] x*x-y*y
    8. 如果你下以上畫圖的命令, 卻有錯誤訊息:
      use 'set term' to set terminal type first
      那麼應先設定繪圖模式: 在 X-Window 下可以設定:
      set term x11
      在 MS Windows 下可以設定:
      set term windows
      如果怎麼試都失敗, 至少可以下:
      set term dumb
      拿文字模式下的字元來畫圖, 雖然有點醜, 至少可以練習. (如果你透過 telnet 連到 UNIX 主機, 就必須這樣設.)
    9. 在命令列上可以用方向鍵及 readline 使用者界面所提供的少數幾個鍵 (但並不是真的 readline 界面) 詳見 help line-editing.
  2. 修飾圖案: set 與 show 的常用選項
    1. 進入 gnuplot 後請先畫好一個圖, 例如 plot sin(x)/x 以下摘要說明中, (no)xzeroaxis 表示你可以下 set noxzeroaxis; replot 看看不要畫 x 軸的效果, 或下 set xzeroaxis; replot 看看要畫 x 軸的效果. 有些選項 (例如 arrow) 比 "要/不要" 還要複雜, 必須看手冊 (例如 help set arrow) 查看詳細的用法.
    2. 要檢查目前的設定, 可以用 show 命令. 例如 show xzeroaxis 可以查詢在目前的設定下, x 軸會不會畫出來; 用 show xrange 可以查詢目前 x 軸方向的數值範圍.
    3. xrange ...: 設定 x 軸方向的數值範圍. y 軸與 z 軸類似. (有些命令只對 x 與 y 有效, 有些對 z 也有效; 以下都只以 x 軸為例.)
    4. title ...: 這張圖的標題.
    5. (no)autoscale x: (不)要讓 gnuplot 自己推敲 x 軸方向的數值範圍 (range)
    6. (no)xzeroaxis: (不)要畫 x 軸.
    7. (no)border: (不)要畫外框.
    8. (no)xtics ...: (不)要畫 x 軸上的刻度. 刻度之間的距離可以調整, 甚至可以不是常數; 刻度旁的文字可以自行指定. 欲單獨控制刻度旁的文字 (消除或改變列印格式) 見 help set format. 又, 如要以月份做為刻度旁的文字, 可以用 xmtics 選項.
    9. function style ...: 用各種不同的方式來畫函數. 建議用 impulses 試一下, 可以畫出物理課本上常出現的圖式; 用 boxes 試一下, 可以畫出統計課本上常出現的圖式.
    10. samples ...: 每一條曲線要由多少個點來近似 (取樣點數).
    11. (no)grid: (不)要在背景上畫方格紙.
    12. (no)key ...: (不)要在右上角顯示圖例 (因為一張圖上可以有好幾個函數) 另外 keytitle 可設定圖例的標題.
    13. label ...: 到處亂寫文字.
    14. arrow ...: 到處亂畫箭頭.
    15. (no)logscale ...: 以對數比例顯示.
  3. 空間曲面
    1. 請見右圖 "二次極限存在但不相等的例子". [二次極限存在但不相等的例子] 圖案
                      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)
              
      


    2. set (no)hidden3d: (不)要消除隱線. 畫空間曲面時, 可以指定要消除被遮蓋住的部分, 看起來比較分得出前後, 但是計算量也稍微大一些.
    3. set isosamples ...: 畫空間曲面時, 指定 x 方向與 y 方向的曲線各要畫多少條.
    4. set view ...: 要從那個角度看圖案? set view 後面的數字如果是 0,0 表示從正上方往下看; 90,0 表示從側面看. 用第一個數字決定俯看的角度後, 可以用第二個數字讓圖案繞著 z 軸轉.
  4. 參數式與極坐標
    1. 有些圖形嚴格說來不是函數, 因為一個 x 對到兩個或兩個以上的 y. 只要可以用參數式表示, 還是可以用 gnuplot 畫. 先用 set parametric 指定以下使用參數式, 以後就可以用 t 當做自變量. 當然用參數式畫圖時, 就必須給 plot 兩個數值, 例如 plot t*t, t*t*t 要還原, 可用 set noparametric ("cusp", 有尖角的曲線)
    2. 同樣地, 也可以畫 "非函數" 的空間曲面 (用 u, v 當做自變量). 例如: [從中間被掐住的紙] 圖案
                      set parametric
                      set hidden3d
                      set isosamples 30,50
                      set view 70, 20
                      splot v*v, -u, v*(u*u+1)
              
      


    3. 平面上有不少常用函數的參數式, 用極坐標表示法比較簡單. 先用 set polar 指定以下使用坐標表示法, 以後就可以用 t 當做自變量. 例如 plot [0:pi*6] 1/sqrt(1+t*t) 要還原, 可用 set nopolar (向內長的螺旋線)
    4. 上例的效果如果要用 set parametric 來達成, 要寫成: plot [0:pi*6] 1/sqrt(1+t*t)*cos(t), 1/sqrt(1+t*t)*sin(t)
    5. 至於用球面坐標與柱面坐標畫函數, splot 並沒有直接支援, 必須用參數式的方式自己計算. 例如:
                      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 有支援用球面坐標與柱面坐標畫外部數據資料. 見下節)

  5. 外部數據資料
    1. Gnuplot 非常重要的用途之一是資料分析: 把搜集而來或其他程式所產生的數據資料拿來畫. 它需要的輸入格式非常簡單: 純文字檔; 每列代表一個點的坐標; # 開頭的當做註解忽略; 如果每列有兩個數字則代表 x 與 y 坐標; 如果每列只有一個數字則代表 y 坐標 (x 坐標自動指定為 1, 2, 3, ...). 例如我們可以建立一個數據資料檔叫做 apache.dat 然後下 plot "apache.dat"
    2. 與 set function style 相對應的, 有一個 set data style 可以用各種不同的方式來畫外部數據資料.
    3. 如果 data style 設定成 lines 或 linespoints, 則資料點之間會有線將它們連起來. 但若數據資料檔內有空列, 則空列前後的兩點之間不會有連線. 範例
    4. 同樣地, splot 也可以從檔案中讀外部數據資料來畫. 如果資料很整齊地排成 m 乘 n 組 x, y, z 坐標, 且 data style 設定成 lines 或 linespoints, 則 splot 會畫成一個 mesh (網狀結構). 最簡單的檔案格式為: 每列一組 x, y, z 坐標; 每 n 列後空一列; 一個圖形內共有 m-1 個空列. 一個檔案內也可以有多個圖形, 不同圖形之間的資料要空兩列以上. 範例
    5. 稍微複雜的例子: 先在 shell 下執行 ./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 
      
  6. 進階功能
    1. 等高線圖範例: [馬鞍面的等高線] 圖案
                      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).

    2. 使用者可以自行定義函數 (見 help user-defined)
    3. 常用設定可以放在 ~/.gnuplot 檔內, 每次進入 gnuplot 時, 會自動執行. 事實上也可以把相關的 gnuplot 命令與自行定義的函數寫在純文字檔內, 存成任何檔名, 只要用 load 命令就可以載進來.
    4. 連續畫好幾個圖時, 可用 pause 暫停, 讓看的人跟得上.
    5. 可以用 fit 命令做 curve-fitting. 也就是說, 如果你已知某數據資料檔應該是某種函數 (例如 y = A*x*x + B*x + C), 只是不知道其中幾個參數的值 (例如 A, B, C), 那麼可以把數據資料餵給 fit 讓它幫你求出最接近的參數值. 對於分析實驗數據很有用.

參考資料

  1. 中研院: GNUPLOT 導讀

[歡迎使用任何瀏覽器] [(力求維持) 無障礙網頁] 以某種 creative
      commons 方式授權


首頁 ] / 上一層 ] 上一篇 ] 下一篇 ]


wind@fcu.org.tw