2015年3月11日

Day 4 疊圖與拼圖:Draw and Frame 的應用

Definition
首先先定義疊圖與拼圖。

何謂疊圖 (composite)?
這裏所謂的疊圖,是指在一張圖上,運用顏色、形狀等方式展現數個不同的場量。舉例來說,可以在一張地面天氣圖上面同時畫上地面氣壓,氣溫,風場,水氣。運用不同顏色的等值線或粗細或塗色,可以將數筆資訊濃縮在一張圖裡面。若學過GrADS,可以知道這是一個在直覺不過的動作,先畫氣壓,再畫氣溫,再畫風場,最後畫水氣,結束。要疊幾張,就同一個步驟重複幾次就可以了。但用NCL做起來可是複雜了幾分...。

何謂拼圖 (panel)?
在一面畫布 (一張PNG或一頁PDF,) 一次上呈現多張圖。舉例來說,要把春、夏、秋、冬四個季節分別的平均氣溫,同時畫在一張畫布上,以2x2的方式排列,左上為春,右上為夏,左下為秋,右下為冬。

Concept of Hold-On
在看範例前,先就概念上解釋一下作法。

是否曾用Matlab疊過圖?譬如畫兩條不同的拋物線在同一個XY座標上,概念是十分類似的。如果直接:
plot(x1,y1)
plot(x2,y2)
這樣輸入兩次 plot 指令,那麼最後只會有第二條線出現在畫面上。因為第二次的 plot 把第一次的 plot 蓋掉了!在Matlab中用 "hold" 告知電腦後面還有圖要畫,類似這樣:
plot(x1,y1) ; hold on
plot(x2,y2) ; hold off

回到NCL。

一樣用前面使用過的 air.2014.nc 來練習。若要將兩層不同高度的溫度場疊起來,如果像 Day 3 中的範例 NCL101-4.ncl 那樣直接輸入兩次
plot = gsn_csm_contour_map_ce( wks , Temp( 0, : , : ) , res )
plot = gsn_csm_contour_map_ce( wks , Temp( 1 , : , : ) , res )
兩層溫度場並不會疊在同一張圖上,而是會得到獨立分開的兩張圖。所以,要找到在NCL中類似 "hold" 的指令,請它等一下 (hold on),等你的 plot 指令全部下完後再一起畫!

Draw and Frame
NCL中,請它等一下的參數是
res@gsnDraw = False     ; 先別畫!
res@gsnFrame = False     ; 先別翻頁!
第一個,@gsnDraw,代表先不要畫;第二個,@gsnFrame 代表先不要翻頁。如果不特別指定,NCL預設會一直自動翻頁畫下一張圖,就像之前範例 NCL101-4.ncl 中,執行了三次的 plot 後,出來的 AirTempMap2.pdf 會有三頁,每頁一張圖。

最後再介紹兩個指令就可以開工了:
draw(plot)     ; 可以畫圖了!
frame(wks)     ; 可以翻頁了!

在下面的範例 NCL101-5.ncl 中,總共開了四個WorkStations,執行script後會產生四個PDF檔。由於已經事先將 @gsnDraw 和 @gsnFrame 指定為 False,所以在這個script中必須手動執行 draw 和 frame 才行。

;===== NCL101-5.ncl =====
load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl"
load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl"

begin

; Work Station
        wks_type                = "pdf"
        wks_type@wkPaperWidthF  = 8.0
        wks_type@wkPaperHeightF = 4.5
        wks1                    = gsn_open_wks(wks_type,"day4-1")
        wks2                    = gsn_open_wks(wks_type,"day4-2")
        wks3                    = gsn_open_wks(wks_type,"day4-3")
        wks4                    = gsn_open_wks(wks_type,"day4-4")

; Variable
        ncFile                  = addfile("air.2014.nc","r")
        Temp                    = ncFile->air(0,:,:,:)

; Plot resources
        res                     = True
        res@gsnMaximize         = True
        res@gsnPaperOrientation = "portrait"

        res@gsnDraw             = False
        res@gsnFrame            = False

