Main Content

NetCDF 파일과 OPeNDAP 데이터 가져오기

여러 가지 방법으로 netCDF 파일에서 데이터를 읽을 수 있습니다. 프로그래밍 방식으로 MATLAB®의 하이 레벨 netCDF 함수 또는 netCDF 라이브러리 네임스페이스의 로우 레벨 함수를 사용할 수 있습니다. 대화형 방식으로는 데이터 가져오기 라이브 편집기 작업을 사용하거나 (MATLAB Online™에서) 가져오기 툴 앱을 사용할 수 있습니다.

MATLAB NetCDF 지원 기능

NetCDF(Network Common Data Form)는 배열 지향적인 과학 데이터를 생성, 액세스 및 공유하도록 지원하는 소프트웨어 라이브러리 및 시스템 독립적인 데이터 형식의 집합입니다. NetCDF는 용이한 데이터의 공유를 위해 표준화된 데이터 저장 방식을 요하는 여러 공학 및 과학 분야에서 사용됩니다.

MATLAB 하이 레벨 함수는 NetCDF 파일이나 OPeNDAP NetCDF 데이터 소스에서 데이터를 가져오는 과정을 단순화합니다. MATLAB 로우 레벨 함수를 사용하면 NetCDF C 라이브러리의 루틴에 액세스하여 가져오기 프로세스를 더 세부적으로 제어할 수 있습니다. 로우 레벨 함수를 효과적으로 사용하려면 NetCDF C 인터페이스를 잘 알고 있어야 합니다. NetCDF 문서는 Unidata 웹사이트에서 참조할 수 있습니다.

참고

별도의 호환되지 않는 형식을 가지고 있는 CDF(Common Data Format) 파일 가져오기에 대한 정보는 Import CDF Files Using Low-Level Functions 항목을 참조하십시오.

OPeNDAP 서버에 연결할 때 보안 관련 고려 사항

신뢰할 수 있는 OPeNDAP 서버에만 연결할 것을 강력히 권장합니다. R2020b 이상 버전에서 MATLAB NetCDF 인터페이스는 서버 인증서 및 호스트 이름 유효성 검사를 수행하여 기본적으로 신뢰할 수 있는 데이터 액세스 프로토콜(DAP) 끝점에만 연결합니다. 이전에는 OPeNDAP 서버에 액세스할 때 서버 인증서 및 호스트 이름 유효성 검사가 모두 기본적으로 비활성화되어 있었습니다.

서버 인증서 및 호스트 이름 유효성 검사를 비활성화하려면 현재 디렉터리의 .dodsrc 파일에 다음 라인을 추가하십시오.

[mylocaltestserver.lab] HTTP.SSL.VALIDATE=0

이렇게 하면 MATLAB NetCDF 인터페이스가 서버 인증서나 호스트 이름에 대한 유효성 검사를 수행하지 않고 URI mylocaltestserver.lab에 지정된 이름이 있는 OPeNDAP 서버에 연결합니다. 이러한 변경 내용은 향후 MATLAB 세션에서도 유지됩니다.

하이 레벨 함수를 사용하여 NetCDF 파일에서 읽어오기

이 예제에서는 하이 레벨 함수를 사용하여 NetCDF 파일 내용을 표시하고 읽어오는 방법을 보여줍니다.

샘플 NetCDF 파일 example.nc의 내용을 표시합니다.

ncdisp('example.nc')
Source:
           \\matlabroot\toolbox\matlab\demos\example.nc
Format:
           netcdf4
Global Attributes:
           creation_date = '29-Mar-2010'
Dimensions:
           x = 50
           y = 50
           z = 5
Variables:
    avagadros_number
           Size:       1x1
           Dimensions: 
           Datatype:   double
           Attributes:
                       description = 'this variable has no dimensions'
    temperature     
           Size:       50x1
           Dimensions: x
           Datatype:   int16
           Attributes:
                       scale_factor = 1.8
                       add_offset   = 32
                       units        = 'degrees_fahrenheit'
    peaks           
           Size:       50x50
           Dimensions: x,y
           Datatype:   int16
           Attributes:
                       description = 'z = peaks(50);'
Groups:
    /grid1/
        Attributes:
                   description = 'This is a group attribute.'
        Dimensions:
                   x    = 360
                   y    = 180
                   time = 0     (UNLIMITED)
        Variables:
            temp
                   Size:       []
                   Dimensions: x,y,time
                   Datatype:   int16
    
    /grid2/
        Attributes:
                   description = 'This is another group attribute.'
        Dimensions:
                   x    = 360
                   y    = 180
                   time = 0     (UNLIMITED)
        Variables:
            temp
                   Size:       []
                   Dimensions: x,y,time
                   Datatype:   int16

