TANGERANG SELATAN WEATHER

Rabu, 20 Mei 2026

Memulai dengan xarray untuk data cuaca: membuat dan menjelajahi dataset sintetis

Conceptual illustration of layered atmospheric data as a multi-dimensional tensor

Mengapa xarray cocok untuk data meteorologi

Data meteorologi hampir selalu hadir dalam bentuk multidimensi. Sebuah field temperatur, misalnya, memiliki tiga sumbu: waktu (time), garis lintang (lat), dan garis bujur (lon). Ketika Kita bekerja dengan reanalysis seperti ERA5 atau output model NWP seperti GFS, dimensi pressure level turut ditambahkan sehingga menjadi empat dimensi atau lebih. Setiap field seperti ini merupakan tensor berlabel — setiap titik dalam array bukan hanya sebuah angka, melainkan angka yang terkait pada posisi geografis dan waktu tertentu.

Dengan numpy murni, array seperti ini kehilangan konteks koordinatnya begitu Kita membuat variabel. Kita hanya mendapatkan indeks integer [0, 1, 2, ...] tanpa informasi apakah indeks ke-5 merujuk ke lintang −10° atau +5°. Akibatnya, setiap kali Kita ingin memilih region tertentu atau melakukan subsetting berbasis koordinat, Kita harus menghitung indeks secara manual. Proses ini rawan kesalahan dan sulit didebug, terutama ketika ukuran grid berubah di antara dataset yang berbeda.

Pandas memperbaiki masalah ini untuk data satu dimensi, misalnya time series observasi dari satu stasiun cuaca. DataFrame dengan DatetimeIndex bekerja sangat baik untuk keperluan tersebut. Namun, pandas tidak dirancang untuk array tiga dimensi atau lebih. Mencoba merepresentasikan field temperatur (time, lat, lon) di dalam DataFrame membutuhkan MultiIndex yang rumit dan operasi pivot yang tidak intuitif.

xarray mengisi celah ini secara langsung. Library ini menyediakan dua struktur data utama: DataArray untuk satu variabel berlabel koordinat, dan Dataset untuk kumpulan DataArray yang berbagi koordinat yang sama. Setiap sumbu dalam DataArray memiliki nama dimensi dan nilai koordinat yang melekat langsung pada data — tidak terpisah. Kita bisa memilih subset data berdasarkan nilai koordinat aktual, misalnya lat=−6.2 dan lon=106.8 untuk Jakarta, bukan berdasarkan indeks posisi.

xarray juga terintegrasi langsung dengan format file standar meteorologi. NetCDF4 dan GRIB dapat dibuka langsung dengan xr.open_dataset(). Koordinat, atribut, dan unit metadata tersimpan di dalam objek xarray secara otomatis, persis seperti yang didefinisikan di dalam file. Ketika Kita membuka file ERA5 yang berisi variabel t2m (temperatur 2 meter), koordinat latitude, longitude, dan valid_time sudah tersedia tanpa preprocessing tambahan. Ini menghemat banyak waktu dibandingkan membaca file dengan netCDF4-python murni dan menyusun koordinat secara manual.

Keunggulan lain yang tidak kalah penting adalah dukungan lazy loading melalui Dask. Ketika Kita membuka file NetCDF besar dengan chunks={"time": 10}, xarray tidak langsung memuat seluruh data ke memori. Komputasi didefinisikan sebagai graph operasi dan dieksekusi hanya ketika hasilnya benar-benar dibutuhkan. Ini memungkinkan Kita bekerja dengan dataset berukuran gigabyte bahkan pada mesin dengan RAM terbatas.

Membangun DataArray dari nol dengan koordinat lat, lon, dan time

Sebelum bekerja dengan data nyata dari ERA5 atau GFS, penting untuk memahami struktur DataArray dari fondasinya. Kita akan membangun DataArray temperatur sintetis tiga dimensi dengan dimensi (time, lat, lon) menggunakan numpy, kemudian memasang koordinat eksplisit padanya. Pendekatan ini memperjelas apa yang sebenarnya terjadi di balik xr.open_dataset() ketika membaca file NetCDF.

