[R] "RNetCDF" 패키지 및 NetCDF 형식인 NOAA 최적 내삽 자료를 이용하여 데이터 프레임 (Data Frame)으로 변환 처리 및 가시화 (3)

 정보

  • 업무명     : "RNetCDF" 패키지 및 NetCDF 형식인 NOAA 최적 내삽 자료를 이용하여 데이터 프레임 (Data Frame)으로 변환 처리 및 가시화 (3)

  • 작성자     : 이상호

  • 작성일     : 2020-03-15

  • 설   명      :

  • 수정이력 :

 

 내용

[개요]

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

  • 이전 포스팅에서 NetCDF 파일을 R로 직접 변환하고 데이터 프레임으로 변환하는 방법을 설명했습니다. 이 방법은 간단하나 단점이 있습니다. 즉 Netcdf 파일에서 배열의 잘못된 행렬을 읽을 수 없다는 것입니다. 이는 다른 행렬을 제거하여 배열의 1번째 행렬로부터 데이터 프레임을 변환합니다. 

 

[R] NetCDF 형식인 NOAA 최적 내삽 자료를 이용하여 데이터 프레임 (Data Frame)으로 변환 처리 및 가시화 (1)

정보 업무명 : NetCDF 형식인 NOAA 최적 내삽 자료를 이용하여 데이터 프레임 (Data Frame)으로 변환 처리 및 가시화 (1) 작성자 : 이상호 작성일 : 2020-02-13 설 명 : 수정이력 : 내용 [개요] 안녕하세요? 기상..

shlee1990.tistory.com

  • 이 포스팅는 접근을 확장하고 이전에서의 문제점을 해결하기 위한 것입니다. 즉 최근 자주 사용하는 패키지 (ncdf4, RNetCDF)를 통해 NetCDF 파일을 데이터 프레임 형식으로 변환하는 과정을 소개해 드리고자 합니다.

 

[R] "ncdf4" 패키지 및 NetCDF 형식인 NOAA 최적 내삽 자료를 이용하여 데이터 프레임 (Data Frame)으로 변환 처리 및 가시화 (2)

정보 업무명 : "ncdf4" 패키지 및 NetCDF 형식인 NOAA 최적 내삽 자료를 이용하여 데이터 프레임 (Data Frame)으로 변환 처리 및 가시화 (2) 작성자 : 이상호 작성일 : 2020-02-13 설 명 : 수정이력 : 내용 [개요]..

shlee1990.tistory.com

  • 크게 주요 3 단계로 구성하였습니다. 우선 NetCDF 파일에 포함 된 메타 데이터를 읽고 파일에 저장된 데이터구조를 확인하는 방법을 보여 드리겠습니다. 2 단계의 경우 데이터를 추출하고 마지막 (3 단계)에서는 데이터 프레임으로 변환 및 가시화하겠습니다. 

 

[특징]

  • R에서 NetCDF 파일을 처리하기 위해서 데이터 프레임으로 변환 처리가 요구되며 이 프로그램은 이러한 목적을 달성하기 위한 소프트웨어

 

[기능]

  • RNetCDF 패키지를 통해 파일 읽기

  • 해수면 온도 가시화

 

[활용 자료]

  • 자료명 : sst.wkmean.1990-present.nc

  • 자료 종류 : 최적 내삽 해수면 온도

  • 확장자 : NetCDF

  • 영역 : 전지구

  • 기간 : 1989년 12월 31일 - 2020년 02월 20일

  • 시간 해상도 : 일 1개 (21시)

  • 제공처 : ESRL | Physical sciences Division

 

ESRL : PSD : NOAA Optimum Interpolation (OI) Sea Surface Temperature (SST) V2

 

www.esrl.noaa.gov

 

 

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

  • 없음

 

[사용법]

  • 소스 코드 참조

 

[사용 OS]

  • Windows 10

 

[사용 언어]

  • R v3.6.2

  • R Studio v1.2.5033

 

 소스 코드

