[IDL] 아이디엘 지구물리 원격탐사 실습 자료 : HDF 형식인 Terra MODIS 극궤도 기상 위성 자료를 이용한 지표면 온도 및 해발 고도 가시화

 정보

  • 업무명    : 지구물리 원격탐사 실습 자료 : 아이디엘 HDF 형식인 Terra/MODIS 극궤도 기상 위성 자료를 이용한 지표면 온도 및 해발 고도 가시화

  • 작성자    : 이상호

  • 작성일    : 2020-03-25

  • 설   명    :

  • 수정이력 :

 

 내용

[개요]

  • 안녕하세요? 기상 연구 및 웹 개발을 담당하고 있는 해솔입니다.

  • 대학원 석사 1학기에 배운 지구물리 원격탐사에 대한 실습 내용을 다루고자 합니다.

  • 오늘 포스팅에서는 HDF 형식인 Terra/MODIS 극궤도 기상 위성 자료를 이용한 지표면 온도 및 해발 고도 가시화를 소개해 드리고자 합니다.

  • 추가로 지구물리 원격탐사에 대한 이론적 배경을 소개한 링크를 보내드립니다.

 

[강릉원주대 대기환경과학과] 2015년 2학기 전선 지구물리 원격탐사 소개 및 과제물

정보 업무명 : 2015년 2학기 전선 지구물리 원격탐사 소개 및 과제물 작성자 : 이상호 작성일 : 2019-12-20 설 명 : 수정이력 : 내용 [특징] 지구물리 원격탐사 수업에 대한 이해를 돕기위해 작성 [기능] 소개 주..

shlee1990.tistory.com

 

[특징]

  • HDF 극궤도 기상 위성 자료를 이용하여 정성적으로 가시화하기 위한 도구가 필요하며 이 프로그램은 이러한 목적을 달성하기 위해 고안된 소프트웨어

 

[기능]

  • Terra/MODIS 극궤도 기상 위성 자료에 대한 위/경도 및 지표면 온도 읽기

  • 지표면 온도 가시화 및 이미지 저장

 

[활용 자료]

  • 자료명 : MOD03.A2014309.0230.005.2014309134625.hdf
                    MOD11_L2.A2014309.0230.005.2014310121006.hdf

  • 자료 종류 : 위/경도, 지표면 온도

  • 확장자 : HDF

  • 영역 : 전지구

  • 기간 : 2014년 11월 05일 02:30 UTC

  • 시간 해상도 : 하루에 2번 관측

  • 제공처 : NASA

MOD03.A2014309.0230.005.2014309134625.zip
9.98MB
MOD03.A2014309.0230.005.2014309134625.z01
10.00MB
MOD03.A2014309.0230.005.2014309134625.z02
10.00MB
MOD11_L2.A2014309.0230.005.2014310121006.hdf
4.15MB

 

[사용법]

  • 입력 자료를 동일 디렉터리에 위치

  • 소스 코드를 실행 (idl -e Visualization_Using_MODIS_Land_Surface_Data)

  • 가시화 결과를 확인

 

[사용 OS]

  • Linux

  • Windows 10

 

[사용 언어]

  • IDL v8.5

 

 소스 코드

  • 해당 작업을 하기 위한 컴파일 및 실행 코드는 IDL로 작성되었으며 가시화를 위한 라이브러리는 CIMSS/SSEC Library를 이용하였습니다.

  • 소스 코드는 단계별로 수행하며 상세 설명은 다음과 같습니다.

    • 1 단계는 주 프로그램은 작업 경로 설정, HDF 파일 읽기, 변수 전처리하여 메모리상에 저장하고 가시화를 위한 초기 설정합니다.

    • 일반적으로 포스트 스크립트 (PS) 형식에서 PNG로 변환하나 오랜 시간이 소요되는 단점이 있습니다. 따라서 2 단계에서는 imagemap를 통해 영상 표출하여 이미지 형식으로 저장합니다. 

 

[명세]

  • 전역 변수 설정

    • 결측값 (fillvnan), 최소값 (small), 그림 창 크기 (nxsize, nysize), 그림 저장 여부 (iop_img), 매핑 시 심볼 크기 (sz1), 위/경도 간격 (latlon_intvl)

    • 지표면 온도에 대한 최대/최소값 범위 (minx, maxx), 해발 고도에 대한 최대/최소값 범위 (minx2, maxx2)

    • 지상 관측소 (GWNU) 표출 여부 (iop_show_gwnu), 지상 관측소를 기준으로로 MODIS 위/경도의 공간 일치를 위한 반경 설정 (acclation)

    • 위/경도 (latbeg, latend, lonbeg, lonend)에 따른 관심 영역 (ROI) 설정 (plotlimit)

    • 지상 관측소의 위 경도 설정 (xlat_pt1, xlon_pt1)

fillvnan=!values.f_nan
small=1.0e-6

nxsize=800 & nysize=800
iop_img=1
sz1=1.5
latlon_intvl=0.2

;**********************************************************************************************
;**********************************************************************************************
;**********************************************************************************************
;**********************************************************************************************
; Please carefully choose the following scale to examine local temperature variability!!!!!
;**********************************************************************************************
minx=285.0 & maxx=295.0  ; range (color scale) of LST to plot (unit: Kelvin)
minx2=0.0 & maxx2=1000.0 ; range (color scale) of terrain height to plot (unit: meter) 
;**********************************************************************************************
;**********************************************************************************************
;**********************************************************************************************
;**********************************************************************************************