Ada tiga konsep yang perlu dipahami sebelum menulis kode:

Dimensi adalah nama sumbu array. Dalam meteorologi, Kita hampir selalu bekerja dengan dimensi bernama time, lat, lon, dan kadang level untuk pressure level. Nama ini bukan sekadar label kosmetik — xarray menggunakannya untuk menentukan arah operasi seperti mean("time") atau sel(lat=...).

Koordinat adalah nilai aktual yang merepresentasikan posisi sepanjang setiap dimensi. Koordinat lat mungkin berisi nilai [−10, −5, 0, 5, 10] dalam satuan derajat lintang. Koordinat time berisi nilai datetime64. Koordinat inilah yang membuat DataArray berbeda dari numpy array biasa.

Atribut adalah metadata tambahan yang disimpan sebagai dictionary di dalam DataArray. Atribut umum dalam data meteorologi mencakup units (misalnya K untuk Kelvin atau m/s untuk kecepatan angin), long_name (deskripsi panjang variabel), dan source (nama dataset atau model yang menghasilkan data).

Berikut cara membangun DataArray secara eksplisit dari array numpy tiga dimensi:

import numpy as np
import xarray as xr

# Definisikan koordinat
times = np.array([
    np.datetime64("2024-01-01T00:00"),
    np.datetime64("2024-01-01T06:00"),
    np.datetime64("2024-01-01T12:00"),
    np.datetime64("2024-01-01T18:00"),
])
lats = np.array([-10.0, -5.0, 0.0, 5.0, 10.0])    # derajat lintang
lons = np.array([100.0, 105.0, 110.0, 115.0, 120.0])  # derajat bujur

# Buat array numpy 3D dengan nilai temperatur sintetis dalam Kelvin
# Shape: (4 time steps, 5 lat, 5 lon)
rng = np.random.default_rng(seed=42)
temp_data = 295.0 + rng.standard_normal((4, 5, 5)) * 3.0  # ~295 K ± 3 K

# Bungkus array ke dalam DataArray xarray dengan koordinat dan atribut
temp = xr.DataArray(
    data=temp_data,
    dims=["time", "lat", "lon"],
    coords={
        "time": times,
        "lat": lats,
        "lon": lons,
    },
    attrs={
        "long_name": "Near-surface air temperature",
        "units": "K",
        "source": "synthetic",
    },
)

print(temp)
print("\nDimensi:", temp.dims)
print("Shape:", temp.shape)
print("Satuan:", temp.attrs["units"])
print("Nilai min (K):", round(float(temp.min()), 2))
print("Nilai max (K):", round(float(temp.max()), 2))
<xarray.DataArray (time: 4, lat: 5, lon: 5)> Size: 800B
array([[[295.91415124, 291.88004768, 297.25135359, 297.82169415,
         289.14689443],
        [291.09346148, 295.38352121, 294.05127222, 294.94959653,
         292.44086822],
        [297.63819392, 297.33337581, 295.19809209, 298.38172362,
         296.40252803],
        [292.42212261, 296.10625235, 292.1233522 , 297.6353509 ,
         294.85022227],
        [294.44541291, 292.95721137, 298.66762402, 294.53641155,
         293.71501653]],

       [[293.94359935, 296.59692756, 296.09633219, 296.23819783,
         296.29246301],
        [301.4249428 , 293.78075495, 293.46327181, 292.55868182,
         296.84793827],
        [298.38691688, 294.65815763, 292.47953057, 292.52655635,
         296.95177836],
        [297.22976251, 296.6294628 , 293.00347088, 295.69648397,
         295.35005743],
        [295.65606579, 297.61428633, 295.67078665, 297.03674069,
...
         293.58888204],
        [293.08336646, 294.17457325, 299.48482393, 292.40250665,
         297.90483506],
        [289.95139069, 293.99534491, 295.4882592 , 296.75866699,
         297.13367974],
        [297.38004171, 293.95382478, 293.61294462, 297.57392764,
         294.42608703],
        [291.17294103, 291.60013836, 292.24164314, 296.49148223,
         295.42727721]],

       [[297.07145606, 293.71824206, 295.47561907, 296.87677118,
         294.07196038],
        [296.37032571, 293.01422218, 293.91083846, 293.85478632,
         291.41248106],
        [296.46091744, 293.59179298, 295.03748236, 296.44223998,
         296.33959353],
        [296.99615533, 294.70454355, 293.73010506, 294.76084537,
         289.9379967 ],
        [290.65866258, 291.03190116, 292.00825952, 296.19932268,
         292.28356283]]])
