logo

줄리아에서 HTTP 프로토콜을 통해 HYCOM 해양 데이터 다운로드 받는 법 📂데이터확보

줄리아에서 HTTP 프로토콜을 통해 HYCOM 해양 데이터 다운로드 받는 법

개요

하이컴에서 데이터를 일일이 손으로 클릭해서 받고 정리하는 것은 쉽지 않은 일이다. 조건을 지정하는 URL을 주어서 받아내는 방법을 소개한다.

코드

HTTP.jl 1

for y = 2019:2024
    url = replace("https://ncss.hycom.org/thredds/ncss/GLBy0.08/expt_93.0/ts3z/$y?var=water_temp
    &north=36.88
    &west=129.52
    &east=130.24
    &south=36.32
    &disableProjSubset=on
    &horizStride=1
    &time_start=$y-01-01T00%3A00%3A00Z
    &time_end=$y-12-31T21%3A00%3A00Z
    &timeStride=1
    &vertCoord=0
    &accept=netcdf4", '\n' => "", " " => "")
    @time response = HTTP.get(url)

    open("data_$y.nc4", "w") do f
        write(f, response.body)
    end
end

가령 위의 코드는 GLBy0.08의 93번 실험에서, 2019년부터 2024년까지의 해수면온도(SST, Sea Surface Temperature)를 위도 36.32~36.88, 경도 129.52~130.24의 범위에서 세 시간 간격의 데이터를 받아내는 코드다.

NCDatasets.jl 2

data_ = []
for y = 2019:2024
    ds  = NCDataset("data_$y.nc4")
    push!(data_, DataFrame([ds["time"][:] reshape(ds["water_temp"][:, :, 1, :], 150, :)'], ["t"; repeat("i" .* string.(1:10), outer = 15) .* repeat("j" .* string.(1:15), inner = 10)]))
    close(ds)
end

다운로드 되는 파일은 NetCDF-4(Network Common Data Form version 4)를 의미하는 *.nc4 파일이다. 고차원의 데이터를 다루기 위해 널리 쓰이지만, 이 가이드에서는 DataFrames.jl로 데이터프레임을 만들고 있다

저장

_data_ = vcat(data_...)
_data_.t = Date.(_data_.t)
_data_ = combine(groupby(_data_, :t), names(_data_, Not(:t)) .=> mean .=> names(_data_, Not(:t)))
CSV.write("data_GLBy0.08_expt_93.0.csv", _data_)
tnsr = reshape(Matrix(_data_[:, 2:end])', 10, 15, :)

@save "data_tnsr.jld2" tnsr
# @load "data_tnsr.jld2"; tnsr

JLD2.jl을 통해서 텐서 그대로를 저장할 수도 있고, 쓰기 간편한 CSV.jl로 저장하는 방법도 있다.

전체 코드

using HTTP, NCDatasets, DataFrames, Dates, CSV, JLD2, StatsBase
for y = 2019:2024
    url = replace("https://ncss.hycom.org/thredds/ncss/GLBy0.08/expt_93.0/ts3z/$y?var=water_temp
    &north=36.88
    &west=129.52
    &east=130.24
    &south=36.32
    &disableProjSubset=on
    &horizStride=1
    &time_start=$y-01-01T00%3A00%3A00Z
    &time_end=$y-12-31T21%3A00%3A00Z
    &timeStride=1
    &vertCoord=0
    &accept=netcdf4", '\n' => "", " " => "")
    @time response = HTTP.get(url)

    open("data_$y.nc4", "w") do f
        write(f, response.body)
    end
end

# ds  = NCDataset("data_$y.nc4")
# # ds.attrib
# # keys(ds)
# # ds["water_temp"][:, :, 1, :]
# CSV.write("lon.csv", DataFrame(i = 1:10, x = round.(ds["lon"][:], digits = 2)))
# CSV.write("lat.csv", DataFrame(j = 1:15, y = round.(ds["lat"][:], digits = 2)))
# close(ds)

data_ = []
for y = 2019:2024
    ds  = NCDataset("data_$y.nc4")
    push!(data_, DataFrame([ds["time"][:] reshape(ds["water_temp"][:, :, 1, :], 150, :)'], ["t"; repeat("i" .* string.(1:10), outer = 15) .* repeat("j" .* string.(1:15), inner = 10)]))
    close(ds)
end
_data_ = vcat(data_...)
_data_.t = Date.(_data_.t)
_data_ = combine(groupby(_data_, :t), names(_data_, Not(:t)) .=> mean .=> names(_data_, Not(:t)))
CSV.write("data_GLBy0.08_expt_93.0.csv", _data_)
tnsr = reshape(Matrix(_data_[:, 2:end])', 10, 15, :)

@save "data_tnsr.jld2" tnsr
# @load "data_tnsr.jld2"; tnsr

니뇨 3.4

다음은 니뇨 3.4Niño 3.4이라고 해서3 위도 5°S~5°N, 경도 170°W~120°W의 해수면온도의 평균값을 받을 수 있는 코드다.

using HTTP, NCDatasets, DataFrames, Dates, CSV, JLD2, StatsBase, ProgressMeter
using Base.Threads

@showprogress @threads for day in Date(2019, 1, 1):Date(2024, 9, 5)
try
    str_day = string(day)
    ("data_$str_day.nc4" |> isfile) && continue
    url = replace("https://ncss.hycom.org/thredds/ncss/GLBy0.08/expt_93.0/ts3z/$(Year(day).value)?var=water_temp
    &north=5
    &west=120
    &east=170
    &south=-5
    &disableProjSubset=on
    &horizStride=1
    &time_start=$(day)T00%3A00%3A00Z
    &time_end=$(day)T21%3A00%3A00Z
    &timeStride=1
    &vertCoord=0
    &accept=netcdf4", '\n' => "", " " => "")
    # @time response = HTTP.get(url)
    response = HTTP.get(url)

    open("data_$str_day.nc4", "w") do f
        write(f, response.body)
    end
catch e
    @warn e
end
end

nc4_ = filter(endswith(".nc4"), readdir())
@time data_ = CSV.read("data_form.csv", DataFrame)
@showprogress for k in eachindex(nc4_)
    NCDataset(nc4_[k]) do ds
        df = DataFrame([ds["time"][:] reshape(ds["water_temp"][:, :, 1, :], 251*626, :)'], ["t"; repeat("i" .* string.(1:626), outer = 251) .* repeat("j" .* string.(1:251), inner = 626)])
        df.t = Date.(df.t)
        data_[k, :] = combine(groupby(df, :t), names(df, Not(:t)) .=> mean .=> names(df, Not(:t)))[1, :]
    end
end

CSV.write("data_GLBy0.08_expt_93.0.csv", data_)
tnsr = reshape(Matrix(data_[:, 2:end])', 626, 251, :)

@save "data_tnsr.jld2" tnsr