๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Data Engineering ์žฌ๋ฐŒ๋”ฐ/Ocean Meteorological Data

ํ•ด์–‘๊ธฐ์ƒ์„ ์œ„ํ•œ NetCDF ๋‹ค๋ฃจ๊ธฐ

by ์ž„๋ฆฌ๋‘ฅ์ ˆ 2024. 12. 3.
๋ฐ˜์‘ํ˜•
๋”๋ณด๊ธฐ

๊ธฐ๋ณธ์ ์ธ python ๊ฐœ๋…์„ ์•Œ๊ณ  ์žˆ๋‹ค๋Š” ์ „์ œ ํ•˜,
๊ฐ„๋‹จํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋“ค ์œ„์ฃผ๋กœ ๊ธฐ์–ตํ•˜๊ธฐ ์œ„ํ•ด ์ตœ์†Œํ•œ์˜ ์ฝ”๋“œ๋กœ ์ž‘์„ฑํ•˜๋Š” ๊ธ€์ž„์„ ์ฐธ๊ณ  ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.


NetCDF (Network Common Data Form) ๋ฐ์ดํ„ฐ๊ฐ€ ๋ญ์—์šฉ?

ํ•ด์–‘๊ณผ ๋Œ€๊ธฐ ๊ณผํ•™์—์„œ ๋„๋ฆฌ ์“ฐ์ธ๋‹ค.

  • ๋‹ค์ฐจ์› ๋ฐ์ดํ„ฐ
  • ์‹œ๊ฐ„๊ณผ ๊ณต๊ฐ„์— ๋”ฐ๋ฅธ ๋Œ€๊ธฐ, ํ•ด์–‘, ๋ฐ์ดํ„ฐ๋“ค

๋ฐฐ์—ด ๋˜๋Š” ํ–‰๋ ฌ๋กœ ๊ตฌ์„ฑ๋œ ๊ณผํ•™์ •๋ณด ํ˜•์‹

ํ•ด์–‘ ์ˆ˜์น˜ ๋ชจ๋ธ ๊ฒฐ๊ณผ๋Š” ๊ณต๊ฐ„์ •๋ณด(3์ฐจ์›)์˜ ์‹œ๊ฐ„์— ๋”ฐ๋ฅธ ๊ฐ’์ด ์ž…๋ ฅ, ๊ฐ’ ๋˜ํ•œ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ณ€์ˆ˜๋ฅผ ํฌํ•จ. (x,y์— ๋”ฐ๋ฅธ h๊ฐ’. ๋ฉด๋ฐ์ดํ„ฐ)

๋˜ํ•œ ๊ณต๊ฐ„๊ณผ ์‹œ๊ฐ„์— ๋”ฐ๋ฅธ ํŒŒ๊ณ , ํŒŒํ–ฅ, ํŒŒ์ฃผ๊ธฐ ๋“ฑ ๋ถ€๊ฐ€ ์ •๋ณด๋ฅผ ํฌํ•จ.

๊ด€์ธก์ •๋ณด ์ผ ๋•Œ๋Š” ๊ด€์ธก์†Œ๋ช…, ํ‘œ์ค€์‹œ, ์ˆ˜์ธต, ์žฅ๋น„๋ช… ๋“ฑ๊ณผ ๋ชจ๋ธ์ผ ๋•Œ๋Š” ์‹œ๊ฐ„, ๊ณต๊ฐ„ ํ‘œ์ค€, ๊ฐ’ ๋‹จ์œ„, fill_value ๋“ฑ๋“ฑ ํฌํ•จ๋˜์–ด์•ผ ํ•  ์ •๋ณด๋“ค์ด ๋งŽ์Œ.

 

์˜ˆ๋กœ ์‹œ๊ฐ„๊ณผ ๊ณต๊ฐ„ (x, y, t) + ๊ทธ ๊ฐ’์— ๋”ฐ๋ฅธ z ๊นŒ์ง€๋ฉด 4์ฐจ์› ๋ฐ์ดํ„ฐ๊ฐ€ ๋จ.