Coordinates:
  * time     (time) datetime64[s] 32B 2024-01-01 ... 2024-01-01T18:00:00
  * lat      (lat) float64 40B -10.0 -5.0 0.0 5.0 10.0
  * lon      (lon) float64 40B 100.0 105.0 110.0 115.0 120.0
Attributes:
    long_name:  Near-surface air temperature
    units:      K
    source:     synthetic

Dimensi: ('time', 'lat', 'lon')
Shape: (4, 5, 5)
Satuan: K
Nilai min (K): 289.15
Nilai max (K): 301.42

Output di atas menampilkan ringkasan struktural DataArray dalam format yang khas untuk xarray. Kita dapat melihat nama dimensi (time, lat, lon), nilai koordinat di setiap sumbu, atribut metadata, serta ringkasan nilai aktual array. Inilah yang membedakan DataArray dari numpy array biasa — konteks koordinat selalu terbawa bersama data dan tidak terpisah. Perhatikan bahwa koordinat time disimpan sebagai datetime64, yang memungkinkan xarray mengenali struktur temporal dan mendukung operasi seperti resample, groupby("time.hour"), atau pemilihan rentang waktu dengan sel(time=slice(...)).

Operasi dasar: select, mean, dan groupby di xarray

Dengan DataArray yang sudah Kita bangun, saatnya menjelajahi tiga operasi paling fundamental dalam alur kerja analisis data meteorologi: pemilihan titik koordinat dengan sel(), reduksi dimensi dengan mean(), dan agregasi temporal dengan groupby(). Ketiga operasi ini menjadi inti dari hampir semua pipeline analisis, mulai dari menghitung klimatologi sederhana hingga mengolah output ensemble NWP.

Metode sel() memungkinkan pemilihan data berdasarkan nilai koordinat aktual, bukan indeks posisi integer. Ini adalah perbedaan krusial. Ketika grid berubah resolusinya — misalnya dari GFS 0.25° ke ERA5 0.1° — kode sel(lat=−6.2, lon=106.8) tetap bekerja tanpa perlu mengubah indeks. Jika nilai koordinat yang diminta tidak tepat cocok dengan nilai yang ada di DataArray, parameter method="nearest" akan memilih nilai koordinat terdekat secara otomatis.

Metode mean() dengan argumen nama dimensi akan mereduksi array sepanjang sumbu yang ditentukan, sambil tetap mempertahankan koordinat dari sumbu-sumbu lainnya. Operasi temp.mean("time") menghasilkan DataArray dua dimensi (lat, lon) yang merepresentasikan rata-rata temporal di setiap titik grid. Hasilnya bukan numpy array polos — koordinat lat dan lon masih melekat, sehingga Kita bisa langsung memplot hasilnya dengan koordinat yang benar.

Metode groupby() memungkinkan agregasi berdasarkan nilai kategoris dari koordinat. Untuk data cuaca, penggunaan paling umum adalah groupby("time.month") untuk menghitung klimatologi bulanan, atau groupby("time.hour") untuk menghitung siklus diurnal. xarray akan membagi DataArray menjadi grup berdasarkan nilai tersebut, menerapkan fungsi agregasi, dan mengembalikan DataArray baru dengan dimensi grup menggantikan dimensi waktu.

# Snippet ini menggunakan DataArray `temp` yang dibuat di snippet sebelumnya

# 1. sel() — pilih time series di satu titik grid (equator, 110°E)
point = temp.sel(lat=0.0, lon=110.0)
print("Time series di lat=0°, lon=110°E (K):")
print(point.values)