ncdisp는 파일의 모든 그룹과 차원, 변수 정의를 표시합니다. 무제한 차원은 레이블 UNLIMITED로 식별됩니다.

peaks 변수에서 데이터를 읽어옵니다.

peaksData  = ncread('example.nc','peaks');

peaksData 출력값에 대한 정보를 표시합니다.

whos peaksData
  Name            Size            Bytes  Class    Attributes

  peaksData      50x50             5000  int16  

변수와 연관된 description 특성(Attribute)을 읽어옵니다.

peaksDesc  = ncreadatt('example.nc','peaks','description')
peaksDesc =

z = peaks(50);

변수 데이터의 3차원 곡면 플롯을 만듭니다. description 특성의 값을 Figure의 제목으로 사용합니다.

surf(double(peaksData))
title(peaksDesc);

/grid1/ 그룹과 연관된 description 특성을 읽어옵니다. 그룹 이름을 ncreadatt 함수에 대한 두 번째 입력값으로 지정합니다.

g = ncreadatt('example.nc','/grid1/','description')
g =

This is a group attribute.

전역 특성 creation_date를 읽어옵니다. 전역 특성에서 ncreadatt에 대한 두 번째 입력 인수를 '/'로 지정합니다.

creation_date = ncreadatt('example.nc','/','creation_date')
creation_date =

29-Mar-2010

NetCDF 파일에서 무제한 차원 모두 찾기

이 예제에서는 하이 레벨 함수를 사용하여 NetCDF 파일에서 그룹의 무제한 차원을 모두 찾는 방법을 보여줍니다.

ncinfo 함수를 사용하여 샘플 파일 example.nc/grid2/ 그룹에 대한 정보를 가져옵니다.

ginfo = ncinfo('example.nc','/grid2/')
ginfo = 

      Filename: '\\matlabroot\toolbox\matlab\demos\example.nc'
          Name: 'grid2'
    Dimensions: [1x3 struct]
     Variables: [1x1 struct]
    Attributes: [1x1 struct]
        Groups: []
        Format: 'netcdf4'

ncinfo는 그룹에 대한 정보가 포함된 구조체형 배열을 반환합니다.

이 그룹의 무제한 차원을 나타내는 부울 값으로 구성된 벡터를 가져옵니다.

unlimDims = [ginfo.Dimensions.Unlimited]
unlimDims =

     0     0     1

unlimDims 벡터를 사용하여 무제한 차원을 표시합니다.

disp(ginfo.Dimensions(unlimDims))
         Name: 'time'
       Length: 0
    Unlimited: 1

로우 레벨 함수를 사용하여 NetCDF 파일에서 읽어오기

이 예제에서는 netcdf 네임스페이스의 MATLAB 로우 레벨 함수를 사용하여 netCDF 파일의 차원, 변수, 특성(attribute)에 대한 정보를 가져오는 방법을 보여줍니다. 이러한 함수를 효과적으로 사용하려면 netCDF C 인터페이스를 잘 알고 있어야 합니다.

NetCDF 파일 열기

netcdf.open 함수를 사용하여 읽기 전용 액세스로 샘플 netCDF 파일 example.nc를 엽니다.

ncid = netcdf.open("example.nc","NC_NOWRITE");

netcdf.open은 파일 ID를 반환합니다.

NetCDF 파일에 대한 정보 가져오기

netcdf.inq 함수를 사용하여 파일의 내용에 대한 정보를 가져옵니다. 이 함수는 netCDF 라이브러리 C API의 nc_inq 함수에 대응합니다.

[ndims,nvars,natts,unlimdimID] = netcdf.inq(ncid)
ndims = 3
nvars = 3
natts = 1
unlimdimID = -1

netcdf.inq는 파일의 차원, 변수, 전역 특성 개수를 반환하고 파일의 무제한 차원 ID를 반환합니다. 무제한 차원은 확장될 수 있습니다.

netcdf.inqAttName 함수를 사용하여 파일의 전역 특성 이름을 가져옵니다. 이 함수는 netCDF 라이브러리 C API의 nc_inq_attname 함수에 대응합니다. 특성 이름을 가져오려면 해당 특성과 연관된 변수 ID와 특성 번호를 지정해야 합니다. 특정 변수와 연관되지 않은 전역 특성에 액세스하려면 상수 "NC_GLOBAL"을 변수 ID로 사용하십시오.