์ด๋Ÿฐ ์‹œ๊ฐ„์— ๋”ฐ๋ฅธ ๋‹ค์ˆ˜์˜ ์  (๊ณต๊ฐ„, ๋ช…)์˜ ๊ฐ’์„ ๊ฐ€์ง€๊ธฐ์— NetCDF ํ˜•์‹์„ ํ™œ์šฉํ•˜๊ณ  ์žˆ์Œ.

(๋Œ€์ถฉ ๊ณต๊ฐ„, ์‹œ๊ฐ„, ๋ชจ๋“  ์ •๋ณด ๋‹ค์ฐจ์› ๋ฐ์ดํ„ฐ๋ผ๋Š” ๋œป)

NetCDF file structure

  • Dimension (์ฐจ์› : ์œ„๋„, ๊ฒฝ๋„, ์‹œ๊ฐ„์˜ ํฌ๊ธฐ, ๊ฐฏ์ˆ˜ ๋“ฑ)
  • Variables (์‹ค์ œ ๋ณ€์ˆ˜๋“ค์˜ ๊ฐ’)
  • attributes (ํŒŒ์ผ์— ๋Œ€ํ•œ ๋ฉ”ํƒ€์ •๋ณด) ๋กœ ๋‚˜๋ˆ„์–ด์ ธ ์žˆ์Œ.

ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” → linux - ncdump, matlap - ncinfo

 

NetCDF Control

pip install netCDF4 seawater GSW xarray

conda install -c conda-forge basemap-data-hires

pip install netCDF4 seawater GSW xarray
conda install -c conda-forge basemap-data-hires

 

import numpy as np
import xarray as xr
import os
import matplotlib.pyplot as plt  # Corrected import for pyplot

# Set absolute path
work_path = '/DataProcessing_TRC/'
input_file = 'data/CTD_station_P1_NLEG01-1_-_Nansen_Legacy_Cruise_-_2021_Joint_Cruise_2-1.nc'
out_file = 'data/ctd_data_set.csv'

# Use path join to create full file paths
f_name = os.path.join(work_path, input_file)
f_out_name = os.path.join(work_path, out_file)

# Load the dataset
ds = xr.open_dataset(f_name)

# Extract temperature values
temperature = ds['TEMP'].values

# Convert selected variables to a DataFrame
df = ds[['PRES', 'TEMP', 'PSAL']].to_dataframe()

# Save the DataFrame to a CSV file
df.to_csv(f_out_name)

# Plotting
fig1 = plt.figure()

# Temperature plot
ax1 = fig1.add_subplot(121)
ax1.plot(ds['TEMP'], ds['PRES'], 'bo-', markersize=2, linewidth=0.5)
ax1.set_ylim(ax1.get_ylim()[::-1])  # Reverse the y-axis
ax1.set_xlabel('Temperature (C)')
ax1.set_ylabel('Depth (m)')
plt.grid(True)
ax1.xaxis.set_label_position('top')  # Move the label to the top
ax1.xaxis.set_ticks_position('top')   # Move the ticks to the top

# Salinity plot
ax2 = fig1.add_subplot(122)
ax2.plot(ds['PSAL'], ds['PRES'], 'ro-', markersize=2, linewidth=0.5)
ax2.xaxis.set_label_position('top')
ax2.xaxis.set_ticks_position('top')
ax2.set_ylim(ax2.get_ylim()[::-1])  # Reverse the y-axis
plt.grid(True)
ax2.set_xlabel('Salinity (PSU)')

# Show the plots
plt.show()

 

file ์ €์žฅ๋„ ์ž˜ ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

NetCDF ๋™ํ•ด ํ‰๊ท ํ•ด๋ฅ˜๋„ ๋‹ค๋ฃจ๊ธฐ

format ํ™•์ธํ•˜๊ธฐ 

# Set absolute path
work_path = '/mnt/c/Users/MML/sh/DataProcessing_TRC/'
input_file = 'data/KHOA_SCU_L4_Z004_Y01_U2023_EastSea.nc'

f_name = work_path + input_file
f_data = xr.open_dataset(f_name)

print(f_data)

u_comp = f_data.data_vars['u']
print(u_comp)

 