;iop_regrd=1 ; set to 1 to do regridding the MODIS Level 2 data
iop_show_gwnu=1 ; set to 1 to show the location of GWNU as an open circle in the map.        
acclatlon=0.015 ; match-up accuracy in degreee (lat/lon) (match up between MODIS LST geolocation 
                ; and the given GWNU Lat/Lon value.

;#######################################################################
;#######################################################################
;area to make a subset
;latbeg=37.0  & latend=38.0 & lonbeg=128.0 & lonend=129.0
latbeg=37.3  & latend=38.2 & lonbeg=128.1 & lonend=129.2 ; set area to plot (and subset)
;#######################################################################
;#######################################################################
;plotlimit=[min(xlat_mod2d),min(xlon_mod2d),max(xlat_mod2d),max(xlon_mod2d)]
;plotlimit=[36.5,127.5,38.5,129.5]
;plotlimit=[37.0,128.0,38.0,129.0]
plotlimit=[latbeg,lonbeg,latend,lonend]


;#######################################################################
;#######################################################################
xlat_pt1=37.771 & xlon_pt1=128.867 ; Lat/Lon of GWNU, Bldg. N16
xlat_pt1arr=replicate(xlat_pt1,2)
xlon_pt1arr=replicate(xlon_pt1,2)
;#######################################################################
;#######################################################################


;#######################################################################
;#######################################################################
;#######################################################################
; input data path ...

pathdata='C:\SYSTEM\PROG\IDL\LandSkinTemp\' ; input data path (modify this line as needed)
pname=pathdata+'M*D11_L2.A*.hdf'
;#######################################################################
;#######################################################################
;#######################################################################

 

  • MODIS 파일 설정 및 파일 찾기

;#######################################################################
;#######################################################################
;#######################################################################
; input data path ...

pathdata='C:\SYSTEM\PROG\IDL\LandSkinTemp\' ; input data path (modify this line as needed)
pname=pathdata+'M*D11_L2.A*.hdf'
;#######################################################################
;#######################################################################
;#######################################################################

pn_modin=dialog_pickfile(path=pname, filter='*11_L2.A*.hdf') ; open a dialog window box to select input MODIS hdf file/

 

  • MODIS (MOD11*) 파일 설정 및 파일 찾기

    • dialog_pickfile를 통해 별도의 검색 창에서 지표면 온도 선택

; input data path ...
pathdata='C:\SYSTEM\PROG\IDL\LandSkinTemp\' ; input data path (modify this line as needed)
pname=pathdata+'M*D11_L2.A*.hdf'

pn_modin=dialog_pickfile(path=pname, filter='*11_L2.A*.hdf') ; open a dialog window box to select input MODIS hdf file/

 

 

  • MODIS (MOD03*) 파일 설정 및 파일 찾기

    • 앞서 MOD11* 파일명 패턴을 기준으로 MOD03* 위/경도 파일 찾기

fn_modin=strmid(pn_modin,43,44,/reverse_offset)
satidstr=strmid(fn_modin,0,3)
granlstr=strmid(fn_modin,9,13)
;fn_geo='MYD03.A2014314.0430.006.2014314181233.hdf'
;pn_geo=pathdata+fn_geo
fn_geo0=satidstr+'03.'+granlstr+'*.hdf'
pn_geo0=pathdata+fn_geo0
chkgeo=file_search(pn_geo0, count=nchkgeo)


if(nchkgeo gt 0) then begin
   pn_geo=chkgeo[0]
endif else begin  ; if(nchkgeo gt 0) then begin
   print, 'No geolocation file found: '+fn_geo0
  ; stop 
endelse           ; if(nchkgeo gt 0) then begin

print, "pn_geo : ", pn_geo

 

  • 출력 파일 (pn_regrddat) 및 이미지 저장 파일 (pn_img*) 설정

pn_regrddat=pathdata+'MODIS_LST_data_regridded.'+satidstr+'.'+granlstr+'.sav'

; output image file names. You may not be able to save output image file
; if you are using unregistered version of IDL.
pn_img0=pathdata+'Visualization_Using_MODIS_Land_Surface_Data'+satidstr+'.'+granlstr+'_img0.png'
pn_img1=pathdata+'Visualization_Using_MODIS_Land_Surface_Data'+satidstr+'.'+granlstr+'_img1.png'
pn_img2=pathdata+'Visualization_Using_MODIS_Land_Surface_Data'+satidstr+'.'+granlstr+'_img2.png'
pn_img3=pathdata+'Visualization_Using_MODIS_Land_Surface_Data'+satidstr+'.'+granlstr+'_img3.png'

print, "pn_modin : ", pn_modin
print, "pn_geo : ", pn_geo

 

 

  • HDF 파일 읽기 및 변수 전처리

    • read_single_MOD11_sds 및 read_single_MOD03_geo를 통해 각각 지표면 온도 및 위/경도/고도  변수 선택

; begin reading MODIS LSD data from hdf file
;=================================================================================
target_sds_name_in='LST'
read_single_MOD11_sds, pn_modin, target_sds_name_in, ndim_ylst, ylst_mod2d
;=================================================================================
;=================================================================================
target_sds_name_in='Latitude'
read_single_MOD03_geo, pn_geo, target_sds_name_in, ndim_latlon, xlat_mod2d
;=================================================================================
target_sds_name_in='Longitude'
read_single_MOD03_geo, pn_geo, target_sds_name_in, ndim_latlon, xlon_mod2d
;=================================================================================
target_sds_name_in='Height'
read_single_MOD03_geo, pn_geo, target_sds_name_in, ndim_latlon, xhgt_mod2d
;=================================================================================

 

  • 지상 관측소 위/경도를 기준으로 MODIS 격자 찾기

; matching up the given GWNU lat/lon information with MODIS pixel
dist_latlon=sqrt(((xlat_mod2d-xlat_pt1)^2 + (xlon_mod2d-xlon_pt1)^2))
locgwnu=where(dist_latlon eq min(dist_latlon) and dist_latlon le acclatlon, nlocgwnu)
if(nlocgwnu gt 0) then begin
   ylst_gwnu=ylst_mod2d[locgwnu[0]]
endif else begin ; if(nlocgwnu gt 0) then begin
   ylst_gwnu=fillvnan
endelse          ; if(nlocgwnu gt 0) then begin 


nxx_mod=ndim_latlon[0] & nyy_mod=ndim_latlon[1]


;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;subsetting MODIS data (to effieciently plot small area)
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
d1=sqrt((xlat_mod2d-latbeg)^2 + (xlon_mod2d-lonbeg)^2)
d2=sqrt((xlat_mod2d-latend)^2 + (xlon_mod2d-lonend)^2)
loc1=where(d1 eq min(d1))
loc2=where(d2 eq min(d2))
kx1 = loc1[0] mod nxx_mod
ky1 = loc1[0]/nxx_mod
kx2 = loc2[0] mod nxx_mod
ky2 = loc2[0]/nxx_mod
print, kx1, ky1
print, kx2, ky2
lxbeg=min([kx1,kx2]) & lxend=max([kx1,kx2])
lybeg=min([ky1,ky2]) & lyend=max([ky1,ky2])
nyynew=lyend-lybeg+1
nxxnew=lxend-lxbeg+1
zlst=fltarr(nxxnew,nyynew)*fillvnan & zhgt=fltarr(nxxnew,nyynew)*fillvnan
zlat=fltarr(nxxnew,nyynew)*fillvnan & zlon=fltarr(nxxnew,nyynew)*fillvnan
zlst[0:nxxnew-1,0:nyynew-1]=ylst_mod2d[lxbeg:lxend,lybeg:lyend]
zhgt[0:nxxnew-1,0:nyynew-1]=xhgt_mod2d[lxbeg:lxend,lybeg:lyend]
zlat[0:nxxnew-1,0:nyynew-1]=xlat_mod2d[lxbeg:lxend,lybeg:lyend]
zlon[0:nxxnew-1,0:nyynew-1]=xlon_mod2d[lxbeg:lxend,lybeg:lyend]

 

  • 가시화를 위한 초기 설정

    • 폰트 설정

    • loadct를 통해 컬러바 설정

!p.charsize=1.2
!p.charthick=2.
!p.thick=2.
!p.symsize=3.0
!x.thick=2.
!x.charsize=1.2
!y.thick=2.
!y.charsize=1.2

loadct, 39

 

 

  • 지표면 온도를 위한 설정 및 가시화

    • imagemap를 통해 위도 (lon), 경도 (lat)에 따른 지표면 온도 (lst) 맵핑

    • oplot를 통해 지상 관측소 매핑

    • saveimage를 통해 png 형식으로 이미지 저장

;*************************************
window, 0, xsize=nxsize, ysize=nysize
device, decomposed=0
;*************************************
mag=20


ndivbar=5
ntick=ndivbar+1
nclev=255
delclev = (maxx - minx)/nclev
dtick = (maxx - minx)/ntick
c_levels = delclev*indgen(nclev) + minx
bottom = 1
c_colors = ((!d.table_size -2)/nclev)*indgen(nclev) + bottom
ncolors=n_elements(c_colors)

lat=congrid(zlat, mag*nxxnew,mag*nyynew, /interp)
lon=congrid(zlon, mag*nxxnew,mag*nyynew, /interp)
lst=congrid(zlst, mag*nxxnew,mag*nyynew,/minus_one)

;locfill=where(lst ge maxx-delclev,nlocfill)
;if(nlocfill gt 0) then lst[locfill]=maxx-delclev
;locfill=where(lst le minx+3.*delclev,nlocfill)
;if(nlocfill gt 0) then lst[locfill]=minx+3.*delclev

map_set, limit=plotlimit, /noborder, /isotropic, xmargin=2, ymargin=5

imagemap, lst, lat, lon, range=[minx,maxx], limit=plotlimit, missing=0 $
        , /noborder, /current, /isotropic, position=[.01,.2,.99,.95] 

if(iop_show_gwnu eq 1) then oplot, xlon_pt1arr, xlat_pt1arr, psym=psym_circle(), color=255, symsize=sz1        

color = !d.table_size -1
map_continents, color=color, /countries, /coasts, /hires
map_grid, color=color, latdel=latlon_intvl, londel=latlon_intvl, charsize=1.2, charthick=2.0, /box_axes ;, /nolabel

colorbar, position=[0.2,0.05,0.8,0.08], range=[minx,maxx] $
        , /horizontal, background=0, color=255, divisions=ndivbar $
        , format='(f6.1)'
if(iop_img eq 1) then saveimage, pn_img0, /png

 

 

  • 지표면 고도를 위한 설정 및 가시화

    • imagemap를 통해 위도 (lon), 경도 (lat)에 따른 해발 고도 (hgt) 맵핑

    • oplot를 통해 지상 관측소 매핑

    • saveimage를 통해 png 형식으로 이미지 저장

;*************************************
window, 1, xsize=nxsize, ysize=nysize
device, decomposed=0
;*************************************

ndivbar=5
ntick=ndivbar+1
nclev=255
delclev = (maxx2 - minx2)/nclev
dtick = (maxx2 - minx2)/ntick
c_levels = delclev*indgen(nclev) + minx2
bottom = 1
c_colors = ((!d.table_size -2)/nclev)*indgen(nclev) + bottom
ncolors=n_elements(c_colors)

hgt=congrid(zhgt, mag*nxxnew,mag*nyynew,/minus_one)

locfill=where(hgt ge maxx2-delclev,nlocfill)
if(nlocfill gt 0) then hgt[locfill]=maxx2-delclev
locfill=where(hgt le minx2+3.*delclev,nlocfill)
if(nlocfill gt 0) then hgt[locfill]=minx2+3.*delclev

map_set, limit=plotlimit, /noborder, /isotropic, xmargin=2, ymargin=5

imagemap, hgt, lat, lon, range=[minx2,maxx2], limit=plotlimit, missing=0 $
        , /noborder, /current, /isotropic, position=[.01,.2,.99,.95]

if(iop_show_gwnu eq 1) then oplot, xlon_pt1arr, xlat_pt1arr, psym=psym_circle(), color=255, symsize=sz1        

color = !d.table_size -1
map_continents, color=color, /countries, /coasts, /hires
map_grid, color=color, latdel=latlon_intvl, londel=latlon_intvl, charsize=1.2, charthick=2.0, /box_axes ;, /nolabel

colorbar, position=[0.2,0.05,0.8,0.08], range=[minx2,maxx2] $
        , /horizontal, background=0, color=255, divisions=ndivbar $
        , format='(f6.1)'
if(iop_img eq 1) then saveimage, pn_img1, /png

 

 

  • 해발 고도 및 온도를 위한 설정 및 가시화

    • plot를 통해 해발 고도 (zhgt), 지표면 온도 (zlst)에 따른 산점도

    • saveimage를 통해 png 형식으로 이미지 저장

;*************************************
window, 2, xsize=800, ysize=700
device, decomposed=0
;*************************************
plot, zhgt, zlst, color=0, psym=psym_circle(/fill), symsize=0.7 $
    , background=7, /nodata, xrange=[0.,1500.], yrange=[minx,maxx] $
    , xtitle='Terrain Heght (m)', ytitle='Land Skin Temperature (K)'
oplot, zhgt, zlst, color=6, psym=psym_circle(/fill), symsize=0.7 

zdist_latlon=sqrt((zlat-xlat_pt1)^2 + (zlon-xlon_pt1)^2)
radgwnu_reg1=0.05
locgwnureg1=where(zdist_latlon le radgwnu_reg1, nlocgwnureg1)
locgwnuz=where(zdist_latlon eq min(zdist_latlon) and zdist_latlon le acclatlon, nlocgwnuz)

if(nlocgwnureg1 gt 1) then oplot, zhgt[locgwnureg1], zlst[locgwnureg1], color=5, psym=psym_circle(/fill), symsize=0.7 
if(nlocgwnuz gt 1) then oplot, replicate(zhgt[locgwnuz[0]],2), replicate(zlst[locgwnuz[0]],2), color=14, psym=1, symsize=1.2 

if(iop_img eq 1) then saveimage, pn_img2, /png

 

 

  • 가시화에 필요한 라이브러리

;##################################################################################
;##################################################################################
pro read_single_MOD03_geo, pn_modin, target_sds_name_in, ndim_target_sds, target_sds
;##################################################################################
;##################################################################################

fillvnan=!values.f_nan
small=1.0e-6
;
;=============================================================================
; open Level 3 MODIS monthly aerosol data - hdf file
;-----------------------------------------------------------------------------
fidmod=hdf_sd_start(pn_modin)
;-----------------------------------------------------------------------------

small=1.0e-6
fillvnan=!values.f_nan

;***************************************
; Target SDS
;***************************************
index =  hdf_sd_nametoindex(fidmod, target_sds_name_in)
sdsid = hdf_sd_select(fidmod, index)
hdf_sd_getinfo, sdsid, name=name, ndims=ndims, natts=natts, dims=dims

ndim_target_sds=dims

   idfill  = hdf_sd_attrfind(sdsid,'_FillValue')
   hdf_sd_attrinfo, sdsid, idfill, data=fillv_modis

   idvrg  = hdf_sd_attrfind(sdsid,'valid_range')
   hdf_sd_attrinfo, sdsid, idvrg, data=vrng_modis

hdf_sd_getdata, sdsid, data
hdf_sd_endaccess, sdsid

target_sds=data
bd=where(abs(data-fillv_modis[0]) le small or data lt vrng_modis[0] or data gt vrng_modis[1],nbd)
if(nbd gt 0) then target_sds[bd]=fillvnan 
; conserve memory
data=fillvnan

;=============================================================================
; closing the hdf file & the end of data file access
;-----------------------------------------------------------------------------
hdf_sd_end, fidmod
;=============================================================================

;##################################################################################
return
; The end of subroutine reading selected SDS from MOD11
end
;##################################################################################



;##################################################################################
;##################################################################################
pro read_single_MOD11_sds, pn_modin, target_sds_name_in, ndim_target_sds, target_sds
;##################################################################################
;##################################################################################

fillvnan=!values.f_nan
small=1.0e-6
;
;=============================================================================
; open Level 3 MODIS monthly aerosol data - hdf file
;-----------------------------------------------------------------------------
fidmod=hdf_sd_start(pn_modin)
;-----------------------------------------------------------------------------

small=1.0e-6
fillvnan=!values.f_nan

;***************************************
; Target SDS
;***************************************
index =  hdf_sd_nametoindex(fidmod, target_sds_name_in)
sdsid = hdf_sd_select(fidmod, index)
hdf_sd_getinfo, sdsid, name=name, ndims=ndims, natts=natts, dims=dims

ndim_target_sds=dims

   idfill  = hdf_sd_attrfind(sdsid,'_FillValue')
   hdf_sd_attrinfo, sdsid, idfill, data=fillv_modis

   idscl  = hdf_sd_attrfind(sdsid,'scale_factor')
   hdf_sd_attrinfo, sdsid, idscl, data=sf_modis

   idoff  = hdf_sd_attrfind(sdsid,'add_offset')
   hdf_sd_attrinfo, sdsid, idoff, data=offset_modis

   idvrg  = hdf_sd_attrfind(sdsid,'valid_range')
   hdf_sd_attrinfo, sdsid, idvrg, data=vrng_modis

hdf_sd_getdata, sdsid, data
hdf_sd_endaccess, sdsid

target_sds=sf_modis[0]*data+offset_modis[0]
bd=where(abs(data-fillv_modis[0]) le small or data lt vrng_modis[0] or data gt vrng_modis[1],nbd)
if(nbd gt 0) then target_sds[bd]=fillvnan 
; conserve memory
data=fillvnan

;=============================================================================
; closing the hdf file & the end of data file access
;-----------------------------------------------------------------------------
hdf_sd_end, fidmod
;=============================================================================

;##################################################################################
return
; The end of subroutine reading selected SDS from MOD08M3
end
;##################################################################################


pro imagemap, image, lat, lon, newimage = newimage, range = range, $
  limit = limit, position = position, isotropic = isotropic, title = title, $
  xoffset = xoffset, yoffset = yoffset, xsize = xsize, ysize = ysize, $
  missing = missing, noborder = noborder, noerase = noerase, lowres = lowres, $
  current = current

;+
;PURPOSE:
;   Display an image which has latitude and longitude defined for
;   each pixel on a map projection. If a map projection is not currently
;   defined, then a Mercator map projection is created which corresponds to
;   the lat/lon limits of the image.
;
;CALLING SEQUENCE:
;   IMAGEMAP, IMAGE, LAT, LON
; 
;INPUT:
;   IMAGE      Array (2D) or vector (1D) of image values
;   LAT        Array or vector of latitudes corresponding to image values
;              (degrees, -90.0 = S, +90.0 = N)
;   LON        Array or vector of longitudes corresponding to image values
;              (degrees, -180.0 = W, +180.0 = E)
;
;OPTIONAL KEYWORDS:
;   NEWIMAGE   Named variable in which resampled image array is returned.
;              Note that this image is always scaled to a BYTE array.
;   RANGE      Range of image values used for brightness scaling, [MIN,MAX]
;              (default is [MIN(IMAGE),MAX(IMAGE)])
;   LIMIT      Limits of map display, [LATMIN,LONMIN,LATMAX,LONMAX]
;              (default is [MIN(LAT),MIN(LON),MAX(LAT),MAX(LON)])
;   POSITION   Normalized coordinates for map display window [X1,Y1,X2,Y2]
;              (default is to let MAP_SET determine the window size)
;              This is useful when used in conjunction with the
;              ESRG BOXPOS procedure. For example,
;              IMAGEMAP, IMAGE, LAT, LON, POS = BOXPOS( /RMARG )
;              will leave room at the right for a COLOR_KEY colorbar.
;   ISOTROPIC  If set, creates an isotropic map projection (default=non-isotropic).
;   TITLE      String variable containing image title (default=no title).
;   XOFFSET    Named variable in which the lower left device X coordinate
;              of the displayed image is returned.
;   YOFFSET    Named variable in which the lower left device Y coordinate
;              of the displayed image is returned.
;   XSIZE      Named variable in which the width of the displayed image
;              is returned (used by devices which have scalable pixels
;              such as Postscript).
;   YSIZE      Named variable in which the height of the displayed image
;              is returned (used by devices which have scalable pixels
;              such as Postscript).
;   MISSING    Byte value to use for missing (unfilled) portions of image
;              (default is zero).
;   NOBORDER   If set, do not draw border around image (default=draw border).
;   NOERASE    If set, do not erase window before creating image (default=erase).
;   LOWRES     If set, draw image in low resolution mode (default=high resolution).
;   CURRENT    If set, use the current map projection.
;
;OUTPUT:
;   The resampled image is displayed in the current graphics window
;   in map coordinates. Continental outlines and lat/lon grids may be
;   overlaid with MAP_CONTINENTS AND MAP_GRID.
;
;CREATED:
;   Liam Gumley, CIMSS/SSEC, 26-JUL-1996
;   liam.gumley@ssec.wisc.edu
;   http://cimss.ssec.wisc.edu/~gumley/index.html
;
;REVISED:
;   Liam Gumley, CIMSS/SSEC, 17-SEP-1996
;   Modified to work with Postscript output.
;   Added XOFFSET, YOFFSET, XSIZE, YSIZE keywords.
;   Mercator map projection is now created only if no map projection exists.
;
;   Liam Gumley, CIMSS/SSEC, 15-OCT-1996
;   Added MISSING keyword to set missing values in image.
;   Added NOBORDER keyword.
;
;   Liam Gumley, CIMSS/SSEC, 25-NOV-1996
;   Now uses MISSING keyword properly.
;   Added NOERASE keyword.
;   Added LOWRES keyword (useful for low resolution images, e.g. HIRS, AMSU).
;
;   Liam Gumley, CIMSS/SSEC, 26-MAR-1999
;   Now uses NOERASE keyword properly.
;
;   Liam Gumley, CIMSS/SSEC, 13-AUG-1999
;   Added CURRENT keyword.
;
;NOTES:
;   (1) Hermann Mannstein (h.mannstein@dlr.de) suggested this IDL method.
;   (2) This has been tested on MAS, AVHRR, GOES, and simulated MODIS data.
;       It will not work well on low resolution data like HIRS or MSU.
;   (3) You might run into problems with data over the poles - I've only
;       tried mid-latitude imagery.
;   (4) This procedure was designed for display purposes *only*.
;       If you use the resampled data for any other purpose, you do so at
;       your own risk.
;   (5) The example takes about 15.6 seconds to execute
;       on a SGI Power Indigo2 (R8000/75MHz) with 256 MB RAM.
;
;EXAMPLE:
;
;; This example is adopted from the ESRG library 'REGRID' procedure.
;; First, create latitude, longitude, and image arrays at 250x200 size.
;;
;c = complex(2,2) + cmplxgen(250,200,/center)/100
;c = c + c^2
;lon = float(c) - 100.0
;lat = 20 + imaginary(c)
;image = sqrt(abs(sin(lon*!pi)*sin(lat*!pi)))^0.3 
;;
;; Resize arrays to simulate 1km resolution imagery.
;;
;lat = congrid(lat,1000,800,interp=1)
;lon = congrid(lon,1000,800,interp=1)
;image = congrid(image,1000,800,interp=1)
;;
;; Resample data to Mercator projection, and overlay coastline and grid
;;
;t0 = systime(1.0)
;imagemap,image,lat,lon
;print,'Elapsed time (sec) = ',systime(1.0)-t0
;map_continents
;map_grid
;-

;- check limit keyword

if keyword_set( limit ) then begin
  if n_elements( limit ) ne 4 then $
    message, 'LIMIT must be a 4 element vector of the form [LATMIN,LONMIN,LATMAX,LONMAX]'
  latmin = limit( 0 )
  lonmin = limit( 1 )
  latmax = limit( 2 )
  lonmax = limit( 3 )
endif else begin
  latmin = min( lat, max = latmax )
  lonmin = min( lon, max = lonmax )
endelse

;- check keywords

if not keyword_set( isotropic ) then isotropic = 0
if not keyword_set( noerase ) then noerase = 0

if n_elements( title ) eq 0 then title = ' '
if n_elements( missing ) eq 0 then missing = 0B
missing = byte( ( missing > 0 ) < ( !d.table_size - 1 ) )

;- create Mercator map projection if necessary after checking position keyword

if not keyword_set( current ) then begin
  if n_elements( position ) gt 0 then begin
    if n_elements( position ) ne 4 then $
      message, 'POSITION must be a 4 element vector of the form [X1,Y1,X2,Y2]'
    map_set, /mercator, limit = [ latmin, lonmin, latmax, lonmax ], $
      title = title, isotropic = isotropic, position = position, /noborder, $
      noerase = noerase
  endif else begin
    map_set, /mercator, limit = [ latmin, lonmin, latmax, lonmax ], $
      title = title, isotropic = isotropic, /noborder, $
      noerase = noerase
  endelse
endif

;- compute scaling range for byte image after checking range keyword

if keyword_set( range ) then begin
  if n_elements( range ) ne 2 then $
    message, 'RANGE must be a 2 element vector of the form [MIN,MAX]'
  imin = range( 0 )
  imax = range( 1 )
endif else begin
  imin = min( image, max = imax )
endelse

;- set number of samples and lines for warped image

ns = !d.x_size
nl = !d.y_size
if ( !d.flags and 1 ) then begin
  ns = 640L
  nl = long( float( ns ) * float( !d.y_size ) / float( !d.x_size ) )
endif

;- create resampled byte image

p = convert_coord( lon, lat, /data, /to_normal )
newimage = replicate( 0B, ns, nl )
newimage( p( 0, * ) * ( ns - 1 ), p( 1, * ) * ( nl - 1 ) ) = $
  bytscl( image, min = imin, max = imax, top = !d.table_size - 2 ) + 1B

;- extract portion of image which fits within map boundaries

x = !x.window * ns
y = !y.window * nl
newimage = temporary( newimage( x(0):x(1), y(0):y(1) ) )

;- compute image offset and size (device coordinates)

p = convert_coord( [ x(0), x(1) ] / float( ns ), [ y(0), y(1) ] / float( nl ), $
  /normal, /to_device )
xoffset = p(0,0)
yoffset = p(1,0)
xsize = p(0,1) - p(0,0)
ysize = p(1,1) - p(1,0)

;- fill holes in resampled image

nxr = 2
nyr = 2
if keyword_set( lowres ) then begin
  nxr = 5
  nyr = 5
  if ( !d.flags and 1 ) then begin
    nxr = 7
    nyr = 7
  endif
endif
fill = dilate( newimage, replicate( 1, nxr, nyr ), /gray )
loc = where( ( fill ge 1b ) and ( newimage eq 0 ), count )
if count ge 1 then newimage( loc ) = fill( loc )
fill = 0

;- fill remaining undefined areas of image with the missing value

loc = where( newimage eq 0B, count )
if ( count ge 1 ) and ( missing gt 0B) then newimage( loc ) = missing

;- display resampled image

tv, newimage, xoffset, yoffset, xsize = xsize, ysize = ysize

;- draw map borders

if not keyword_set( noborder ) then begin
  plots, [ p(0,0), p(0,1) ], [ p(1,0), p(1,0) ], /device
  plots, [ p(0,1), p(0,1) ], [ p(1,0), p(1,1) ], /device
  plots, [ p(0,1), p(0,0) ], [ p(1,1), p(1,1) ], /device
  plots, [ p(0,0), p(0,0) ], [ p(1,1), p(1,0) ], /device
endif

end



FUNCTION psym_circle, E, ANGLE, flag= FLAG, radius= RADIUS, fill= FILL
; ANGLE is in degrees
  FILL = Keyword_set( FILL )
  theta = Findgen( 48 ) * 2 * !pi / 47.
  ANGLE = Keyword_set( ANGLE ) ? Float( ANGLE[ 0 ] ) * !pi / 180. : 0.
  If Keyword_set( FLAG ) Then theta = theta + Float( FLAG - 1 ) * !pi / 4.
  While Max( theta ) Ge 2*!pi Do theta[ Where( theta Ge 2*!pi ) ] = theta[ Where( theta Ge 2*!pi ) ] - 2 * !pi
  ;
  If N_elements(   E   ) Eq 0 Then E = 1
  e2 = 1./E^2
  y2 = 1./( tan( theta - ANGLE )^2 + E2 )
  r = Sqrt( 1 + y2 * ( 1 - E2 ) )
  ;
  If Keyword_set( FLAG ) Then Begin
    theta = [ theta[ 0 ], theta ]
    r     = [ 2 * r[ 0 ], r     ]
   Endif
  If Keyword_set( RADIUS ) Then r = r * RADIUS[ 0 ]
  Usersym, r * Sin( theta ), r * Cos( theta ), fill= FILL
  Return, 8
 End


FUNCTION SCREENREAD, X0, Y0, NX, NY, DEPTH=DEPTH

;- Check arguments
if (n_elements(x0) eq 0) then x0 = 0
if (n_elements(y0) eq 0) then y0 = 0
if (n_elements(nx) eq 0) then nx = !d.x_vsize - x0
if (n_elements(ny) eq 0) then ny = !d.y_vsize - y0

;- Check for TVRD capable device
tvrd_true = !d.flags and 128
if (tvrd_true eq 0) then message, $
  'TVRD is not supported on this device: ' + !d.name

;- On devices which support windows, check for open window
win_true = !d.flags and 256
if (win_true gt 0) and (!d.window lt 0) then message, $
  'No graphics window are open'

;- Get IDL version number
version = float(!version.release)

;- Get display depth
depth = 8
if (win_true gt 0) then begin
  if (version ge 5.1) then begin
    device, get_visual_depth=depth
  endif else begin
    if (!d.n_colors gt 256) then depth = 24
  endelse
endif

;- Set decomposed color mode on 24-bit displays
if (depth gt 8) then begin
  entry_decomposed = 0
  if (version gt 5.1) then $
    device, get_decomposed=entry_decomposed
  device, decomposed=1
endif

;- Get the contents of the window
if (depth gt 8) then true = 1 else true = 0
image = tvrd(x0, y0, nx, ny, order=0, true=true)

;- Restore decomposed color mode on 24-bit displays
if (depth gt 8) then device, decomposed=entry_decomposed

;- Return result to caller
return, image

END

PRO SAVEIMAGE, FILE, $
  BMP=BMP, PNG=PNG, GIF=GIF, JPEG=JPEG, TIFF=TIFF, $
  QUALITY=QUALITY, DITHER=DITHER, CUBE=CUBE, QUIET=QUIET

;- Check arguments
if (n_params() ne 1) then $
  message, 'Usage: SAVEIMAGE, FILE'
if (n_elements(file) eq 0) then $
  message, 'Argument FILE is undefined'
if (n_elements(quality) eq 0) then quality = 75

;- Get output file type
output = 'JPEG'
if keyword_set(bmp)  then output = 'BMP'
if keyword_set(png)  then output = 'PNG'
if keyword_set(gif)  then output = 'GIF'
if keyword_set(jpeg) then output = 'JPEG'
if keyword_set(tiff) then output = 'TIFF'

;- Check if GIF output is available
version = float(!version.release)
if (version ge 5.4) and (output eq 'GIF') then $
  message, 'GIF output is not available'

;- Get contents of graphics window,
;- and color table if needed
image = screenread(depth=depth)
if (depth le 8) then tvlct, r, g, b, /get

;- Write 8-bit output file
if (output eq 'BMP') or $
   (output eq 'PNG') or $
   (output eq 'GIF') then begin

  ;- If image depth is 24-bit, convert to 8-bit
  if (depth gt 8) then begin
    case keyword_set(cube) of
      0 : image = color_quan(image, 1, r, g, b, $
            colors=256, dither=keyword_set(dither))
      1 : image = color_quan(image, 1, r, g, b, cube=6)
    endcase
  endif

  ;- Reverse PNG image order if required
  if (output eq 'PNG') and (version le 5.3) then $
    image = reverse(temporary(image), 2)

  ;- Save the image
  case output of
    'BMP'  : write_bmp, file, image, r, g, b
    'PNG'  : write_png, file, image, r, g, b
    'GIF'  : write_gif, file, image, r, g, b
  endcase

endif

;- Write 24-bit output file
if (output eq 'JPEG') or $
   (output eq 'TIFF') then begin

  ;- Convert 8-bit image to 24-bit
  if (depth le 8) then begin
    info = size(image)
    nx = info[1]
    ny = info[2]
    true = bytarr(3, nx, ny)
    true[0, *, *] = r[image]
    true[1, *, *] = g[image]
    true[2, *, *] = b[image]
    image = temporary(true)
  endif

  ;- Reverse TIFF image order
  if (output eq 'TIFF') then $
    image = reverse(temporary(image), 3)

  ;- Write the image
  case output of
    'JPEG' : write_jpeg, file, image, $
               true=1, quality=quality
    'TIFF' : write_tiff, file, image, 1
  endcase

endif

;- Report to user
if (keyword_set(quiet) eq 0) then $
  print, file, output, $
    format='("Created ",a," in ",a," format")'

END



;+
; NAME:
;   COLORBAR
;
; PURPOSE:
;
;       The purpose of this routine is to add a color bar to the current
;       graphics window.
;
; AUTHOR:
;
;   FANNING SOFTWARE CONSULTING
;   David Fanning, Ph.D.
;   1645 Sheely Drive
;   Fort Collins, CO 80526 USA
;   Phone: 970-221-0438
;   E-mail: davidf@dfanning.com
;   Coyote's Guide to IDL Programming: http://www.dfanning.com/
;
; CATEGORY:
;
;       Graphics, Widgets.
;
; CALLING SEQUENCE:
;
;       COLORBAR
;
; INPUTS:
;
;       None.
;
; KEYWORD PARAMETERS:
;
;       BOTTOM:       The lowest color index of the colors to be loaded in
;                     the bar.
;
;       CHARSIZE:     The character size of the color bar annotations. Default is 1.0.
;
;       COLOR:        The color index of the bar outline and characters. Default
;                     is !P.Color..
;
;       DIVISIONS:     The number of divisions to divide the bar into. There will
;                     be (divisions + 1) annotations. The default is 6.
;
;       FONT:         Sets the font of the annotation. Hershey: -1, Hardware:0, True-Type: 1.
;
;       FORMAT:       The format of the bar annotations. Default is '(I5)'.
;
;       INVERTCOLORS: Setting this keyword inverts the colors in the color bar.
;
;       MAXRANGE:     The maximum data value for the bar annotation. Default is
;                     NCOLORS.
;
;       MINRANGE:     The minimum data value for the bar annotation. Default is 0.
;
;       MINOR:        The number of minor tick divisions. Default is 2.
;
;       NCOLORS:      This is the number of colors in the color bar.
;
;       POSITION:     A four-element array of normalized coordinates in the same
;                     form as the POSITION keyword on a plot. Default is
;                     [0.88, 0.10, 0.95, 0.90] for a vertical bar and
;                     [0.10, 0.88, 0.90, 0.95] for a horizontal bar.
;;
;       RANGE:        A two-element vector of the form [min, max]. Provides an
;                     alternative way of setting the MINRANGE and MAXRANGE keywords.
;
;       RIGHT:        This puts the labels on the right-hand side of a vertical
;                     color bar. It applies only to vertical color bars.
;
;       TICKNAMES:    A string array of names or values for the tick marks.
;
;       TITLE:        This is title for the color bar. The default is to have
;                     no title.
;
;       TOP:          This puts the labels on top of the bar rather than under it.
;                     The keyword only applies if a horizontal color bar is rendered.
;
;       VERTICAL:     Setting this keyword give a vertical color bar. The default
;                     is a horizontal color bar.
;
; COMMON BLOCKS:
;
;       None.
;
; SIDE EFFECTS:
;
;       Color bar is drawn in the current graphics window.
;
; RESTRICTIONS:
;
;       The number of colors available on the display device (not the
;       PostScript device) is used unless the NCOLORS keyword is used.
;
; EXAMPLE:
;
;       To display a horizontal color bar above a contour plot, type:
;
;       LOADCT, 5, NCOLORS=100
;       CONTOUR, DIST(31,41), POSITION=[0.15, 0.15, 0.95, 0.75], $
;          C_COLORS=INDGEN(25)*4, NLEVELS=25
;       COLORBAR, NCOLORS=100, POSITION=[0.15, 0.85, 0.95, 0.90]
;
; MODIFICATION HISTORY:
;
;       Written by: David W. Fanning, 10 JUNE 96.
;       10/27/96: Added the ability to send output to PostScript. DWF
;       11/4/96: Substantially rewritten to go to screen or PostScript
;           file without having to know much about the PostScript device
;           or even what the current graphics device is. DWF
;       1/27/97: Added the RIGHT and TOP keywords. Also modified the
;            way the TITLE keyword works. DWF
;       7/15/97: Fixed a problem some machines have with plots that have
;            no valid data range in them. DWF
;       12/5/98: Fixed a problem in how the colorbar image is created that
;            seemed to tickle a bug in some versions of IDL. DWF.
;       1/12/99: Fixed a problem caused by RSI fixing a bug in IDL 5.2. Sigh... DWF.
;       3/30/99: Modified a few of the defaults. DWF.
;       3/30/99: Used NORMAL rather than DEVICE coords for positioning bar. DWF.
;       3/30/99: Added the RANGE keyword. DWF.
;       3/30/99: Added FONT keyword. DWF
;       5/6/99: Many modifications to defaults. DWF.
;       5/6/99: Removed PSCOLOR keyword. DWF.
;       5/6/99: Improved error handling on position coordinates. DWF.
;       5/6/99. Added MINOR keyword. DWF.
;       5/6/99: Set Device, Decomposed=0 if necessary. DWF.
;       2/9/99: Fixed a problem caused by setting BOTTOM keyword, but not NCOLORS. DWF.
;       8/17/99. Fixed a problem with ambiguous MIN and MINOR keywords. DWF
;       8/25/99. I think I *finally* got the BOTTOM/NCOLORS thing sorted out. :-( DWF.
;       10/10/99. Modified the program so that current plot and map coordinates are
;            saved and restored after the colorbar is drawn. DWF.
;       3/18/00. Moved a block of code to prevent a problem with color decomposition. DWF.
;       4/28/00. Made !P.Font default value for FONT keyword. DWF.
;       9/26/00. Made the code more general for scalable pixel devices. DWF.
;       1/16/01. Added INVERTCOLORS keyword. DWF.
;       5/11/04. Added TICKNAME keyword. DWF.
;-
;
;###########################################################################
;
; LICENSE
;
; This software is OSI Certified Open Source Software.
; OSI Certified is a certification mark of the Open Source Initiative.
;
; Copyright � 2000-2004 Fanning Software Consulting.
;
; This software is provided "as-is", without any express or
; implied warranty. In no event will the authors be held liable
; for any damages arising from the use of this software.
;
; Permission is granted to anyone to use this software for any
; purpose, including commercial applications, and to alter it and
; redistribute it freely, subject to the following restrictions:
;
; 1. The origin of this software must not be misrepresented; you must
;    not claim you wrote the original software. If you use this software
;    in a product, an acknowledgment in the product documentation
;    would be appreciated, but is not required.
;
; 2. Altered source versions must be plainly marked as such, and must
;    not be misrepresented as being the original software.
;
; 3. This notice may not be removed or altered from any source distribution.
;
; For more information on Open Source Software, visit the Open Source
; web site: http://www.opensource.org.
;
;###########################################################################


PRO COLORBAR, BOTTOM=bottom, CHARSIZE=charsize, COLOR=color, DIVISIONS=divisions, $
   FORMAT=format, POSITION=position, MAXRANGE=maxrange, MINRANGE=minrange, NCOLORS=ncolors, $
   TITLE=title, VERTICAL=vertical, TOP=top, RIGHT=right, MINOR=minor, $
   RANGE=range, FONT=font, TICKLEN=ticklen, _EXTRA=extra, INVERTCOLORS=invertcolors, $
   TICKNAMES=ticknames

   ; Return to caller on error.

On_Error, 2

   ; Save the current plot state.

bang_p = !P
bang_x = !X
bang_Y = !Y
bang_Z = !Z
bang_Map = !Map

   ; Are scalable pixels available on the device?

IF (!D.Flags AND 1) NE 0 THEN scalablePixels = 1 ELSE scalablePixels = 0

   ; Which release of IDL is this?

thisRelease = Float(!Version.Release)

    ; Check and define keywords.

IF N_ELEMENTS(ncolors) EQ 0 THEN BEGIN

   ; Most display devices to not use the 256 colors available to
   ; the PostScript device. This presents a problem when writing
   ; general-purpose programs that can be output to the display or
   ; to the PostScript device. This problem is especially bothersome
   ; if you don't specify the number of colors you are using in the
   ; program. One way to work around this problem is to make the
   ; default number of colors the same for the display device and for
   ; the PostScript device. Then, the colors you see in PostScript are
   ; identical to the colors you see on your display. Here is one way to
   ; do it.

   IF scalablePixels THEN BEGIN
      oldDevice = !D.NAME

         ; What kind of computer are we using? SET_PLOT to appropriate
         ; display device.

      thisOS = !VERSION.OS_FAMILY
      thisOS = STRMID(thisOS, 0, 3)
      thisOS = STRUPCASE(thisOS)
      CASE thisOS of
         'MAC': SET_PLOT, thisOS
         'WIN': SET_PLOT, thisOS
         ELSE: SET_PLOT, 'X'
      ENDCASE

         ; Here is how many colors we should use.

      ncolors = !D.TABLE_SIZE
      SET_PLOT, oldDevice
    ENDIF ELSE ncolors = !D.TABLE_SIZE
ENDIF
IF N_ELEMENTS(bottom) EQ 0 THEN bottom = 0B
IF N_ELEMENTS(charsize) EQ 0 THEN charsize = 1.0
IF N_ELEMENTS(format) EQ 0 THEN format = '(I5)'
IF N_ELEMENTS(color) EQ 0 THEN color = !P.Color
IF N_ELEMENTS(minrange) EQ 0 THEN minrange = 0
IF N_ELEMENTS(maxrange) EQ 0 THEN maxrange = ncolors
IF N_ELEMENTS(ticklen) EQ 0 THEN ticklen = 0.2
IF N_ELEMENTS(minor) EQ 0 THEN minor = 2
IF N_ELEMENTS(range) NE 0 THEN BEGIN
   minrange = range[0]
   maxrange = range[1]
ENDIF
IF N_ELEMENTS(divisions) EQ 0 THEN divisions = 6
IF N_ELEMENTS(font) EQ 0 THEN font = !P.Font
IF N_ELEMENTS(title) EQ 0 THEN title = ''

; You can't have a format set *and* use ticknames.
IF N_ELEMENTS(ticknames) NE 0 THEN format = ""

IF KEYWORD_SET(vertical) THEN BEGIN
   bar = REPLICATE(1B,20) # BINDGEN(ncolors)
   IF Keyword_Set(invertcolors) THEN bar = Reverse(bar, 2)
   IF N_ELEMENTS(position) EQ 0 THEN BEGIN
      position = [0.88, 0.1, 0.95, 0.9]
   ENDIF ELSE BEGIN
      IF position[2]-position[0] GT position[3]-position[1] THEN BEGIN
         position = [position[1], position[0], position[3], position[2]]
      ENDIF
      IF position[0] GE position[2] THEN Message, "Position coordinates can't be reconciled."
      IF position[1] GE position[3] THEN Message, "Position coordinates can't be reconciled."
   ENDELSE
ENDIF ELSE BEGIN
   bar = BINDGEN(ncolors) # REPLICATE(1B, 20)
   IF Keyword_Set(invertcolors) THEN bar = Reverse(bar, 1)
   IF N_ELEMENTS(position) EQ 0 THEN BEGIN
      position = [0.1, 0.88, 0.9, 0.95]
   ENDIF ELSE BEGIN
      IF position[3]-position[1] GT position[2]-position[0] THEN BEGIN
         position = [position[1], position[0], position[3], position[2]]
      ENDIF
      IF position[0] GE position[2] THEN Message, "Position coordinates can't be reconciled."
      IF position[1] GE position[3] THEN Message, "Position coordinates can't be reconciled."
   ENDELSE
ENDELSE

   ; Scale the color bar.

 bar = BYTSCL(bar, TOP=(ncolors-1 < (255-bottom))) + bottom

   ; Get starting locations in NORMAL coordinates.

xstart = position(0)
ystart = position(1)

   ; Get the size of the bar in NORMAL coordinates.

xsize = (position(2) - position(0))
ysize = (position(3) - position(1))

   ; Display the color bar in the window. Sizing is
   ; different for PostScript and regular display.

IF scalablePixels THEN BEGIN

   TV, bar, xstart, ystart, XSIZE=xsize, YSIZE=ysize, /Normal

ENDIF ELSE BEGIN

   bar = CONGRID(bar, CEIL(xsize*!D.X_VSize), CEIL(ysize*!D.Y_VSize), /INTERP)

        ; Decomposed color off if device supports it.

   CASE  StrUpCase(!D.NAME) OF
        'X': BEGIN
            IF thisRelease GE 5.2 THEN Device, Get_Decomposed=thisDecomposed
            Device, Decomposed=0
            ENDCASE
        'WIN': BEGIN
            IF thisRelease GE 5.2 THEN Device, Get_Decomposed=thisDecomposed
            Device, Decomposed=0
            ENDCASE
        'MAC': BEGIN
            IF thisRelease GE 5.2 THEN Device, Get_Decomposed=thisDecomposed
            Device, Decomposed=0
            ENDCASE
        ELSE:
   ENDCASE

   TV, bar, xstart, ystart, /Normal

      ; Restore Decomposed state if necessary.

   CASE StrUpCase(!D.NAME) OF
      'X': BEGIN
         IF thisRelease GE 5.2 THEN Device, Decomposed=thisDecomposed
         ENDCASE
      'WIN': BEGIN
         IF thisRelease GE 5.2 THEN Device, Decomposed=thisDecomposed
         ENDCASE
      'MAC': BEGIN
         IF thisRelease GE 5.2 THEN Device, Decomposed=thisDecomposed
         ENDCASE
      ELSE:
   ENDCASE

ENDELSE

   ; Annotate the color bar.

IF KEYWORD_SET(vertical) THEN BEGIN

   IF KEYWORD_SET(right) THEN BEGIN

      PLOT, [minrange,maxrange], [minrange,maxrange], /NODATA, XTICKS=1, $
         YTICKS=divisions, XSTYLE=1, YSTYLE=9, $
         POSITION=position, COLOR=color, CHARSIZE=charsize, /NOERASE, $
         YTICKFORMAT='(A1)', XTICKFORMAT='(A1)', YTICKLEN=ticklen , $
         YRANGE=[minrange, maxrange], FONT=font, _EXTRA=extra, YMINOR=minor

      AXIS, YAXIS=1, YRANGE=[minrange, maxrange], YTICKFORMAT=format, YTICKS=divisions, $
         YTICKLEN=ticklen, YSTYLE=1, COLOR=color, CHARSIZE=charsize, $
         FONT=font, YTITLE=title, _EXTRA=extra, YMINOR=minor, YTICKNAME=ticknames

   ENDIF ELSE BEGIN

      PLOT, [minrange,maxrange], [minrange,maxrange], /NODATA, XTICKS=1, $
         YTICKS=divisions, XSTYLE=1, YSTYLE=9, YMINOR=minor, $
         POSITION=position, COLOR=color, CHARSIZE=charsize, /NOERASE, $
         YTICKFORMAT=format, XTICKFORMAT='(A1)', YTICKLEN=ticklen , $
         YRANGE=[minrange, maxrange], FONT=font, YTITLE=title, _EXTRA=extra, $
         YTICKNAME=ticknames

      AXIS, YAXIS=1, YRANGE=[minrange, maxrange], YTICKFORMAT='(A1)', YTICKS=divisions, $
         YTICKLEN=ticklen, YSTYLE=1, COLOR=color, CHARSIZE=charsize, $
         FONT=font, _EXTRA=extra, YMINOR=minor

   ENDELSE

ENDIF ELSE BEGIN

   IF KEYWORD_SET(top) THEN BEGIN

      PLOT, [minrange,maxrange], [minrange,maxrange], /NODATA, XTICKS=divisions, $
         YTICKS=1, XSTYLE=9, YSTYLE=1, $
         POSITION=position, COLOR=color, CHARSIZE=charsize, /NOERASE, $
         YTICKFORMAT='(A1)', XTICKFORMAT='(A1)', XTICKLEN=ticklen, $
         XRANGE=[minrange, maxrange], FONT=font, _EXTRA=extra, XMINOR=minor

      AXIS, XTICKS=divisions, XSTYLE=1, COLOR=color, CHARSIZE=charsize, $
         XTICKFORMAT=format, XTICKLEN=ticklen, XRANGE=[minrange, maxrange], XAXIS=1, $
         FONT=font, XTITLE=title, _EXTRA=extra, XCHARSIZE=charsize, XMINOR=minor, $
         XTICKNAME=ticknames

   ENDIF ELSE BEGIN

      PLOT, [minrange,maxrange], [minrange,maxrange], /NODATA, XTICKS=divisions, $
         YTICKS=1, XSTYLE=1, YSTYLE=1, TITLE=title, $
         POSITION=position, COLOR=color, CHARSIZE=charsize, /NOERASE, $
         YTICKFORMAT='(A1)', XTICKFORMAT=format, XTICKLEN=ticklen, $
         XRANGE=[minrange, maxrange], FONT=font, XMinor=minor, _EXTRA=extra, $
         XTICKNAME=ticknames

    ENDELSE

ENDELSE

   ; Restore the previous plot and map system variables.

!P = bang_p
!X = bang_x
!Y = bang_y
!Z = bang_z
!Map = bang_map

END


PRO LOADCOLORS, BOTTOM=BOTTOM, NAMES=NAMES

;- Check arguments
if (n_elements(bottom) eq 0) then bottom = 0

;- Load McIDAS graphics colors
red = [  0, 255,   0, 255,   0, 255,   0, 255, $
         0, 255, 255, 112, 219, 127,   0, 255, $
        90,  50, 150, 255]
grn = [  0,   0, 255, 255, 255,   0,   0, 255, $
         0, 187, 127, 219, 112, 127, 163, 171, $
        90,  50, 50, 90]
blu = [  0, 255, 255,   0,   0,   0, 255, 255, $
       115,   0, 127, 147, 219, 127, 255, 127, $
        90,  50, 255, 200]
tvlct, red, grn, blu, bottom

;- Set color names
names = [ 'Black', 'Magenta', 'Cyan', 'Yellow', 'Green', 'Red', 'Blue', 'White', $
          'Navy', 'Gold', 'Pink', 'Aquamarine', 'Orchid', 'Gray', 'Sky', 'Beige', $
          'DarkGray', 'GraphiteGray', 'Purple', 'FlowerPink' ]

END

 

[전체] 

 

 

 

 참고 문헌

[논문]

  • 없음

[보고서]

  • 없음

[URL]

  • 없음

 

 문의사항

[기상학/프로그래밍 언어]

  • sangho.lee.1990@gmail.com

[해양학/천문학/빅데이터]

  • saimang0804@gmail.com