; Plot on wks1
        plot1                   = gsn_csm_contour_map_ce(wks1,Temp( 0,:,:),res)
        draw(plot1)
        frame(wks1)
        plot1                   = gsn_csm_contour_map_ce(wks1,Temp( 5,:,:),res)
        draw(plot1)
        frame(wks1)
        plot1                   = gsn_csm_contour_map_ce(wks1,Temp(10,:,:),res)
        draw(plot1)
        frame(wks1)

; Plot on wks2
        plot2                   = gsn_csm_contour_map_ce(wks2,Temp( 0,:,:),res)
        plot2                   = gsn_csm_contour_map_ce(wks2,Temp( 5,:,:),res)
        plot2                   = gsn_csm_contour_map_ce(wks2,Temp(10,:,:),res)
        draw(plot2)
        frame(wks2)

; Plot on wks3
        plot3                   = gsn_csm_contour_map_ce(wks3,Temp( 0,:,:),res)
        draw(plot3)
        plot3                   = gsn_csm_contour_map_ce(wks3,Temp( 5,:,:),res)
        draw(plot3)
        plot3                   = gsn_csm_contour_map_ce(wks3,Temp(10,:,:),res)
        draw(plot3)
        frame(wks3)

; Plot on wks4
        plot4                   = gsn_csm_contour_map_ce(wks4,Temp( 0,:,:),res)
        frame(wks4)
        plot4                   = gsn_csm_contour_map_ce(wks4,Temp( 5,:,:),res)
        frame(wks4)
        plot4                   = gsn_csm_contour_map_ce(wks4,Temp(10,:,:),res)
        frame(wks4)
        draw(plot4)

print("All Done.")
end
;=====

第一個PDF,是每 plot 一次,就 draw 一次,再 frame 一次。翻譯成白話文就是,每作一張圖 (plot) 就畫 (draw) 到畫布上然後翻面 (frame)。所以第一個PDF檔案理論上是跟 NCL101-4.ncl 所做出來的 AirTempMap2.pdf 相似。

而後面三個PDF檔分別測試了不同策略的 draw 和 frame 的組合。在打開下面的PDF檔案連結之前,你能先想想看每個檔案應該長什麼樣子嗎?結果和你想的一樣嗎?

解答:
day4-1.pdf
day4-2.pdf
day4-3.pdf
day4-4.pdf

Composite and Panel
範例 NCL101-6.ncl 示範如何疊圖和拼圖。跟疊圖和拼圖直接相關的指令用螢光筆畫了重點。

;===== NCL101-6.ncl =====
load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl"
load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl"

begin

; Work Station
        wks_type                = "pdf"
        wks_type@wkPaperWidthF  = 8.0
        wks_type@wkPaperHeightF = 4.5
        wks                     = gsn_open_wks(wks_type,"day4_example")

; Variable
        ncFile                  = addfile("air.2014.nc","r")
        Temp                    = ncFile->air(0,:,:,:)

; Plot resources
        res                     = True
        res@gsnLeftString       = ""
        res@gsnRightString      = ""
        res@gsnDraw              = False
        res@gsnFrame            = False

        ; Resources for contour plot
        res_cn                  = res
        res_cn@cnFillOn         = False
        res_cn@cnLinesOn        = True
        res_cn@cnInfoLabelOn    = False

        ; Resources for shading plot
        res_sd                  = res
        res_sd@gsnMaximize      = True
        res_sd@gsnPaperOrientation = "portrait"
        res_sd@cnFillOn         = True
        res_sd@cnLinesOn        = False
        res_sd@mpCenterLonF     = 180.
        res_sd@mpMinLatF        = 0.
        res_sd@mpMaxLatF        = 80.
        res_sd@mpMinLonF        = 60.
        res_sd@mpMaxLonF        = 200.
        res_sd@tiMainString     = "Composite Demo"
        res_sd@gsnLeftString    = "Shading: T @ level 0"
        res_sd@gsnRightString   = "Contour: T @ level 5"
        res_sd@lbOrientation    = "vertical"

        res_pn                  = True
        res_pn@gsnMaximize      = True
        res_pn@gsnPaperOrientation = "portrait"