[명세]

  • 전역 설정

    • 최대 10 자리 설정

    • 메모리 해제

    • 영어 인코딩 설정

    • 폰트 설정

# Set Option
memory.limit(size = 9999999999999)
options(digits = 10)
Sys.setlocale("LC_TIME", "english")
font = "Palatino Linotype"

 

  • 라이브러리 읽기

# Library Load
library(extrafont)
library(ncdf4)
library(tidyverse)
library(ncdump)
library(RNetCDF)
library(tidyverse)
library(lubridate)
library(gganimate)
library(insol)
library(spData)
library(raster)

 

  • NetCDF 파일 설정 및 열기

    • RNetCDF::open.nc를 통해 파일 열기

sFileDirName = Sys.glob("INPUT/sst.wkmean.1990-present.nc")

oOpenNc = RNetCDF::open.nc(sFileDirName)

 

  • 메타 데이터 이해

    • RNetCDF 패키지에서 print.nc 함수를 사용하여 파일의 메타 데이터를 확인

    • 이러한 메타 데이터에서 dimensions은 위도, 경도 및 시간과 같은 벡터 형식 변수가 포함

    • 추가로 메타 데이터에서 variables마다 세부 정보  포함

# NetCDF Meta Information
RNetCDF::print.nc(oOpenNc)

 

> RNetCDF::print.nc(oOpenNc)

netcdf classic {
dimensions:
	lat = 180 ;
	lon = 360 ;
	time = UNLIMITED ; // (1574 currently)
	nbnds = 2 ;
variables:
	NC_FLOAT lat(lat) ;
		NC_CHAR lat:units = "degrees_north" ;
		NC_CHAR lat:long_name = "Latitude" ;
		NC_FLOAT lat:actual_range = 89.5, -89.5 ;
		NC_CHAR lat:standard_name = "latitude" ;
		NC_CHAR lat:axis = "Y" ;
		NC_CHAR lat:coordinate_defines = "center" ;
	NC_FLOAT lon(lon) ;
		NC_CHAR lon:units = "degrees_east" ;
		NC_CHAR lon:long_name = "Longitude" ;
		NC_FLOAT lon:actual_range = 0.5, 359.5 ;
		NC_CHAR lon:standard_name = "longitude" ;
		NC_CHAR lon:axis = "X" ;
		NC_CHAR lon:coordinate_defines = "center" ;
	NC_SHORT sst(lon, lat, time) ;
		NC_CHAR sst:long_name = "Weekly Mean of Sea Surface Temperature" ;
		NC_FLOAT sst:unpacked_valid_range = -5, 40 ;
		NC_FLOAT sst:actual_range = -1.79999995231628, 36.1599998474121 ;
		NC_CHAR sst:units = "degC" ;
		NC_FLOAT sst:add_offset = 0 ;
		NC_FLOAT sst:scale_factor = 0.00999999977648258 ;
		NC_SHORT sst:missing_value = 32767 ;
		NC_SHORT sst:precision = 2 ;
		NC_SHORT sst:least_significant_digit = 2 ;
		NC_CHAR sst:var_desc = "Sea Surface Temperature" ;
		NC_CHAR sst:dataset = "NOAA Optimum Interpolation (OI) SST V2" ;
		NC_CHAR sst:level_desc = "Surface" ;
		NC_CHAR sst:statistic = "Weekly Mean" ;
		NC_CHAR sst:parent_stat = "Individual obs" ;
		NC_CHAR sst:standard_name = "sea_surface_temperature" ;
		NC_SHORT sst:valid_range = -500, 4000 ;
	NC_DOUBLE time(time) ;
		NC_CHAR time:units = "days since 1800-1-1 00:00:00" ;
		NC_CHAR time:long_name = "Time" ;
		NC_DOUBLE time:actual_range = 69395, 80406 ;
		NC_CHAR time:delta_t = "0000-00-07 00:00:00" ;
		NC_CHAR time:avg_period = "0000-00-07 00:00:00" ;
		NC_CHAR time:standard_name = "time" ;
		NC_CHAR time:axis = "T" ;
		NC_CHAR time:bounds = "time_bnds" ;
	NC_DOUBLE time_bnds(nbnds, time) ;
		NC_CHAR time_bnds:long_name = "Time Boundaries" ;

// global attributes:
		NC_CHAR :title = "NOAA Optimum Interpolation (OI) SST V2" ;
		NC_CHAR :Conventions = "CF-1.0" ;
		NC_CHAR :history = "Created 10/2002 by RHS" ;
		NC_CHAR :comments = "Data described in  Reynolds, R.W., N.A. Rayner, T.M.
Smith, D.C. Stokes, and W. Wang, 2002: An Improved In Situ and Satellite
SST Analysis for Climate, J. Climate" ;
		NC_CHAR :platform = "Model" ;
		NC_CHAR :source = "NCEP Climate Modeling Branch" ;
		NC_CHAR :institution = "National Centers for Environmental Prediction" ;
		NC_CHAR :References = "https://www.esrl.noaa.gov/psd/data/gridded/data.noaa.oisst.v2.html" ;
		NC_CHAR :NCO = "4.0.0" ;
		NC_CHAR :dataset_title = "NOAA Optimum Interpolation (OI) SST V2" ;
		NC_CHAR :source_url = "http://www.emc.ncep.noaa.gov/research/cmb/sst_analysis/" ;
}

 

  • NetCDF 파일 읽기

    • RNetCDF::read.nc를 통해 파일 읽기