์–ด๋–ค ํฌ๋งท์ธ๊ฐ€ ์ „๋ฐ˜์ ์œผ๋กœ ๋ณด๊ณ ...
data variable๋“ค์ด ๋ญ๊ฐ€ ์žˆ๋‚˜ ๋ณด๊ธฐ๋„ ํ•˜๊ณ ..

Realizing The East Sea NetCDF

''' File Processing '''
f_name = work_path + input_file
ds = xr.open_dataset(f_name)                    # Open the NetCDF dataset

# f_data = xr.open_dataset(f_name)
# print(f_data)
# u_comp = f_data.data_vars['u']
# print(u_comp)

lat = ds["lat"].values                          # ์œ„๋„.values ๋กœ numpy ๋ณ€ํ™˜
lon = ds["lon"].values                          # ๊ฒฝ๋„.values ๋กœ numpy ๋ณ€ํ™˜

# Transpose the u and v velocity components
u_velocity = np.transpose(ds["u"].values)       # East-west velocity
v_velocity = np.transpose(ds["v"].values)       # North-south velocity
  • np.transpose()
    ๋ณดํ†ต ํ•ด์–‘ ๋ฐ์ดํ„ฐ๋Š” ์‹œ๊ฐ„, ๊นŠ์ด, ์œ„๋„, ๊ฒฝ๋„ ๋“ฑ์˜ ์ฐจ์›์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด ์†๋„ (u, v)์˜ ๋ฐฐ์—ด์ด ์‹œ๊ฐ„๊ณผ ๊นŠ์ด ์ฐจ์›์„ ๋จผ์ € ํฌํ•จํ•œ๋‹ค๋ฉด, ์ด๋ฅผ ์ „์น˜ํ•˜์—ฌ ์›ํ•˜๋Š” ์ฐจ์›์„ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•จ!
    (๋Œ€์ถฉ ์›ํ•˜๋Š” ๊ฑฐ ๊ณจ๋ผ์“ฐ๋ ค๊ณ  . ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋ ค๊ณ  ๋’ค์ง‘์—ˆ๋‹ค๋Š” ๋œป)
''' Convert to DataFrame for calculations '''
# Generate a grid for longitude and latitude
lon_grid, lat_grid = np.meshgrid(lon, lat)
# Create a DataFrame with longitude, latitude, and velocity components
data_frame = pd.DataFrame({
    "lon": lon_grid.ravel(),
    "lat": lat_grid.ravel(),
    "u_velocity": u_velocity.ravel(),           # Flatten to 1D
    "v_velocity": v_velocity.ravel()            # Flatten to 1D
})
  • .ravel()
    ์›๋ณธ์ด ์•„๋‹Œ view๋ฅผ ๋ฐ˜ํ™˜.
    ๋‹ค์ฐจ์› -> 1์ฐจ์›์œผ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ Pandas DataFrame์„ ์ƒ์„ฑํ•˜๊ณ  ์žˆ์Œ.
    ํ–‰ row ๋กœ ๋‚˜์—ด๋˜์–ด ์‰ฝ๊ฒŒ ์ €์žฅํ•˜๊ณ  ์ด์šฉ.
''' Map plotting '''
fig, ax = plt.subplots(figsize=(10, 8))
m = Basemap(llcrnrlon=126,                      # Lower-left corner longitude
            llcrnrlat=33,                       # Lower-left corner latitude
            urcrnrlon=142,                      # Upper-right corner longitude
            urcrnrlat=48,                       # Upper-right corner latitude
            lon_0=134,                          # Central longitude
            lat_0=40,                           # Central latitude
            projection="merc",                  # Mercator projection
            resolution="h",                     # High resolution
            ax=ax)                              # Specify the axes object

