반응형

     정보

    • 업무명     : NetCDF 형식인 Aqua/CERES 기상위성 자료를 이용한 가시화

    • 작성자     : 이상호

    • 작성일     : 2019-10-22

    • 설   명      :

    • 수정이력 :

      • 2020-02-05 : 소스 코드 명세 추가

     

     내용

    [개요]

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

    • 최근 국외 기상학회에서는 R 또는 Python을 통해 가시화 결과를 종종 볼 수 있습니다.

    • 따라서 Python을 이용하여 NetCDF 자료 전처리 및 가시화를 소개해 드리고자 합니다. 

     

    [특징]

    • NetCDF 형태인 기상위성 자료를 이해하기 위해 가시화 도구가 필요하며 이 프로그램은 이러한 목적을 달성하기 위해 고안된 소프트웨어

     

    [기능]

    • Aqua/CERES 기상위성 자료를 이용한 가시화

     

    [활용 자료]

    • 위성명 : Aqua 기상위성

    • 센서명 : CERES

    • 자료종류 : 대기상단에서의 상향단파복사

    • 영역 : 전지구 및 전구

    • 해상도 : 20 km

    • 확장자 : .nc

    • 기간 : 2015년 07월 15일 0000-2300 UTC

     

    [자료 처리 방안 및 활용 분석 기법]

    • 없음

     

    [사용법]

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

    • 소스 코드를 실행 (Jupyter notebook 실행)

    • 가시화 결과를 확인

     

    [사용 OS]

    • Window 10

     

    [사용 언어]

    • Python v2.7

     

     소스 코드

    [명세]

    • 라이브러리 읽기

      • NetCDF 읽기 : netCDF4 

      • 데이터 전처리 : dplython

      • 가시화 : matplot

    •  
    # Library
    import pandas as pd
    import numpy as np
    import sys 
    # import iris
    import os
    import matplotlib.pyplot as plt
    from dplython import *
        # (DplyFrame, X, diamonds, select, sift, sample_n,
        #     sample_frac, head, arrange, mutate, group_by, summarize, DelayFunction) 
    from scipy.stats import linregress
    from matplotlib import pyplot as plt
    from IPython.display import Image
    from mpl_toolkits.basemap import Basemap
    from matplotlib.colors import Normalize
    import matplotlib
    import matplotlib.cm as cm
    import seaborn as sns
    from scipy.stats import linregress
    from matplotlib import rcParams
    from netCDF4 import Dataset
    import struct
    import binascii
    from mpl_toolkits.basemap import addcyclic
    from netCDF4 import num2date, date2num, date2index
    import datetime
    from pyhdf.SD import SD, SDC
    import h5py

     

    • NetCDF 파일 읽기

    ncfile_path  = 'CERES/CERES_SSF_Aqua-XTRK_Edition4A_Subset_2015071500-2015071523.nc'
    ncfile = Dataset(ncfile_path)
    
    # print(ncfile)

     

    • NetCDF 헤더 보기

      • 원도우 (Window)에서 ncdump를 사용할 경우 Anaconda Cloud에서 "conda install -c anaconda netcdf4" 설치 필요

      • ncdump 외에 "ncBrowse", "Panoply" 등 다양한 도구가 있으니 참고 바램

     

     

    [연구개발] NetCDF 파일을 이용한 시각화 도구 소개

    정보 업무명 : NetCDF 파일을 이용한 시각화 도구 소개 작성자 : 이상호 작성일 : 2020-02-03 설 명 : 수정이력 : 내용 [개요] 안녕하세요? 기상 연구 및 웹 개발을 담당하고 있는 해솔입니다. NetCDF 파일 (*.nc)..

    shlee1990.tistory.com

     

    !ncdump -h CERES/CERES_SSF_Aqua-XTRK_Edition4A_Subset_2015071500-2015071523.nc

     

    netcdf CERES/CERES_SSF_Aqua-XTRK_Edition4A_Subset_2015071500-2015071523 {
    dimensions:
    	time = UNLIMITED ; // (2370473 currently)
    	The_8_most_prevalent_surface_types = 8 ;
    	Conditions_clear__lower__upper__upper_over_lower = 4 ;
    variables:
    	double time(time) ;
    		time:long_name = "time" ;
    		time:units = "days since 1970-01-01 00:00:00" ;
    		time:_FillValue = 1.79769313486232e+308 ;
    		time:valid_range = 0., 39412.5 ;
    	float lon(time) ;
    		lon:long_name = "longitude" ;
    		lon:units = "degrees_east" ;
    		lon:_FillValue = 3.402823e+038f ;
    		lon:valid_range = -180.f, 180.f ;
    	float lat(time) ;
    		lat:long_name = "latitude" ;
    		lat:units = "degrees_north" ;
    		lat:_FillValue = 3.402823e+038f ;
    		lat:valid_range = -90.f, 90.f ;
    	double Time_of_observation(time) ;
    		Time_of_observation:orig_name = "Time of observation" ;
    		Time_of_observation:units = "day" ;
    		Time_of_observation:format = "F18.9" ;
    		Time_of_observation:_FillValue = 1.79769313486232e+308 ;
    		Time_of_observation:valid_range = 2440000., 2480000. ;
    	float Longitude_of_CERES_FOV_at_surface(time) ;
    		Longitude_of_CERES_FOV_at_surface:orig_name = "Longitude of CERES FOV at surface" ;
    		Longitude_of_CERES_FOV_at_surface:units = "degrees" ;
    		Longitude_of_CERES_FOV_at_surface:format = "F18.9" ;
    		Longitude_of_CERES_FOV_at_surface:_FillValue = 3.402823e+038f ;
    		Longitude_of_CERES_FOV_at_surface:valid_range = 0.f, 360.f ;
    	float Colatitude_of_CERES_FOV_at_surface(time) ;
    		Colatitude_of_CERES_FOV_at_surface:orig_name = "Colatitude of CERES FOV at surface" ;
    		Colatitude_of_CERES_FOV_at_surface:units = "degrees" ;
    		Colatitude_of_CERES_FOV_at_surface:format = "F18.9" ;
    		Colatitude_of_CERES_FOV_at_surface:_FillValue = 3.402823e+038f ;
    		Colatitude_of_CERES_FOV_at_surface:valid_range = 0.f, 180.f ;
    	float CERES_solar_zenith_at_surface(time) ;
    		CERES_solar_zenith_at_surface:orig_name = "CERES solar zenith at surface" ;
    		CERES_solar_zenith_at_surface:units = "degrees" ;
    		CERES_solar_zenith_at_surface:format = "F18.9" ;
    		CERES_solar_zenith_at_surface:_FillValue = 3.402823e+038f ;
    		CERES_solar_zenith_at_surface:valid_range = 0.f, 180.f ;
    	float CERES_SW_TOA_flux___upwards(time) ;
    		CERES_SW_TOA_flux___upwards:orig_name = "CERES SW TOA flux - upwards" ;
    		CERES_SW_TOA_flux___upwards:units = "Watts per square meter" ;
    		CERES_SW_TOA_flux___upwards:format = "F18.9" ;
    		CERES_SW_TOA_flux___upwards:_FillValue = 3.402823e+038f ;
    		CERES_SW_TOA_flux___upwards:valid_range = 0.f, 1400.f ;
    	float TOA_Incoming_Solar_Radiation(time) ;
    		TOA_Incoming_Solar_Radiation:orig_name = "TOA Incoming Solar Radiation" ;
    		TOA_Incoming_Solar_Radiation:units = "Watts per square meter" ;
    		TOA_Incoming_Solar_Radiation:format = "F18.9" ;
    		TOA_Incoming_Solar_Radiation:_FillValue = 3.402823e+038f ;
    		TOA_Incoming_Solar_Radiation:valid_range = 0.f, 1400.f ;
    	float CERES_downward_SW_surface_flux___Model_B(time) ;
    		CERES_downward_SW_surface_flux___Model_B:orig_name = "CERES downward SW surface flux - Model B" ;
    		CERES_downward_SW_surface_flux___Model_B:units = "Watts per square meter" ;
    		CERES_downward_SW_surface_flux___Model_B:format = "F18.9" ;
    		CERES_downward_SW_surface_flux___Model_B:_FillValue = 3.402823e+038f ;
    		CERES_downward_SW_surface_flux___Model_B:valid_range = 0.f, 1400.f ;
    	short Surface_type_index(time, The_8_most_prevalent_surface_types) ;
    		Surface_type_index:orig_name = "Surface type index" ;
    		Surface_type_index:units = "N/A" ;
    		Surface_type_index:format = "I10" ;
    		Surface_type_index:_FillValue = 32767s ;
    		Surface_type_index:valid_range = 1s, 20s ;
    	float Clear_layer_overlap_percent_coverages(time, Conditions_clear__lower__upper__upper_over_lower) ;
    		Clear_layer_overlap_percent_coverages:orig_name = "Clear/layer/overlap percent coverages" ;
    		Clear_layer_overlap_percent_coverages:units = "N/A" ;
    		Clear_layer_overlap_percent_coverages:format = "F18.9" ;
    		Clear_layer_overlap_percent_coverages:_FillValue = 3.402823e+038f ;
    		Clear_layer_overlap_percent_coverages:valid_range = 0.f, 100.f ;
    
    // global attributes:
    		:Conventions = "CF-1.0" ;
    		:Subsetter_title = "ASDC CERES Subset" ;
    		:Subsetter_version = "2.9.b1" ;
    		:Subsetter_institution = "Atmospheric Science Data Center (ASDC) http://eosweb.larc.nasa.gov" ;
    		:Subsetter_history = "2017-08-03T10:35:23 -0400 SubsetCeresSsf" ;
    		:Subsetter_temporalFilter = "2015-07-15T00:00:00.000000Z to 2015-07-15T23:59:59.000000Z" ;
    		:Subsetter_spatialFilter = "POLYGON ((-180 -90, -180 90, 180 90, 180 -90, -180 -90))" ;
    		:Subsetter_parameterFilter = "none" ;
    		:platform = "Aqua" ;
    		:history = "Thu Aug  3 11:30:59 2017: ncrcat -o CERES_SSF_Aqua-XTRK_Edition4A_Subset_2015071500-2015071523.nc" ;
    		:nco_input_file_number = 24 ;
    		:nco_input_file_list = "CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071500_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071501_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071502_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071503_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071504_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071505_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071506_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071507_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071508_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071509_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071510_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071511_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071512_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071513_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071514_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071515_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071516_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071517_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071518_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071519_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071520_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071521_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071522_Subset.nc CER_SSF_Aqua-FM3-MODIS_Edition4A_401404.2015071523_Subset.nc" ;
    		:nco_openmp_thread_number = 1 ;
    }

     

    • 변수 설정

      • NetCDF에서 필요한 변수 저장

        • 시간 : 시간 변수 (times), 단위 (dtime), Data Frame 형태로 변환 (time)

        • 변수 : 위도 (lon), 경도 (lat), 태양 천정각 (sza), 대기 상단에서의 하향 단파복사 (insw), 대기 상단에서의 상향단파복사 (rsr), 지표면에서의 하향 단파복사 (dsr), 지표면 특성 (surface_type), 청천 비율 (clear_fraction)

    # Time
    times = ncfile.variables[u'time']
    dtime = num2date(times[:], times.units)
    time = pd.to_datetime(dtime)
    
    # Variable
    lon  = ncfile.variables[u'lon'][:] 
    lat  = ncfile.variables[u'lat'][:] 
    sza  = ncfile.variables[u'CERES_solar_zenith_at_surface'][:]
    insw = ncfile.variables[u'TOA_Incoming_Solar_Radiation'][:]
    rsr  = ncfile.variables[u'CERES_SW_TOA_flux___upwards'][:]
    dsr  = ncfile.variables[u'CERES_downward_SW_surface_flux___Model_B'][:]
    surface_type   = ncfile.variables[u'Surface_type_index'][:,1]
    clear_fraction = ncfile.variables[u'Clear_layer_overlap_percent_coverages'][:,1]

     

    • Data Frame 설정

      • 시간의 경우 년, 월, 일, 시, 분, 초, 마이크로초로 변환

      • 앞서 설명한 변수에 대한 컬럼명 지정

    data =  pd.DataFrame( np.column_stack([time.year, time.month, time.day, 
                                           time.hour, time.minute, time.second, time.microsecond, 
                                           lon, lat, sza, insw, rsr, dsr, surface_type, clear_fraction]),
                         columns=['year', 'month', 'day', 'hour', 'minute', 'second', 'microsecond', 
                                  'lon', 'lat', 'sza', 'insw', 'rsr', 'dsr', 'surface_type', 'clear_fraction'])
    
    data.head()

     

    • Data Frame를 통해 L1 전처리

      • 최근 데이터 분석에서 사용되는 R의 "dplyr" 라이브러리와 유사한 "dplython"를 사용

      • 각 변수에 대해 최대값 및 최소값 설정

    data_L1 = ( DplyFrame(data) >>
               sift( (-90 <= X.lat)   &  (X.lat <= 90) ) >>
               sift( (-180 <= X.lon)  &  (X.lon <= 180) ) >>
               sift( (0 <= X.rsr)  &  (X.rsr <= 1400) ) >>
               sift( (0 <= X.dsr)  &  (X.dsr <= 1400) ) >>
               sift( (0 <= X.insw) &  (X.insw <= 1400) ) >>
               sift( (0 <= X.sza)  &  (X.sza <= 90) ) >>
               sift( (0 <= X.hour)  &  (X.hour <= 23) )
            )
    
    data_L1.head()

     

    	year	month	day	hour	minute	second	microsecond	lon	lat	sza	insw	rsr	dsr	surface_type	clear_fraction
    1	2015.0	7.0	15.0	0.0	0.0	0.0	63770.0		74.017220	66.208206	77.034363	295.658325	116.962135	98.196671	10.0	73.008736
    2	2015.0	7.0	15.0	0.0	0.0	0.0	73788.0		73.517990	66.443062	77.118500	293.772278	117.117500	93.707993	17.0	72.541275
    3	2015.0	7.0	15.0	0.0	0.0	0.0	93784.0		72.567398	66.873962	77.275452	290.252289	94.097664	104.814674	7.0	39.283241
    4	2015.0	7.0	15.0	0.0	0.0	0.0	113779.0	71.685020	67.255684	77.417488	287.064911	76.625443	125.678894	17.0	41.375149
    5	2015.0	7.0	15.0	0.0	0.0	0.0	133775.0	70.850426	67.601425	77.548729	284.118256	121.472298	86.047745	17.0	81.676659

     

    • 가시화를 위한 설정

      • 초기 설정

        • 크기 : figure

        • 스타일 : style

        • 폰트 : rc, rcParams

        • 지도 해상도 : Basemap

      • 변수 설정

        • 위도 (lon), 경도 (lat), 상향단파복사 (rsr)

    •  
      • 그림 설정

        • 산점도 : scatter

        • 컬러바 : colorbar

        • 해안선 : drawcostlines, drawcountries, drawmapboundary

        • 수평/수직 그리드 : drawparallels, drawmeridians

        • 그림 제목 : title

        • 그림 저장 : savefig

     

    %matplotlib inline
    # define plot size in inches (width, height) & resolution(DPI)
    plt.figure(figsize=(12, 10))
    
    # style
    plt.style.use('seaborn-darkgrid')
    
    # define font size
    plt.rc("font", size=20)
    plt.rcParams['font.family'] = 'New Century Schoolbook'
    # rcParams['font.family'] = 'sans-serif'
    # plt.rcParams["font.weight"] = "bold"
    # plt.rcParams['axes.labelsize'] = 22
    # plt.rcParams['xtick.labelsize'] = 22
    # plt.rcParams['ytick.labelsize'] = 22
    # plt.rcParams["axes.labelweight"] = "bold"
    # plt.rcParams["axes.titleweight"] = "bold"
    
    m = Basemap(projection='cyl', lon_0 = 0, lat_0 = 0)
    # c (crude) < l (low) < i (intermediate) < h (high) < f (full)
    # Source: http://seesaawiki.jp/met-python/d/Basemap
    
    X, Y = m(data_L1.lon.values, data_L1.lat.values)
    VAL  = data_L1.rsr.values
    # print(VAL)
    
    m.scatter(X, Y, c=VAL, s=1.0, marker="s", zorder=1, vmin=0, vmax=1200, cmap=plt.cm.get_cmap('jet'), alpha=1.0) 
    m.colorbar(location='right', label='Reflected  Shortwave  Radiation  $\mathregular{[Wm^{-2}]}$')
    
    m.drawcoastlines()
    m.drawcountries()
    m.drawmapboundary(fill_color='white')
    m.drawparallels(np.arange(-90,91,30),labels=[1,0,0,0],dashes=[2,2])
    m.drawmeridians(np.arange(0,361,60),labels=[0,0,0,1],dashes=[2,2]) 
    
    plt.title('Aqua / CERES  2015.07.15 00-23 UTC \n')
    # plt.savefig("FIG/Scane_analysis_Himawari-8_AHI_RSR.png")
    plt.show()

     

    그림. Aqua/CERES 기상위성 자료를 이용한 대기상단에서의 상향단파복사 가시화 (전지구).

     

    • matplotlib를 이용한 가시화

      • 초기 설정

      • 변수 설정

      • 그림 설정

        • 그림 좌표에서 원하는 글자 넣기 : annotate

    •  
    %matplotlib inline
    # define plot size in inches (width, height) & resolution(DPI)
    plt.figure(figsize=(12, 10))
    
    # style
    plt.style.use('seaborn-darkgrid')
    
    # define font size
    plt.rc("font", size=22)
    plt.rcParams['font.family'] = 'New Century Schoolbook'
    # rcParams['font.family'] = 'sans-serif'
    plt.rcParams["font.weight"] = "bold"
    plt.rcParams['axes.labelsize'] = 22
    plt.rcParams['xtick.labelsize'] = 22
    plt.rcParams['ytick.labelsize'] = 22
    plt.rcParams["axes.labelweight"] = "bold"
    plt.rcParams["axes.titleweight"] = "bold"
    
    m = Basemap(projection='ortho', lon_0=140.714793, lat_0=-0.007606, resolution='c')
    # c (crude) < l (low) < i (intermediate) < h (high) < f (full)
    # Source: http://seesaawiki.jp/met-python/d/Basemap
    
    X, Y = m(data_L1.lon.values, data_L1.lat.values)
    VAL  = data_L1.rsr.values
    
    m.scatter(X, Y, c=VAL, s=3.0, marker="s", zorder=1, vmin=0, vmax=1200, cmap=plt.cm.get_cmap('gist_earth'), alpha=1.0) 
    m.colorbar(location='right', label='Reflected  Shortwave  Radiation  (RSR)  $\mathregular{[Wm^{-2}]}$')
    
    m.drawcoastlines()
    m.drawcountries()
    m.drawmapboundary(fill_color='white')
    m.drawparallels(np.arange(-60.,61.,30.),labels=[1,0,0,0],dashes=[2,2])
    m.drawmeridians(np.arange(-160.,200.,30.),labels=[0,0,0,1],dashes=[2,2])
    plt.title('RSR using Aqua/CERES on the 1 October, 2016  \n')
    
    plt.annotate(u'60\N{DEGREE SIGN}S', xy=(m(170, -62.5)), color='black', fontweight='bold', xycoords='data', horizontalalignment='center', verticalalignment='top')
    plt.annotate(u'30\N{DEGREE SIGN}S', xy=(m(170, -32.5)), color='black', fontweight='bold', xycoords='data', horizontalalignment='center', verticalalignment='top')
    plt.annotate(u'30\N{DEGREE SIGN}N', xy=(m(170, +27.5)), color='black', fontweight='bold', xycoords='data', horizontalalignment='center', verticalalignment='top')
    plt.annotate(u'60\N{DEGREE SIGN}N', xy=(m(170, +57.5)), color='black', fontweight='bold', xycoords='data', horizontalalignment='center', verticalalignment='top')
    plt.annotate(u'80\N{DEGREE SIGN}E', xy=(m(80, -2.5))  , color='black', fontweight='bold', xycoords='data', horizontalalignment='center', verticalalignment='top')
    plt.annotate(u'110\N{DEGREE SIGN}E', xy=(m(110, -2.5)), color='black', fontweight='bold', xycoords='data', horizontalalignment='center', verticalalignment='top')
    plt.annotate(u'110\N{DEGREE SIGN}E', xy=(m(110, -2.5)), color='black', fontweight='bold', xycoords='data', horizontalalignment='center', verticalalignment='top')
    plt.annotate(u'140\N{DEGREE SIGN}E', xy=(m(140, -2.5)), color='black', fontweight='bold', xycoords='data', horizontalalignment='center', verticalalignment='top')
    plt.annotate(u'170\N{DEGREE SIGN}E', xy=(m(170, -2.5)), color='black', fontweight='bold', xycoords='data', horizontalalignment='center', verticalalignment='top')
    plt.annotate(u'160\N{DEGREE SIGN}W', xy=(m(-160, -2.5)),color='black', fontweight='bold', xycoords='data', horizontalalignment='center', verticalalignment='top')
    # plt.savefig("FIG/Scane_analysis_Aqua_CERES_RSR.png")
    plt.show()

     

    그림. Aqua/CERES 기상위성 자료를 이용한 대기상단에서의 상향단파복사 가시화 (빈구).

     

    [전체]

     

     참고 문헌

    [논문]

    • 없음

    [보고서]

    • 없음

    [URL]

    • 없음

     

     문의사항

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

    • sangho.lee.1990@gmail.com

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

    • saimang0804@gmail.com
    반응형
    • 네이버 블러그 공유하기
    • 네이버 밴드에 공유하기
    • 페이스북 공유하기
    • 카카오스토리 공유하기