# 2. mean("time") — rata-rata temporal, hasilnya DataArray (lat, lon)
time_mean = temp.mean("time")
print("\nRata-rata temporal — shape:", time_mean.shape)
print("Dimensi yang tersisa:", time_mean.dims)

# 3. Nilai rata-rata di titik equator, lon=110°E setelah mean temporal
point_mean = temp.sel(lat=0.0, lon=110.0).mean("time")
print(f"\nRata-rata temperatur di lat=0°, lon=110°E: {float(point_mean):.2f} K")

# 4. groupby — rata-rata per jam UTC (menghitung siklus diurnal sintetis)
hourly_mean = temp.groupby("time.hour").mean("time")
print("\nRata-rata per jam UTC — shape:", hourly_mean.shape)
print("Jam UTC yang tercakup:", hourly_mean["hour"].values)
print("Dimensi hasil groupby:", hourly_mean.dims)
Time series di lat=0°, lon=110°E (K):
[295.19809209 292.47953057 295.4882592  295.03748236]

Rata-rata temporal — shape: (5, 5)
Dimensi yang tersisa: ('lat', 'lon')

Rata-rata temperatur di lat=0°, lon=110°E: 294.55 K

Rata-rata per jam UTC — shape: (4, 5, 5)
Jam UTC yang tercakup: [ 0  6 12 18]
Dimensi hasil groupby: ('hour', 'lat', 'lon')

Hasil operasi ini memperlihatkan bagaimana label koordinat tetap terjaga di setiap langkah transformasi. Setelah mean("time"), DataArray masih memiliki koordinat lat dan lon yang utuh. Setelah groupby("time.hour").mean("time"), dimensi time digantikan oleh dimensi hour, dengan nilai koordinat berupa jam UTC yang ada dalam data kita.

Berikut adalah alur transformasi DataArray yang Kita lakukan dalam snippet di atas:

Diagram diagram-1

Pola ini — sel() untuk memilih, mean() untuk reduksi, groupby() untuk agregasi — merupakan inti dari hampir semua alur analisis data meteorologi dengan xarray. Pola yang sama berlaku persis ketika Kita membuka file NetCDF ERA5 nyata atau membaca output model GFS, karena xarray memperlakukan semua DataArray dengan cara yang seragam, terlepas dari sumber datanya.

Memvisualisasikan DataArray dengan Koordinat Berlabel

Setelah memahami struktur dan operasi xarray, langkah natural berikutnya adalah memplot DataArray sebagai field 2D. Karena lat dan lon melekat pada data, matplotlib.pcolormesh bisa langsung menerima ketiga komponen — koordinat x, koordinat y, dan nilai — tanpa preprocessing tambahan. Snippet di bawah memplot rata-rata temporal yang sudah Kita hitung sebagai gradien warna, ditambah time series satu titik di sebelahnya untuk membandingkan dua pola operasi.

# Prereq globals (dari snippet 1-2):
#   temp        — DataArray (time, lat, lon) sintetis
#   point       — temp.sel(lat=0, lon=110) → DataArray (time,)
#   time_mean   — temp.mean('time')        → DataArray (lat, lon)
import matplotlib.pyplot as plt

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(13, 5),
                                gridspec_kw={"width_ratios": [1.4, 1]})

mesh = ax1.pcolormesh(
    time_mean["lon"], time_mean["lat"], time_mean.values,
    cmap="RdYlBu_r", shading="auto",
)
ax1.set_xlabel("Lon (°E)")
ax1.set_ylabel("Lat (°N)")
ax1.set_title("temp.mean('time')\nDataArray (lat, lon)", fontsize=11, weight="bold")
for la in time_mean["lat"].values:
    for lo in time_mean["lon"].values:
        v = float(time_mean.sel(lat=la, lon=lo))
        ax1.text(lo, la, f"{v:.1f}", ha="center", va="center",
                 fontsize=8, color="black")
plt.colorbar(mesh, ax=ax1, shrink=0.8, label="Suhu (K)")

# Right panel: time series at equator, 110E
times = point["time"].values
ax2.plot(range(len(times)), point.values, "o-", color="#1565C0",
         linewidth=2.0, markersize=10)