# Fill continents and draw coastlines
m.fillcontinents(color="#D3D3D3", lake_color="lightblue")
m.drawcoastlines()
  • Figure ์ „์ฒด๊ทธ๋ฆผ, Axes ํ”Œ๋กฏ์˜ ์ถ• = plt.subplots(figsize=(๊ฐ€๋กœ,์„ธ๋กœ))
  • Basemap ( ์™ผ์•„๋ž˜๊ฒฝ๋„, ์™ผ์•„๋ž˜์œ„๋„, ์˜ค๋ฅธ์œ„๊ฒฝ๋„, ์˜ค๋ฅธ์œ„์œ„๋„, ์ค‘์‹ฌ๊ฒฝ๋„, ์ค‘์‹ฌ์œ„๋„, ํˆฌ์˜๋ฒ•, ํ•ด์ƒ๋„, ์ถ• )
  • .fillcontinents()
  • .drawcoastlines()
''' Calculate velocity of sea '''
# np.hypot (a, b) Calculate between a and b. 
# Calculate the horizontal speed using u and v components.
speeds = np.hypot(data_frame.u_velocity, data_frame.v_velocity)
 
# Plot arrows to represent velocity
X, Y = m(data_frame.lon, data_frame.lat)
quiver = m.quiver(X, Y, data_frame.u_velocity, data_frame.v_velocity, speeds, cmap="jet")
  • np.hypot (a, b) :
    a, b ๋‘ ์  ์‚ฌ์ด ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ
    ํ•ด์ˆ˜์˜ ๋™์„œ u ๋ฐฉํ–ฅ, ๋‚จ๋ถ v ๋ฐฉํ–ฅ ์†๋„๋ฅผ ์ด์šฉํ•ด ์ˆ˜ํ‰ ์†๋„๋ฅผ ๊ตฌํ•จ.
  • m.quiver ( ์‹œ์ž‘์ x, ์‹œ์ž‘์ y,
    ๋™์„œ๋ฐฉํ–ฅ์†๋„(x์ถ•์†๋„)u,
    ๋‚จ๋ถ๋ฐฉํ–ฅ์†๋„(y์ถ•์†๋„)v,
    speed (๋ฒกํ„ฐ์˜ ํฌ๊ธฐ๋‚˜ ๊ฐ•๋„),
    cmap (์ปฌ๋Ÿฌ๋งต ์ง€์ •์ธ์ž)
''' Add remaining elements '''
# Add color bar
cbar = plt.colorbar(quiver, 
                    ax=ax,
                    orientation='horizontal',
                    shrink=0.4, 
                    aspect=12, 
                    pad=0.04)

# Draw meridians and parallels
m.drawmeridians(np.arange(126, 142, 3), labels=[0, 0, 0, 1])  # Meridians with label on top
m.drawparallels(np.arange(33, 49, 3), labels=[1, 0, 0, 0])    # Parallels with label on left

# Set title and show the plot
plt.title("Ocean Current Vector Map using Quiver", fontsize=14)
plt.show()
  • plt.colorbar ( ๊ฐ์ฒด, ์ถ•, orientation ๋ฐฉํ–ฅ(horizontal / vertical),
    shrink(๋ง‰๋Œ€ ํฌ๊ธฐ), aspect(์ข…ํšก๋น„. 10-20), pad(๋ง‰๋Œ€์™€ ์ถ• ๊ฐ„๊ฒฉ))
  • ๊ฒฝ์„  .drawmeridians(๋ฒ”์œ„, ๋ ˆ์ด๋ธ”[์ƒ๋‹จ, ์šฐ์ธก, ํ•˜๋‹จ, ์ขŒ์ธก])
    ์œ„์„  .drawparallels(๋ฒ”์œ„,๋ ˆ์ด๋ธ”[์ƒ๋‹จ, ์šฐ์ธก, ํ•˜๋‹จ, ์ขŒ์ธก])

์˜ค .. ์‹ ๊ธฐ...

 

 


์ธ๋„ค์ผ ์ด๋ฏธ์ง€ ์ฐธ๊ณ  ๋ฐ NetCDF ์ฐธ๊ณ ์ž๋ฃŒ ! (ํ•œ ๋ฒˆ์€ ์ฝ์–ด๋ณด๋ฉด ์ข‹๊ฒ ๋‹ค)

๋ฐ˜์‘ํ˜•

์ตœ๊ทผ๋Œ“๊ธ€

์ตœ๊ทผ๊ธ€

skin by ยฉ 2024 ttutta