global_att_name = netcdf.inqAttName(ncid,...
    netcdf.getConstant("NC_GLOBAL"),0)
global_att_name = 
'creation_date'

netcdf.inqAtt 함수를 사용하여 특성의 데이터형과 길이에 대한 정보를 가져옵니다. 이 함수는 netCDF 라이브러리 C API의 nc_inq_att 함수에 대응합니다. 다시 netcdf.getConstant("NC_GLOBAL")을 사용하여 변수 ID를 지정합니다.

[xtype,attlen] = netcdf.inqAtt(ncid,...
    netcdf.getConstant("NC_GLOBAL"),global_att_name)
xtype = 2
attlen = 11

netcdf.getAtt 함수를 사용하여 특성 값을 가져옵니다.

global_att_value = netcdf.getAtt(ncid,...
    netcdf.getConstant("NC_GLOBAL"),global_att_name)
global_att_value = 
'29-Mar-2010'

netcdf.inqDim 함수를 사용하여 파일의 첫 번째 차원에 대한 정보를 가져옵니다. 이 함수는 netCDF 라이브러리 C API의 nc_inq_dim 함수에 대응합니다. netcdf.inqDim에 대한 두 번째 입력값은 차원을 식별하는 차원 ID로, 0부터 시작하는 인덱스입니다. 첫 번째 차원의 인덱스 값은 0입니다.

[dimname,dimlen] = netcdf.inqDim(ncid,0)
dimname = 
'x'
dimlen = 50

netcdf.inqDim은 차원의 이름과 길이를 반환합니다.

netcdf.inqVar 함수를 사용하여 파일의 첫 번째 변수에 대한 정보를 가져옵니다. 이 함수는 netCDF 라이브러리 C API의 nc_inq_var 함수에 대응합니다. netcdf.inqVar에 대한 두 번째 입력값은 변수를 식별하는 변수 ID로, 0부터 시작하는 인덱스입니다. 첫 번째 변수의 인덱스 값은 0입니다.

[varname,vartype,dimids,natts] = netcdf.inqVar(ncid,0)
varname = 
'avagadros_number'
vartype = 6
dimids =

     []
natts = 1

netcdf.inqVar은 변수와 연관된 특성의 이름, 데이터형, 차원 ID 및 개수를 반환합니다. vartype에서 반환되는 데이터형 정보는 NC_INT, NC_BYTE 같은 netCDF 데이터형 상수의 숫자형 값입니다. 이러한 상수에 대한 정보는 netCDF 문서를 참조하십시오.

NetCDF 파일에서 데이터 읽어오기

netcdf.getVar 함수를 사용하여 예제 파일에서 변수 avagadros_number와 연관된 데이터를 읽어옵니다. netcdf.getVar에 대한 두 번째 입력값은 변수를 식별하는 변수 ID로, 0부터 시작하는 인덱스입니다. avagadros_number 변수의 인덱스 값은 0입니다.

A_number = netcdf.getVar(ncid,0)
A_number = 6.0221e+23

A_number의 데이터형을 확인합니다.

whos A_number
  Name          Size            Bytes  Class     Attributes

  A_number      1x1                 8  double              

netcdf 네임스페이스의 함수는 해당 NetCDF 데이터형에 가장 잘 맞는 MATLAB 클래스를 자동으로 선택하지만, netcdf.getVar에 대한 선택적 인수를 사용하여 반환 데이터의 클래스를 지정할 수도 있습니다.

avagadros_number와 연관된 데이터를 읽어온 후 해당 데이터를 single형 클래스로 반환합니다.

A_number = netcdf.getVar(ncid,0,"single")
A_number = single
    6.0221e+23
whos A_number
  Name          Size            Bytes  Class     Attributes

  A_number      1x1                 4  single              

NetCDF 파일 닫기

netCDF 파일 example.nc를 닫습니다.

netcdf.close(ncid)

대화형 방식으로 NetCDF 파일에서 데이터 읽어오기

이 예제에서는 데이터 가져오기 작업을 사용하여 netCDF 파일의 구조를 탐색하고 파일에서 데이터를 가져온 후 데이터를 분석하고 시각화하는 방법을 보여줍니다.

데이터셋 다운로드하기

미국 NOAA PSL(National Oceanic and Atmospheric Administration Physical Sciences Laboratory)은 NSIDC(National Snow and Ice Data Center)가 수집한 보간된 북반구 적설량 데이터의 데이터셋을 호스팅합니다. 이 데이터셋을 현재 폴더에 다운로드합니다.

filename = "snowcover.mon.mean.nc";
url = "https://downloads.psl.noaa.gov/Datasets/snowcover/snowcover.mon.mean.nc";
fullLocalPath = websave(filename,url);