ax2.set_xticks(range(len(times)))
ax2.set_xticklabels(["00 UTC", "06 UTC", "12 UTC", "18 UTC"], rotation=15)
ax2.set_ylabel("Suhu (K)")
ax2.set_title("temp.sel(lat=0, lon=110)\nDataArray (time,)", fontsize=11, weight="bold")
ax2.grid(True, alpha=0.3)
ax2.axhline(float(point.mean()), color="#E65100", linestyle="--",
            linewidth=1.4, label=f"point.mean() = {float(point.mean()):.2f} K")
ax2.legend(loc="best", fontsize=9)

fig.suptitle("Dua Pola Operasi xarray dalam Satu Figure", fontsize=13, weight="bold")
plt.tight_layout()
plt.savefig("xarray_two_operations.png", dpi=150, bbox_inches="tight")

Dua panel xarray — kiri: peta rata-rata temporal sintetis lat-lon grid 5x5, kanan: time series 4-timestep di equator 110E

Dua panel ini merangkum dua arah agregasi yang paling sering dilakukan: panel kiri menggambarkan reduksi dimensi time menjadi field spasial 2D, panel kanan menggambarkan pemilihan satu titik koordinat menjadi time series 1D. Pada data sintetis kita yang sengaja noise murni, tidak ada pola spasial yang berarti — tetapi struktur visualisasinya sama persis dengan ERA5 atau GFS nyata: ganti temp dengan xr.open_dataset("era5_t2m.nc")["t2m"] dan dua plot di atas tetap berlaku tanpa modifikasi kecuali skala warna.

Langkah selanjutnya untuk eksplorasi data nyata

Dataset sintetis yang Kita bangun di atas memberikan pemahaman kokoh tentang struktur dan operasi dasar xarray. Langkah berikutnya adalah menerapkan pengetahuan ini pada data meteorologi nyata yang tersedia secara publik dan dapat langsung diunduh.

ERA5 dari ECMWF adalah salah satu dataset reanalysis paling lengkap dan banyak digunakan dalam komunitas meteorologi global. Kita bisa mengaksesnya melalui CDS API (Copernicus Climate Data Store) dengan paket cdsapi. Setelah file NetCDF diunduh, cukup gunakan xr.open_dataset("era5_subset.nc") dan semua koordinat serta variabel langsung tersedia dengan metadata lengkap. Era5 menyediakan data dari 1940 hingga hampir real-time, mencakup ratusan variabel mulai dari temperatur dan kelembaban hingga fluk radiasi dan parameter tanah.

GFS dari NOAA tersedia secara real-time melalui endpoint NOMADS atau mirror publik lainnya dalam format GRIB2. Paket cfgrib memungkinkan xarray membuka file GRIB2 langsung dengan engine="cfgrib". GFS menghasilkan prakiraan global 0.25° hingga 16 hari ke depan, dan output-nya diperbarui empat kali sehari pukul 00, 06, 12, dan 18 UTC.

IMERG dari NASA menyediakan data presipitasi global berbasis gabungan satelit dan gauge observasi, dengan resolusi spasial 0.1° dan temporal 30 menit. File HDF5 dapat dibuka dengan xarray menggunakan engine h5netcdf, dan koordinat lat/lon tersedia langsung. IMERG sangat berguna untuk analisis presipitasi di wilayah Indonesia yang minim jaringan pengamatan darat.

Untuk data lokal Indonesia, BMKG menyediakan data observasi sinoptik dan beberapa produk NWP melalui portal dan API yang terus berkembang. Menggabungkan data BMKG dengan reanalysis ERA5 menggunakan xarray — misalnya untuk validasi model terhadap observasi — adalah latihan yang sangat bermanfaat untuk memperdalam pemahaman analisis data meteorologi.

Eksplorasi artikel meteorologi lainnya di meteo.my.id — temukan panduan tentang ERA5, GFS, analisis data BMKG, dan teknik visualisasi dengan cartopy di https://meteo.my.id.

Tidak ada komentar:

Posting Komentar