對於寫程式這件事情不熟悉的人,這邊舉一個例子:假設今天的任務是「讀取一份一整年的氣溫資料,要畫每天一張的全球氣溫分布圖,圖上面的標題要寫上當天的日期。」圖的標題一直在變,如果不能善用批次功能自動設定每張圖的標題,一年365張圖,就要手動更改script檔並手動執行365次...。利用批次處理,可以只執行一次,完成相同的任務。
對於作圖目的取向,學習基本的批次功能,不外乎找到以下幾個問題的答案:
如何使用 if 判斷式?
如何使用迴圈 (loop)?
如何擷取、組合字串?
如何抓取變數資訊 (e.g., 名稱、維度、單位...)?
對於Linux中的NCL,多了一個問題:
如何在 NCL script 中與 Linux 互動?
下面用 NCL101-8.ncl 作為範例,示範一些常用到的工具與函數,同樣的就直接在程式碼中做說明以精簡版面。day6_example.pdf 可在這下載。
;===== NCL101-8.ncl =====
load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl"
load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl"
begin
OutputPDFName = "day6_example"
print("Delete old " + OutputPDFName + ".pdf at the beginning.")
; OutputPDFName 是一個字串變數。組合在一起後這一行就同等於
; print("Delete old day6_example.pdf at the beginning.")
; 在NCL中可以利用 + 號自由的將「字串變數」和「一般字串」組合在一起。
; 而更方便的是,NCL對於字串的限制非常寬鬆 (聰明?),
; 整數/浮點數也可以直接拼進字串內,無須先把數字轉換成字串格式
; (可能要學過別的程式(Matlab/Fortran)才會知道上一行在說什麼...)
system("rm -f " + OutputPDFName + ".pdf")
CurrentPDFList = systemfunc("ls -l *.pdf")
; 在script中也可以直接下達Linux指令,活用這部分將對於批次處理有莫大的幫助。
; system 和 systemfunc 裡面都可以直接下達 Linux 指令,
; 差別在於 systemfunc 會回傳執行結果回 NCL script,而 system 不會。
print("All .pdf in this folder...")
print("" + CurrentPDFList)
print("")
wks_type = "pdf"
wks_type@wkPaperWidthF = 8.0
wks_type@wkPaperHeightF = 4.5
wks = gsn_open_wks(wks_type,OutputPDFName)
ncFile = addfile("air.2014.nc","r")
Temp = ncFile->air(0:3,:,:,:)
nDim = dimsizes(Temp)
; dimsizes 可以回傳變數的維度資訊
nT = nDim(0)
nZ = nDim(1)
nY = nDim(2)
nX = nDim(3)
res = True
res@gsnDraw = False
res@gsnFrame = False
res@mpCenterLonF = 180.
res@mpMinLatF = 0.
res@mpMaxLatF = 80.
res@mpMinLonF = 90.
res@mpMaxLonF = 220.
res_pn = True
res_pn@gsnMaximize = True
res_pn@gsnPaperOrientation = "portrait"
plot = new(6,graphic)
; 迴圈的寫法。起始,結束,間隔。
; 也可以遞減,就讓第一個數字大於第二個數字,間隔給負值。
do iT = 0,nT-1,1
do iZ = 0,nZ-1,3
; 判斷式 if 的用法也很直覺。
if (iZ.eq.0) then
iPlot = 0
print("TimeStep = "+iT)
end if
; 這是個「字串+整數=字串」的例子
res@gsnLeftString = "Level = " + iZ
plot(iPlot) = gsn_csm_contour_map_ce(wks,Temp(iT,iZ,:,:),res)
iPlot = iPlot + 1
end do
; 別忘了變數的屬性 (@, attributes) 也是字串,很好用。
res_pn@txString = Temp@long_name + " TimeStep = " + iT
gsn_panel(wks,plot,(/2,3/),res_pn)
end do
print("All Done.")
end
;=====
當然這幾招花拳繡腿打完不敢說自己的批次撰寫能力有多好,但的確是個不錯的開始了。一個個的小技巧實在太多太雜,無法一一列舉,但會隨著寫程式的年資慢慢的學習領悟、不斷地精進累積。
正所謂:師父領入門,修行在個人。
待續... Day 7
沒有留言:
張貼留言