데이터 탐색 및 가져오기

라이브 편집기 탭에서 작업 > 데이터 가져오기를 선택하여 라이브 편집기에서 데이터 가져오기 작업을 엽니다. netCDF 데이터셋의 파일 이름인 snowcover.mon.mean.nc파일 필드에 입력합니다. 이 작업을 사용하여 변수와 그 특성을 포함해 데이터의 구조를 탐색할 수 있습니다.

  • 전역 특성을 통해 참조를 비롯하여 파일에 포함된 데이터의 일반적인 의미를 파악할 수 있습니다.

  • 데이터셋에는 두 개의 공간 차원(latlon)과 한 개의 시간 차원(time), 즉 3개의 차원이 포함되어 있습니다.

  • lat 변수는 크기가 90이고 값이 'degrees_north'units라는 특성을 갖습니다. 이 변수는 측정된 점의 위도를 나타내며, 위도는 적도로부터 북쪽 방향으로 도 단위로 측정됩니다.

  • lon 변수는 크기가 360이고 값이 'degrees_east'units라는 특성을 갖습니다. 이 변수는 측정된 점의 경도를 나타내며, 경도는 본초자오선으로부터 동쪽 방향으로 도 단위로 측정됩니다.

  • time 변수는 크기가 297이고 차원은 무제한이며 값이 'hours since 1800-01-01 00:00:0.0'units라는 특성을 갖습니다. 이 변수는 측정된 시간을 나타냅니다.

  • snowcover 변수는 크기가 360×90×297이고 세 번째 차원은 무제한이며 값이 '%'units라는 특성과 값이 'Monthly Means Snowcover Extent'long_name이라는 특성을 갖습니다. snowcover 변수는 lat, lon, time 변수를 통합합니다. 이는 북반구의 특정 점에 대한 특정 달의 월 평균 적설량을 나타내며, 눈으로 덮인 지면의 비율로 측정됩니다.

lat, lon, time, snowcover 변수에서 데이터를 선택하고 가져옵니다.

Import Data Live Editor task with the snowcover.mon.mean.nc file imported, showing all variables selected for import

이 작업이 생성하는 코드를 확인하려면 작업 파라미터 영역 맨 아래에 있는 코드 표시를 클릭하여 작업 표시 영역을 확장합니다.

% Create a structure to store imported netCDF data
snowcover_mon_mean = struct();

filename = "snowcover.mon.mean.nc";
snowcover_mon_mean.Variables(1).Name = "lat";
snowcover_mon_mean.Variables(2).Name = "lon";
snowcover_mon_mean.Variables(3).Name = "time";
snowcover_mon_mean.Variables(4).Name = "snowcover";

snowcover_mon_mean.Variables(1).Value = ncread(filename, "/lat");

snowcover_mon_mean.Variables(2).Value = ncread(filename, "/lon");

snowcover_mon_mean.Variables(3).Value = ncread(filename, "/time");

snowcover_mon_mean.Variables(4).Value = ncread(filename, "/snowcover");

clear filename

데이터를 구성하고 준비하기

데이터셋의 변수 각각에 대해 지역 변수를 만듭니다.

lats = snowcover_mon_mean.Variables(1).Value;
lons = snowcover_mon_mean.Variables(2).Value;
times = snowcover_mon_mean.Variables(3).Value;
snows = snowcover_mon_mean.Variables(4).Value;

데이터를 플로팅할 때 latslons가 적절하게 표시되도록 준비합니다. 각 축에 10개의 레이블을 표시하는 표시 스케일을 선택합니다.

numLabels = 10;

latDisps = strings(length(lats),1);
latsLabelInterval = length(lats)/numLabels;
latLabelInds = latsLabelInterval:latsLabelInterval:length(lats);
latDisps(latLabelInds) = lats(latLabelInds);

lonDisps = strings(length(lons),1);
lonsLabelInterval = length(lons)/numLabels;
lonLabelInds = lonsLabelInterval:lonsLabelInterval:length(lons);
lonDisps(lonLabelInds) = lons(lonLabelInds);

time 변수의 units 특성은 time이 1800년 초부터 시간 단위로 측정되었다는 것을 나타냅니다. 또한 snowcover 변수의 long_name 특성은 값이 월 평균이라는 것을 나타냅니다. 이 정보를 사용하여 times 벡터를 대응하는 datetime 값으로 변환하고, 월과 연도는 포함하지만 일은 표시하지 않도록 times의 표시 형식을 설정합니다.