# NetCDF File Read 
liReadNc = RNetCDF::read.nc(oOpenNc)

 

  • 속성 정보 가져오기

    • RNetCDF::dim.inq.nc RNetCDF::att.get.nc를 통해 시간 속성 정보 가져오기
    • RNetCDF::att.get.nc를 통해 해수면 온도에 대한 scale_factor, add_offset, actual_range 가져오기
# Get Time Unit 
nFileNumber = RNetCDF::dim.inq.nc(oOpenNc, "time")$length 
sTimeUnit = RNetCDF::att.get.nc(oOpenNc, "time", "units")

# Get Attribute
fSaleFactor = RNetCDF::att.get.nc(oOpenNc, "sst", "scale_factor")
fAddOffset = RNetCDF::att.get.nc(oOpenNc, "sst", "add_offset")
fActualRange = RNetCDF::att.get.nc(oOpenNc, "sst", "actual_range")

fMinActualRange = fActualRange[1]
fMaxActualRange = fActualRange[2]

 

 

  • 변수 가져오기

    • 시간 (nTime), 경도 (nLon), 위도 (nLat), 해수면 온도 (nVal)

    • 지오포텐셜 고도의 경우 Fill Value의 여부에 따라 Scale Factor 및 Add Off Set 그리고 NA로 설정

# Get Variable 
nTime = RNetCDF::utcal.nc(sTimeUnit, liReadNc$time) 
nLon = liReadNc[["lon"]] 
nLat = liReadNc[["lat"]] 
nVal = (liReadNc[["sst"]] * fSaleFactor) + fAddOffset

dim(nTime)
dim(nLon)
dim(nLat)
dim(nVal)

 

 

  • 데이터 프레임 (Data Frame) 변환

    • 배열의 행렬을 데이터 프레임으로 변환할 때 noncompliance::expand.grid.DT 함수를 이용

    • 벡터화를 사용하기 때문에 속도 개선

# Set Data Frame
dfData = data.frame(
   noncompliance::expand.grid.DT(nTime, nLat, nLon)
   , c(nVal)
)

colnames(dfData) = c("nYear", "nMonth", "nDay", "nHour", "nMinute", "nSec" , "nLat", "nLon", "nVal")

dplyr::tbl_df(dfData)

 

 

  • Data Frame L1을 이용한 L2 전처리 

    • 전체 기간 (1989년 12월 31일 - 2020년 02월 20일), 위도, 경도에 따른 평균 수행