; composite plot
        plot_sd                 = gsn_csm_contour_map_ce(wks,Temp(5,:,:),res_sd)
        plot_cn                 = gsn_csm_contour(wks,Temp(0,:,:),res_cn)
        overlay(plot_sd,plot_cn)
        draw(plot_sd)
        frame(wks)

; panel plot (3*2)
        plot_pn                 = new(6,graphic)
        plot_pn(0)              = gsn_csm_contour_map_ce(wks,Temp(0,:,:),res_cn)
        plot_pn(1)              = gsn_csm_contour_map_ce(wks,Temp(1,:,:),res_cn)
        plot_pn(2)              = gsn_csm_contour_map_ce(wks,Temp(2,:,:),res_cn)
        plot_pn(3)              = gsn_csm_contour_map_ce(wks,Temp(3,:,:),res_cn)
        plot_pn(4)              = gsn_csm_contour_map_ce(wks,Temp(4,:,:),res_cn)
        plot_pn(5)              = gsn_csm_contour_map_ce(wks,Temp(5,:,:),res_cn)
        gsn_panel(wks,plot_pn,(/2,3/),res_pn)

print("All Done.")
end
;=====

>>$ NCL101-6.ncl

執行後產生 day4_example.pdf




範例 script 說明:
<<疊圖>>
疊圖的要領就是先在 plot resources 中設定「先別畫」+「先別翻頁」
res@gsnDraw             = False
res@gsnFrame            = False

設定好 plot_sd 和 plot_cn 兩張要疊在一起的圖之後,告訴NCL要哪張壓在哪張上面
overlay(底圖,上面疊的那張圖)
在範例中一張是shding一張是contour,所以如果寫反把shading疊在contour上面,會把contour完全覆蓋掉;相對的,如果兩張都是contour,不管哪張在上面都可以看到疊加在一起的兩張圖。

另外要注意的是兩張含有地圖資訊 (gsn_csm_contour_map_ce) 的圖是無法疊加的,所以只有底圖可以用 gsn_csm_contour_map_ce,要疊在上面的圖都只能用 gsn_csm_contour 來畫。

最後提醒一點,如果要疊三張以上的圖也沒問題,一樣都先設定好 plot,再一次一張的蓋上去:
plot_bottom = ...
plot1 = ...
plot2 = ...
plot3 = ...
overlay( plot_bottom , plot1 )
overlay( plot_bottom , plot2 )
overlay( plot_bottom , plot3 )
draw(plot_bottom)

<<拼圖>>
說穿了,拼圖就是一個指令而已
gsn_panel( wks , plot_pn , (/2,3/) , res_pn )
函數 gsn_panel 需要的 input 就是:WorkStation,圖,排列方式,Resources。

為了方便輸入 (縮短程式碼),通常會把圖做成一個 array,像範例中的作法:
plot_pn = new( 6 , graphic )
plot_pn 就是一個可以含有6個plot的集合。new 是一個常用的函數,也常常被用來定義一個新的變數,譬如 NewTemp = new( (/nT,nZ,nY,nX/) , float ) 再次提醒一下,記得像這樣把座標順序反過來寫。

排列方式,就是一個二維的向量,指定拼圖總共有幾行幾欄。在NCL中一個陣列的標準寫法就是 ( / A , B , C , D , ... / )。

最後提醒一點,從 NCL101-4.ncl 就都有使用到的兩個設定 @gsnMaximize 和 @gsnPaperOrientation 一直還沒有解釋用途。在單張單張作圖的時候,照著先用就對了,不用管它們的用途。但在疊圖與拼圖時,需要特別注意使用的時機,才不會讓作出來的圖忽大忽小或位置不太對。這裏只講結論:
1. 對於疊圖,只有底圖要做這兩個設定
2. 對於拼圖,只有最後一個步驟的 gsn_panel 要做這兩個設定





待續... Day 5

沒有留言:

張貼留言