sampTimes = datetime("1800-01-01 00:00:00") + hours(times);
sampTimes.Format = "MMM-yyyy";
sampTimeDisps = string(sampTimes);

snows의 첫 번째 차원은 위도를 나타내고 두 번째 차원은 경도를 나타냅니다. 이 데이터의 히트맵을 만들려면 첫 번째 차원은 열(경도), 두 번째 차원은 행(위도)에 대응되어야 합니다. snows의 이 두 차원을 치환합니다.

snows = permute(snows,[2 1 3]);

데이터 플로팅하기

데이터의 첫 달에 대한 히트맵을 만듭니다.

h = heatmap(lons,lats,snows(:,:,1));
h.XLabel = "Longitude (°E)";
h.YLabel = "Latitude (°N)";
h.XDisplayLabels = lonDisps;
h.YDisplayLabels = latDisps;
h.Colormap = winter;
h.GridVisible = "off";

사용 가능한 모든 시간에 대한 데이터를 루프로 순환하여 히트맵을 애니메이션합니다.

for i = 1:numel(sampTimeDisps)
    h.ColorData = snows(:,:,i);
    h.Title = "Percent Snow Cover vs. Location (" + sampTimeDisps(i) + ")";
    pause(0.1)
end

Figure contains an object of type heatmap. The chart of type heatmap has title Percent Snow Cover vs. Location (Sep-1995).

적설량이 가장 많은 시간 찾기

총 적설량을 시간의 함수로 계산하고 플로팅합니다.

cumSnowsbyTime = squeeze(sum(snows,[1 2])) / (length(lats)*length(lons));

plot(sampTimes,cumSnowsbyTime)
xlabel("Date")
ylabel("Total Snow Cover (%)")
title("Total Snow Cover vs. Date")

Figure contains an axes object. The axes object with title Total Snow Cover vs. Date, xlabel Date, ylabel Total Snow Cover (%) contains an object of type line.

적설량이 가장 많은 시간을 찾아 플로팅합니다.

[maxSnowsbyTime,maxSnowsbyTimeInd] = max(cumSnowsbyTime);

h = heatmap(lons,lats,snows(:,:,maxSnowsbyTimeInd));
h.XLabel = "Longitude (°E)";
h.YLabel = "Latitude (°N)";
h.Title = "Percent Snow Cover vs. Location (" + sampTimeDisps(maxSnowsbyTimeInd) + ")";
h.XDisplayLabels = lonDisps;
h.YDisplayLabels = latDisps;
h.Colormap = winter;
h.GridVisible = "off";

Figure contains an object of type heatmap. The chart of type heatmap has title Percent Snow Cover vs. Location (Feb-1978).

적설량이 가장 많았던 달은 1978년 2월입니다.

적설량이 가장 많은 위치 찾기

평균 적설량을 위치의 함수로 계산하고 플로팅합니다.

cumSnowsbyLoc = sum(snows,3) / length(times);

h = heatmap(lons,lats,cumSnowsbyLoc);
h.XLabel = "Longitude (°E)";
h.YLabel = "Latitude (°N)";
h.Title = "Average Percent Snow Cover vs. Location";
h.XDisplayLabels = lonDisps;
h.YDisplayLabels = latDisps;
h.Colormap = winter;
h.GridVisible = "off";

Figure contains an object of type heatmap. The chart of type heatmap has title Average Percent Snow Cover vs. Location.

적설량이 가장 많은 위치를 찾아 플로팅합니다.

maxSnowsbyLocVal = max(cumSnowsbyLoc,[],"all");
maxSnowsbyLoc = maxSnowsbyLocVal*(cumSnowsbyLoc == maxSnowsbyLocVal);

h = heatmap(lons,lats,maxSnowsbyLoc);
h.XLabel = "Longitude (°E)";
h.YLabel = "Latitude (°N)";
h.Title = "Locations of Maximum Snow Cover";
h.XDisplayLabels = lonDisps;
h.YDisplayLabels = latDisps;
h.Colormap = winter;
h.GridVisible = "off";

Figure contains an object of type heatmap. The chart of type heatmap has title Locations of Maximum Snow Cover.

적설량이 가장 많은 위치에는 그린란드 대부분의 지역, 그리고 스발바르 제도와 프란츠 요제프 제도의 일부가 포함됩니다.

출처

미국 콜로라도주 볼더에 있는 NOAA PSL이 해당 웹사이트(https://psl.noaa.gov)를 통해 제공한 NH Ease-Grid Snow Cover 데이터.

참고 항목

함수

라이브 편집기 작업

관련 항목

외부 웹사이트