# L1 Processing Using Data Frame
dfDataL1 = dfData %>%
   dplyr::group_by(nLon, nLat) %>%
   dplyr::summarise(nMeanVal = mean(nVal, na.rm = TRUE))

dplyr::tbl_df(dfDataL1)

 

 

  • Data Frame L1을 이용한 L2 전처리

    • 위도 변수 (nLon)가 0~360-180~180으로 변환

# L2 Processing Using Data Frame L1
dfDataL2 = dfDataL1 %>%
   dplyr::mutate(nLon180 = metR::ConvertLongitude(nLon, from = 360))

summary(dfDataL2)

 

 

  • 가시화

    • 데이터 세트에서 정보는 여전히 숨겨져 있기 때문에 가시화 필요

    • 가시화는 일반적인 정적 탐색 데이터 분석에서 웹 브라우저의 동적 대화식 데이터 시각화에 이르기까지 다양함

    • 특히 R의 기본 plot으로 여러 미학적 측면을 제어 할 수 있으나 Hadley Wickham (2016)이 개발한 ggplot2는 새로운 방법으로 시각화하기 때문에 이를 사용 

 

  • 가시화를 위한 초기 설정

  • ggplot2를 이용한 가시화

# Visualization Using ggplot2
ggplot() +
   theme_bw() +
   geom_tile(data = dfDataL2, aes(x = nLon180, y = nLat, fill = nMeanVal)) +
   metR::geom_text_contour(data = dfDataL2, aes(x = nLon180, y = nLat, z = nMeanVal), stroke = 0.2, check_overlap = TRUE, rotate = TRUE, na.rm = TRUE) +
   metR::geom_contour2(data = dfDataL2, aes(x = nLon180, y = nLat, z = nMeanVal), color = "black", alpha = 0.3) +
   scale_fill_gradientn(colours = cbOcean, limits=c(-5, 35), breaks = seq(-5, 35, 10), na.value = cbOcean[length(cbOcean)]) +
   geom_sf(data = mapData, fill = "grey100", col = "black") +
   metR::scale_x_longitude(expand = c(0, 0), breaks = seq(-180, 180, 60), limits = c(-180, 180)) +
   metR::scale_y_latitude(expand = c(0, 0), breaks = seq(-90, 90, 30), limits = c(-90, 90)) +
   labs(
      x = ""
      , y = ""
      , fill = "Mean Sea Surface Temperature [℃]"
      , colour = ""
      , title  = "NOAA Optimum Interpolation (OI) SST V2"
      , subtitle = "Period : December 31, 1989 - February 20, 2020"
      , caption = "Source : NCEP Climate Modeling Branch"
   ) +
   theme(
      plot.title = element_text(face = "bold", size = 18, color = "black")
      , axis.title.x = element_text(face = "bold", size = 18, colour = "black")
      , axis.title.y = element_text(face = "bold", size =18, colour = "black", angle=90)
      , axis.text.x  = element_text(face = "bold", size = 18, colour = "black")
      , axis.text.y  = element_text(face = "bold", size = 18, colour = "black")
      , legend.title = element_text(face = "bold", size = 14, colour = "white")
      , legend.position = c(0, 1)
      , legend.justification = c(0, 0.96)
      , legend.key = element_blank()
      , legend.text = element_text(size = 14, face = "bold", colour = "white")
      , legend.background = element_blank()
      , text = element_text(family = font)
      , plot.margin = unit(c(0, 8, 0, 0), "mm")
   ) +
   ggsave(filename = paste0("FIG2/RNetCDF_Mean_Sea_Surface_Temperature.png"), width = 12, height = 8, dpi = 600)

 

 

[전체]

 

 참고 문헌

[논문]

  • 없음

[보고서]

  • 없음

[URL]

  • 없음

 

 문의사항

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

  • sangho.lee.1990@gmail.com

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

  • saimang0804@gmail.com