背景
- 本項作業取代傳統SURFER、NCL、或dat2kml、csv2kml等繪圖方式,以python程式讀取高斯煙流模式結果(plotfile、格式詳下),運作NCL並讀取結果檔,與Open TopoMap地圖進行疊加,並以CaaS形式對外提供遠端計算服務。
重要元件
- 開放地形圖(Open TopoMap)為開放街道圖專案項目之一
- 其線上服務位置:https://opentopomap.org/#map=5/49.000/10.000,url命令列#後的三個數字分別是放大倍率(zoom)、緯度及經度。臺灣則為:https://opentopomap.org/#map=8/23.5338/120.9265
-
OpenTopoMap 可用於嵌入到個別的項目中,圖磚可從{a b c}.tile.opentopomap.org/{z}/{x}/{y}.png圖檔取得。 - 此處之作業乃將其下載至本地目錄,貼上NCL圖檔,並於CGI服務中提供予使用者。
- NCAR命令語言(NCL)
- 為美國大氣研究中心提供之高精繪圖套件,除一般使用外,也常使用在學術論文報告中。
- 此處應用其繪製高斯模式之濃度輸出等值線圖。
- 為典型之等值線搭配png底圖,其他搭配構想詳等濃度圖類型與比較
其他方案之比較
- 在數位板專案中曾經用到Open Map系列的Open TopoMap,該專案是套用Leaflet套件,將底圖在網頁中置換成地形圖(如範例),並不是真正輸出高解析度之圖檔。
- dat2kml或csv2kml作業結果為google Map可以讀取的kml檔案,該方案也是以網頁呈現為主(如範例),因google Map的版權限制,並不適合輸出成圖檔製作成報告。
過去製圖方式之檢討
- 底圖的截取:
- 從網頁畫面、使用剪取工具直接就所要的範圍進行截取
- 無法得到指定座標的精確範圍,須嘗試錯誤
- 解析度有限(截圖只有72dpi、列印另存pdf檔可達300dpi),對高品質要求製圖(>1000dpi)則無法配合
- 使用OSMOSIS
- 可以就經緯度範圍(box or polygon)進行切割、數個檔案可以再進行整併(merge)
- 如要較高解析度之地圖,要先全部下載再行切割。
- 除了命令列方式之外,也有GUI版本OSMembrane
- 如果是較大範圍的地圖,整併時會發生問題,需要較專業的merge方式,
- 在小範圍、接近垂直座標系統的情況下,直接montage拼接較快速方便,也不會有顏色失真的問題(詳merged_GeoTIFF)。
- 用使Pbftoosm或 osmconvert(都沒有macOS版本)
- 直接動態下載:(詳merged_GeoTIFF)
- 與Leaflet或其他網頁存取方式相同
- 隨時更新圖資內容,與時俱進
- 下載後另存快取,提升後續存取速度
- 從網頁畫面、使用剪取工具直接就所要的範圍進行截取
- SURFER:
- 好處:
- 互動式作業方式、也有模版可以使用、容易上手、品質符合水準
- 也能貼上png或其他格式之地圖
- 沒有linux/macOS版本
- 自動化方面雖有VBA程式、然目前仍無法與其他unix系統相容
- 底圖的georeferencing須自行(另行)輸入4個頂點的座標
- 因為不是程式化、自動化的作業方式,修改範圍、解析度時,將難以因應。
- 好處:
- NCL
- dat2kml.py
煙流模式結果的PLT格式(PLOTFILE)
* AERMOD ( 19191): A Simple Example Problem for the AERMOD Model with PRIME 03/10/21
* AERMET ( 15181): 05:36:19
* MODELING OPTIONS USED: NonDFAULT CONC FLAT RURAL MMIF_Data
* PLOT FILE OF HIGH 1ST HIGH 1-HR VALUES FOR SOURCE GROUP: ALL
* FOR A TOTAL OF 5000 RECEPTORS.
* FORMAT: (3(1X,F13.5),3(1X,F8.2),3X,A5,2X,A8,2X,A5,5X,A8,2X,I8)
* X Y AVERAGE CONC ZELEV ZHILL ZFLAG AVE GRP RANK NET ID DATE(CONC)
* ____________ ____________ ____________ ______ ______ ______ ______ ________ ________ ________ ________
132700.00000 2595400.00000 0.00008 34.00 34.00 0.00 1-HR ALL 1ST GD2 20012620
133700.00000 2595400.00000 0.00013 34.00 34.00 0.00 1-HR ALL 1ST GD2 20012620
134700.00000 2595400.00000 0.00020 34.00 34.00 0.00 1-HR ALL 1ST GD2 20012620
135700.00000 2595400.00000 0.00026 34.00 34.00 0.00 1-HR ALL 1ST GD2 20012620
…
181200.00000 2644900.00000 0.00001 34.00 34.00 0.00 1-HR ALL 1ST GD3 20031710
181700.00000 2644900.00000 0.00001 34.00 34.00 0.00 1-HR ALL 1ST GD3 20031710
182200.00000 2644900.00000 0.00001 34.00 34.00 0.00 1-HR ALL 1ST GD3 20031710
實例
遠端計算服務:在OpenTopoMap上貼上高斯煙流模式之NCL等值圖 |
CaaS成果及運作
輸入說明:
- (一) 切割OpenTopoMap服務:輸入RE GRIDCART範圍設定
- 在空格內至少要輸入6個數字,數字的內容、順序及意義如下表所示(ISC/AERMOD之受體點RE GRIDCART設定方式),其他考量檢討如下:
- 直角座標系統的必要性
- 由於煙流模式必須用直角座標系統來設定接收點及排放口位置,不接受經緯度系統
- NCL雖然可以接受經緯度、但網格定義仍然是用等間距系統
- 雖然各式地圖之引用以經緯度為主,但在此階段還是要用直角座標系統輸入較為方便
- 在此使用TWD97(2度分帶)系統,符合內政部地圖系統的要求(與一般模式模擬作業之習慣)
RE GRIDCART範圍設定參數說明
項目 | 設定內容(範例) | 說明 |
---|---|---|
1. | 290700 | 原點x座標,單位為m(TWD97系統) |
2. | 40 | 東西向格點數、整數 |
3. | 1250 | 東西向格點間距(m) |
4. | 2746400 | 原點y座標,單位為m(TWD97系統) |
5. | 40 | 南北向格點數、整數 |
6. | 1250 | 南北向格點間距(m) |
- (二)製作等值線圖服務(輸入高斯模式模擬結果.PLT檔案、或regrid後的.grd檔)
- 按下執行鍵(Run and Revise Links)
輸出檔案
項目 | 服務 | 結果 | 範例 |
---|---|---|---|
1. | 切割OpenTopoMap | 依使用者要求範圍、解析度之OTM地形圖 | fitted.png |
2. | 製作等值線圖服務 | 同一範圍解析度之OTM地形圖 | fitted.png |
- | - | NCL等值線圖(不含底圖) | 固定檔名tmp_cn.png |
- | - | 疊圖結果 | 固定檔名NCLonOTM.png |
OTM檔案下載、合併與切割( tiles_to_tiffFit.py)
本項工作的目標是得到指定範圍、指定解析度之OTM檔案,可以給SURFER或其他繪圖軟體使用。詳細參閱詳merged_GeoTIFF及筆記之說明,此處說明搭配的原則與注意事項:
(一)引數個數與內容的應用
- 在CaaS的cgi_python中,tiles_to_tiffFit.py有2種被呼叫的可能情況:網格設定字串、或直接給予一個PLT檔案。因此必須彈性設計引數的個數:
- 按照引數個數是否小於6作為判斷
- 6以下,讀取使用者提供的PLT檔案,從當中讀取西南、東北位置的座標
- 至少6個數字,讀取使用者提供的字串,從當中計算出網格範圍西南、東北位置的座標
- 再將這2個位置座標轉成經緯度(TWDLL)
44 larg=len(sys.argv)
45 if larg<6:
46 fname=sys.argv[1]
47 with open(fname,'r') as f:
48 ll=[l for l in f]
49 ll=ll[8:]
50 X,Y=([float(l.split()[i]) for l in ll] for i in [0,1])
51 mnX,mnY,mxX,mxY=(min(X),min(Y),max(X),max(Y))
52 else:
53 mnX,nx,dx,mnY,ny,dy=(float(sys.argv[i]) for i in range(larg-6,larg))
54 mxX,mxY=mnX+nx*dx,mnY+ny*dy
55 lat_min,lon_min=TWD2LL(mnX,mnY)
56 lat_max,lon_max=TWD2LL(mxX,mxY)
(二)縮放比例(zoom)的決定
- OSM/OTM的拼塊儲存位置、名稱、與其位置的定義,都是按照縮放比例決定的,zoom必須先決定,才能正確下載檔案。
- 縮放比例、下載檔案個數,也與裁切後的解析度(dpi)、像素矩陣大小有關、亦即與地圖的品質、檔案大小有關。
- 太密:檔案太大、下載處理的速度變慢、等值圖須放大的比例太大,會出現斷線、無線條的狀況,降低圖的品質,只能重做。
- 太疏:地圖無法辨識細節,也只能重做
- 為維持等值圖與地圖有接近的像素大小,地圖至少須20幅以上、但也必須控制在150幅以下。
33 zoomi = 22 #initial zoomming level
...
137 for zoom in range(zoomi,5,-1):
138 x_min, x_max, y_min, y_max = bbox_to_xyz(
139 lon_min, lon_max, lat_min, lat_max, zoom)
140 ntiles=(x_max - x_min + 1) * (y_max - y_min + 1)
141 if 150 > ntiles > 20:break
142 print(f"Downloading {(x_max - x_min + 1) * (y_max - y_min + 1)} tiles")
(三)圖檔的管理
- Png
- 雖然OSM/OTM的更新速度很快,沒有必要儲存在工作站,但如果在嘗試錯誤期間,同一地區地圖不斷重複下載,似乎也沒有必要。
- 此處修改原程式的設計,先測試是否已經有過去下載過的檔案,如果沒有,才真的進行下載。依然暫時儲存在temp目錄下。
- 執行裁切後,原程式內設是刪除temp目錄下所有檔案,在此修改成備份到工作站某處儲存備用。
- tif
- 原程式是將結果檔案另存在output目錄之下,如此就檔案性質分類自然是為了方便檔案管理。
- cgi_python每次呼叫會開一個暫存目錄(cntr_????),output似乎沒有必要存在,為減少目錄的複雜性,在此取消output,將裁切結果直接存在cntr_????下即可。
28 store_dir = os.path.join(os.path.dirname(__file__), '../pngs')
29 temp_dir = ‘temp'
...
101 def download_tile(x, y, z, tile_server):
102 url = tile_server.replace(
103 "{x}", str(x)).replace(
104 "{y}", str(y)).replace(
105 "{z}", str(z))
106 store = f'{store_dir}/{x}_{y}_{z}.png'
107 path = f'{temp_dir}/{x}_{y}_{z}.png'
108 if os.path.exists(store):
109 os.system('ln -sf '+store+' '+path)
110 return(path)
111 if "street" in tile_server:
112 os.system(wget+url+' -O '+path)
113 else:
114 urllib.request.urlretrieve(url, path)
115 os.system('cp '+path+' '+store)
116 return(path)
(四)合併(merge)或拼接(montage)
- 原程式是使用gdal_merge.py這支程式進行下載圖檔的合併。
- 衛星圖像變色的問題與解決
- OSM/OTM每個圖檔的顏色種類個數不同,合併時會按照第一個圖片的色譜來解讀後續圖檔,因此合併後全變成黑白版(以達成最大公約數)。
- 解決方案
$ cat mtg.cs
#$1=X1,$2=X2,$3=Y1,$4=Y2
X1=$1
X2=$2
Y1=$3
Y2=$4
Z=$5
for x in `seq $X1 $X2`; do for y in `seq $Y1 $Y2`; do ln -sf ${x}_${y}_${Z}.tif ${Z}_${y}_${x}.tif;done;done
/usr/local/bin/montage -mode concatenate -tile "$((X2-X1+1))x" "${Z}_*.tif" ../merged_montage.tif >&/dev/null
cd ..
/opt/anaconda3/envs/env_name/bin/gdalwarp -t_srs "+proj=longlat +ellps=WGS84" -to DST_METHOD=NO_GEOTRANSFORM merged.tif merged_montage.tif
(五)圖檔格式的選擇
- 原程式是設計讓圖檔自帶座標資料,因此使用GeoTiff格式
- 如果NCL的等值線是按照座標繪製、地圖也是按照座標裁切,二者疊圖是再沒有需要知道座標值或任何座標系統相關資訊,tiff似無必要
- 經比較tiff的RGB色譜與png格格不入,縮放、疊圖時,都會發生變色的情形,
- 結論就是不必再維護tiff檔、利用Imagmagic的convert指令,將裁切結果都轉成png檔
(六)切割Open TopoMap png檔服務之結果
- 給定範圍解析度(RE GRIDCART)STR: 290700 40 1250 2746400 40 1250
- 檔案大小:3.7MB
- 像素矩陣: (1464, 1457)
NCL等值線製圖(PLT_cn.ncl)
本項工作的目標是得到像素較高的等值線圖,使用NCL的程式PLT_cn.ncl。使用NCL的理由:
- 品質為科學期刊所認可、軟體持續精進更新、備援及範例豐富
- Linux/macos相容、自動化作業
- 出圖像素可控制
(一)矩陣大小的判定
- NCL 的asciiread指令可以接受未知維度、長度的檔案,但是要在NCL程式內判斷檔案X軸及Y軸的格點數,因為沒有
set()
指令,困難度太高了、只能放棄 - 在cgi_python內呼叫os.system(“echo”)指令,可以將RE GRIDCART字串設定參數寫在文字檔案param.txt內(只有用到網格數nx,ny)
- 在NCL程式內讀入維度、宣告檔案及變數的陣列大小、可以順利將矩陣讀入
kuang@114-32-164-198 /Users/Data/GIS/OSM_20210318/merged_GeoTIFF
$ cat -n PLT_cn.ncl
1 ;----------------------------------------------------------------------
2 ; WRF_cn_1.ncl
3 ;
…
17 nxy=asciiread("param.txt",(/6/),"integer")
18 nx=nxy(1)
19 ny=nxy(4)
...
22 f=asciiread("tmp.PLT",(/ny*nx,3/),"float”)
…
28 p=new((/ny,nx/),float)
29 do j=0,ny-1
30 do i=0,nx-1
31 ji=j*nx+i
32 p(j,i)=f(ji,2)
33 end do
34 end do
(二)圖名的傳遞
- 同樣運用檔案來傳遞圖名訊息
...
20 t=asciiread("title.txt",1,"string")
21 tit=t(0)
...
49 res@tiMainString = tit ; main title
...
(三)等值圖的像素
- 在疊圖過程中,需要保持底圖與等值線圖有接近的解析度,如此二者失真的情況可以降到最低。
- 縮放地圖:因地圖是格柵圖、不宜縮放。
- 縮放等值圖:雖然NCL不能輸出向量檔,但因為等值線相對單純、微小的縮放尚能接受。
- 唯一需要控制像素
- 在
wks_type
函數內控制,在此抓整個圖約2000像素、圖框內約控制在1500左右 - 此處XY方向保持一樣(如有需要可以按照nx/ny比例修改)
- 在
41 ;---Create simple contour plots
42 wks_type = "png"
43 wks_type@wkWidth = 2000
44 wks_type@wkHeight = 2000
45 wks = gsn_open_wks(wks_type,"tmp_cn")
(四)等值線的粗細
- 由於等值線要在複製的地圖上表現清楚,必須加粗。
- 在
nLineThicknessF
變數控制,內設為1。
50 res@cnLineThicknessF =7
(五)輸出結果
- 檔名內設為
tmp_cn.png
,詳範例。
疊圖(NCLonOTM.py)
本項作業的重點是在尋找等值圖上找到圖框的位置、框外保持不變、框內空白處置換成底圖的像素即可。圖框的定義及作法:
- 在X或Y方向有最多的黑色像素、
- 運用np.where來協助尋找
- 解決2個圖像素不同的問題
- 解決NCL等值線不夠黑的問題
- 逐一判斷、置換
- 存檔離開
(一)圖框位置的判定
- 圖框位置會因為nx,ny的大小、比例、圖名的長度字型等而改變,雖然其數字差異不大,但為精確,還是用程式將其定位較佳。
- 先求出各方向非為白色的像素個數(nwidth,nheight)
- 依序取最高、次高位置,如果二者一樣,表示軸線黑色像素完全一樣,np.where全部囊括,只要判斷序列的大小就知道起訖了。
- 由於軸線的寬度至少有3點像素,用
abs()
來解決(approximate)。
#kuang@114-32-164-198 /Users/Data/GIS/OSM_20210318/merged_GeoTIFF
#$ cat -n NCLonOTM.py
1 #!/opt/anaconda3/envs/env_name/bin/python
...
11 image=cv2.imread('tmp_cn.png')
12 ny,nx,nz=image.shape
13
14 #locate the frame of contour plot
15 nwidth=np.array([len(np.where(image[j,:,:]!=255)[0]) for j in range(ny)])
16 nheight=np.array([len(np.where(image[:,i,:]!=255)[0]) for i in range(nx)])
17 wh={'j':'nwidth','i':'nheight'}
18 nxy={'j':'ny','i':'nx'}
19 for ij in wh:
20 n=nxy[ij]
21 exec('id1=int(np.mean(np.where('+wh[ij]+'>=max('+wh[ij]+')-2)[0]))')
22 exec('id2=int(np.mean(np.where('+wh[ij]+'==max(['+wh[ij]+'[i] for i in range('+n+') if abs(i-id1) > 2]))))')
23 if id1==id2:
24 exec('id1=np.min(np.where('+wh[ij]+'>=max('+wh[ij]+')-2)[0])')
25 exec('id2=np.max(np.where('+wh[ij]+'>=max('+wh[ij]+')-2)[0])')
26 exec(ij+'0=min([id1,id2])')
27 exec(ij+'1=max([id1,id2])')
28 size = (j1-j0,i1-i0)
(二)圖框內線條加黑
- NCL為求品質,線條數字可能帶有陰影、漸層、灰階,在縮放、疊圖時會不清楚,此處全部將其塗黑。
- 邏輯就是RGB 3者相同,卻不是白色RGB=(255,255,255))
- 不是白色,即設成全黑
30 #darken the lines inside of the frame
31 image3=image[:]
32 boo=(image[:,:,0]==image[:,:,1]) & (image[:,:,1]==image[:,:,2])& (image[:,:,2]!=255)
33 idx=np.where(boo)
34 idx0=np.array([idx[0][i] for i in range(len(idx[0])) if idx[0][i]>j0 and idx[0][i]<j1 and idx[1][i]>i0 and idx[1][i]<i1])
35 idx1=np.array([idx[1][i] for i in range(len(idx[0])) if idx[0][i]>j0 and idx[0][i]<j1 and idx[1][i]>i0 and idx[1][i]<i1])
36 if len(idx0)>0 and len(idx1)>0:image3[idx0,idx1,:]=0
(三)等值線圖縮放
- 此處控制等值線圖可以放大、縮小,但縮小不能超過30%。
- 使用cv2.resize函數進行縮放
- 圖框原點也要縮放
38 #resize (alignment the resolutions)
39 image2=cv2.imread('fitted.png')
40 ny2,nx2,nz=image2.shape
41 if ny2<size[0] and size[0]/ny2>1.3 :sys.exit('make a more detail basemap')
42 rate=(ny2/size[0],nx2/size[1])
43 size2=(int(rate[0]*ny),int(rate[1]*nx))
44 im_resized = cv2.resize(image3,size2, interpolation=cv2.INTER_CUBIC)
45 image3=np.array(im_resized)
46 j0,i0=int(j0*rate[0]),int(i0*rate[1])
(四)空白處置換成底圖
- 由於前面已經將等值線加黑(RGB=(0,0,0))了,因此判斷式就是黑色處跳開、非黑處置換成底圖
- 只有圖框內的像素需要置換、圖框外的軸線、文字、保持不變
- 存檔離開
48 #replace the nodata location with OSM plot
49 for j in range(j0,j0+ny2):
50 for i in range(i0,i0+nx2):
51 if (image3[j,i,:]==0).all():continue
52 # if sum(image3[j,i,:])>=200+255:
53 image3[j,i,:]=image2[j-j0,i-i0,:]
54 cv2.imwrite("NCLonOTM.png",image3)
NCLonOTM.html
- 設計成可以接受字串與檔案輸入。右側有成品範例、下側有設定數字意義表格,詳實例或前圖。
- IO部分設計可以接受RE GRIDCART字串、以及開啟本地檔案(filepicker)
- 呼叫cgi_python、傳遞字串或檔案
cgi_python(NCLonOTM-cgi.py)
主要工作就是接受html的呼叫,將RE GRIDCART座標設定內容、或檔案內容傳遞到前述3項作業。
(一)解析輸入檔案的副程式
26 def PLT_parser(fname):
27 with open(fname,'r') as f:
28 l=[line.strip('\n') for line in f]
29 if l[0][0]=='*':l=l[8:]
30 X,Y=([float(l[i].split()[j]) for i in range(len(l))] for j in range(2))
31 sX ,sY=list(set(X)),list(set(Y))
32 sX.sort()
33 sY.sort()
34 nx,ny=len(sX),len(sY)
35 dx,dy=[round(sX[i+1]-sX[i],3) for i in range(nx-1)],[round(sY[i+1]-sY[i],3) for i in range(ny-1)]
36 if len(set(dx))!=1 or len(set(dy))!=1:
37 fname=pth+fn
38 print """not a regular RE GRIDCART system, sorry! your input is:
39 <a data-auto-download href="%s">%s</a>
40 """ % (fname.replace(WEB,'../../../'),fname.split('/')[-1])
41 sys.exit('not a regular RE GRIDCART system')
42 return ' %d %d %d %d %d %d ' % (int(min(X)),nx,int(dx[0]),int(min(Y)),ny,int(dy[0]))
(二)按照輸入字串呼叫FIT程式
- 確認RE GRIDCART字串是否存在任何內容(長度4以上)
15 FIT='/Users/Data/GIS/OSM_20210318/merged_GeoTIFF/tiles_to_tiffFit.py '
...
48 form = cgi.FieldStorage()
49 STR = str(form.getvalue("iscinp"))
50 os.system('echo "'+STR+'"'+OUT)
51 if len(STR)>=4: #in case of input a string
52 cmd ='cd '+pth+';'
53 cmd+= FIT+STR+OUT+';'
54 os.system('echo "'+cmd+'"'+OUT)
55 r=os.system(cmd+OUT)
56 if r!=0:sys.exit('error in ncl')
57 fnames=['fitted.png']
(三)將regridded的SURFER grd檔案寫成tmp.PLT (X,Y,C)格式
- 檔案類型的判斷依據是在檔案的第一行、第一個字串必須是“DSAA”,才是.grd檔案
- 使用網友提供的load_surfer模組
- 寫出時要注意python2還沒有{:f}格式,必須符合工作站cgi-python的版本進行調修
58 else:
59 fileitem = form['filename']
60 if fileitem.filename:
61 fn = os.path.basename(fileitem.filename)
62 open(pth+fn, 'wb').write(fileitem.file.read())
63 with open(pth+fn, 'r') as f:
64 ll=[l.strip('\n') for l in f]
65 if ll[0]=='DSAA':
66 x, y, c, (ny, nx) = load_surfer(pth+fn)
67 with open(pth+'tmp.PLT','w') as f:
68 for j in range(ny):
69 for i in range(nx):
70 f.write('%f %f %f\n' % (x[j,i],y[j,i],c[j,i]))
(四)如是PLOTFILE格式,還需要進行SED去行、CUT選欄位
- tmp.PLT檔案整理好之後就可以進行FIT程式
71 elif ll[0].split()[1] in ['AERMOD','ISCST3']:
72 cmd ='cd '+pth+';'
73 if pth+fn!=pth+'userinp.PLT': cmd+='cp '+pth+fn+' '+pth+'userinp.PLT;'
74 cmd+= SED+'userinp.PLT'+CUT+';'
75 os.system('echo "'+cmd+'"'+OUT)
76 r=os.system(cmd+OUT)
77 else:
78 print 'wrong format! '+ll[0]
79 sys.exit('wrong format')
80 cmd ='cd '+pth+';'
81 cmd+= FIT+' tmp.PLT '+OUT+';'
82 os.system('echo "'+cmd+'"'+OUT)
83 r=os.system(cmd+OUT)
(五)執行NCL程式與疊圖
- 準備好座標設定字串內容
- 依序執行NCL製圖、再與前述FIT準備好的底圖進行疊加(
OVL
即前述NCLonOTM.py)
16 OVL='/Users/Data/GIS/OSM_20210318/merged_GeoTIFF/NCLonOTM.py'
...
85 STR=PLT_parser(pth+'tmp.PLT')
86 cmd ='cd '+pth+';'
87 cmd+='echo "'+STR+'">param.txt;'
88 cmd+='echo "'+fn+'">title.txt;'
89 cmd+= NCL+OUT+';'
90 cmd+= OVL
91 os.system('echo "'+cmd+'"'+OUT)
92 r=os.system(cmd+OUT)
93 if r!=0:sys.exit('error in ncl')
(六)輸出結果檔案
94 fnames=['fitted.png', 'tmp_cn.png', "NCLonOTM.png"]
95 descip={ 'fitted.png':'OpenTopoMap: ',
96 'tmp_cn.png':'CLN_contour: ',
97 'NCLonOTM.png':'contour post on OTM: '}
98
99 for fn in fnames:
100 fname=pth+fn
101 print """\
102 %s<a data-auto-download href="%s">%s</a></br>
103 """ % (descip[fn],fname.replace(WEB,'../../../'),fname.split('/')[-1])
104 print """\
105 </body>
106 </html>
107 """
Reference
- Jimmy Utterström, Generate merged GeoTIFF imagery from web maps (xyz tile servers) with Python, merged_GeoTIFF
- wiki, “OpenTopoMap ( opentopomap.org ) 是一個旨在從 OSM 和SRTM數據中渲染地形圖的項目。”
- wiki, 通用网关接口, “在電腦領域,通用閘道器介面 (英語:Common Gateway Interface,CGI) 是為提供網路服務而執行控制台應用 (或稱命令列介面)的程式,提供於伺服器上實現動態網頁的通用協定。通常情況下,一次請求對應一個CGI 指令碼的執行,生成一個 HTML。簡而言之,一個 HTTP POST 請求,從客戶端經由 標準輸入 傳送資料到一個CGI 程式。同時攜帶其他資料,例如 URL 路徑, HTTP頭欄位資料,被轉換為行程的環境變數。”
- NCL, “NCAR Command Language Programs”