*Kai dangus prabyla: žaibų dinamika ir ką jie pasako apie lietų ⛈️*
*Įvadas*
Vyraujančios meteorologinės sąlygos, o kartu ir įvairūs meteorologiniai reiškiniai yra neasiejama mūsų gyvenimo dalis. Greitai, o gal ir neplanuotai besikeičiantys orai, juos lydintys pavojingi meteorologiniai reiškinai gali pakoreguoti ne tik mūsų gyvenimo rutiną, bet ir artimiausių dienų planus.
Žvelgiant į besikeičiančių orų dinamiką svarbu įvertinti ne tik vieno, tuo metu vyraujančio meteorologinio reišknio, tačiau ir tuo pat metu susidarančių kitų reikšnių sąsajas. Šiame darbe bus apžvelgiamas žaibų išlydžių Lietuvos teritorije pasiskirstymas ir tarpusavio ryšiai su iškrentančiu kritulių kiekiu 2023 – 2025 m.
*Tikslas*
Išanalizuoti žaibų pasisikirtymą Lietuvos teritorije ir įvertinti jų sąsajas su iškrentančiu kritulių kiekiu.
*Hipotezės*
Žaibų pasiskirstymas Lietuvoje nėra visiškai tolygus – skirtingais metais išryškėja tam tikri teritoriniai ir pasiskirtymo laike skirtumai.
Stebint didelį žaibų išlydžių kiekį, fikuojamas ir gausesnis kritulių kiekis.
Žaibų išlydžių pasiskirstymas sutampa su gausaus kritulių kiekio zonomis.
Žaibų išlydžių kiekis yra glaudžiai susijęs su trumpalaikiais, intensyviais kritulių epizodais.
*Kintamieji*
Obstime, dg_obstime – laikas
dg_name, vardas – savivaldybės
rr_per – kritulių kiekis
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
df_2023 = pd.read_csv(r'C:\Users\ievam\Desktop\Duomenu analitika\Baigiamasis darbas\Python dalis\p.krituliai_2023.csv')
df_2024 = pd.read_csv(r'C:\Users\ievam\Desktop\Duomenu analitika\Baigiamasis darbas\Python dalis\p.krituliai_2024.csv')
df_2025 = pd.read_csv(r'C:\Users\ievam\Desktop\Duomenu analitika\Baigiamasis darbas\Python dalis\p.krituliai_2025.csv')
df_krituliai = pd.concat([df_2023, df_2024, df_2025], ignore_index=True)
df_zaibai = pd.read_csv(r'C:\Users\ievam\Desktop\Duomenu analitika\Baigiamasis darbas\Python dalis\p.zaibai_2023_2025.csv')
df_zaibai['kiekis'] = 1
Visų savivaldybių kritulių suma:
df_krituliai['dg_obstime'] = pd.to_datetime(df_krituliai['dg_obstime'])
df_krituliai['rr_per'] = pd.to_numeric(df_krituliai['rr_per'], errors='coerce')
hourly_sum_krituliai = df_krituliai.groupby('dg_obstime')['rr_per'].sum().reset_index()
print(hourly_sum_krituliai.head(10))
dg_obstime rr_per 0 2023-01-01 00:00:00 25.4 1 2023-01-01 01:00:00 28.9 2 2023-01-01 02:00:00 33.6 3 2023-01-01 03:00:00 30.8 4 2023-01-01 04:00:00 31.5 5 2023-01-01 05:00:00 30.8 6 2023-01-01 06:00:00 32.8 7 2023-01-01 07:00:00 17.8 8 2023-01-01 08:00:00 10.2 9 2023-01-01 09:00:00 8.9
Visų savivaldybių žaibų suma:
df_zaibai['obstime'] = pd.to_datetime(df_zaibai['obstime'], errors='coerce')
df_zaibai['hour'] = df_zaibai['obstime'].dt.floor('h')
hourly_sum = df_zaibai.groupby('hour')['kiekis'].sum()
full_range = pd.date_range(start=df_zaibai['hour'].min(), end=df_zaibai['hour'].max(), freq='h')
hourly_sum_zaibai = hourly_sum.reindex(full_range, fill_value=0)
hourly_sum_zaibai = hourly_sum_zaibai.reset_index().rename(columns={'index': 'laikas', 'kiekis': 'žaibų kiekis'})
print(hourly_sum_zaibai.head(10))
laikas žaibų kiekis 0 2023-03-07 19:00:00 6 1 2023-03-07 20:00:00 4 2 2023-03-07 21:00:00 3 3 2023-03-07 22:00:00 8 4 2023-03-07 23:00:00 1 5 2023-03-08 00:00:00 2 6 2023-03-08 01:00:00 0 7 2023-03-08 02:00:00 0 8 2023-03-08 03:00:00 0 9 2023-03-08 04:00:00 0
Visų savivaldybių žaibų ir kritulių kiekio pasiskirstymas skirtingais metais:
hourly_sum_krituliai = hourly_sum_krituliai.rename(columns={'dg_obstime': 'time', 'rr_per': 'krituliai'})
hourly_sum_zaibai = hourly_sum_zaibai.rename(columns={'laikas': 'time', 'žaibų kiekis': 'zaibai'})
years = [2023, 2024, 2025]
max_rain = 220
max_lightning = 4500
for year in years:
rain_year = hourly_sum_krituliai[hourly_sum_krituliai['time'].dt.year == year]
lightning_year = hourly_sum_zaibai[hourly_sum_zaibai['time'].dt.year == year]
fig, ax1 = plt.subplots(figsize=(12,5))
ax1.bar(rain_year['time'], rain_year['krituliai'], color='#00b3b3', label='Krituliai', width=0.2)
ax1.set_ylabel('Krituliai (mm)', color='#00b3b3')
ax1.set_ylim(0, max_rain)
ax1.tick_params(axis='y', labelcolor='#00b3b3')
if not rain_year.empty:
ax1.set_xlim(rain_year['time'].min(), rain_year['time'].max())
ax2 = ax1.twinx()
ax2.fill_between(lightning_year['time'], 0, lightning_year['zaibai'], color='orange', alpha=0.2)
ax2.plot(lightning_year['time'], lightning_year['zaibai'], label='Žaibai', color='orange',)
ax2.set_ylabel('Žaibų kiekis', color='orange',)
ax2.set_ylim(0, max_lightning)
ax2.tick_params(axis='y', labelcolor='orange',)
plt.title(f'Krituliai ir žaibai {year} metais')
fig.tight_layout()
lines, labels = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines + lines2, labels + labels2, loc='upper left')
plt.show()
Daugiausiai kritulių per visą laikotarpį iškrito:
df_krituliai['dg_obstime'] = pd.to_datetime(df_krituliai['dg_obstime'])
sum_by_city = (
df_krituliai[df_krituliai['dg_obstime'].dt.year.between(2023, 2025)]
.groupby('dg_name')['rr_per'].sum())
max_city, max_value = sum_by_city.idxmax(), sum_by_city.max()
print(f"Daugiausia kritulių (2023–2025 m.) iškrito savivaldybėje: {max_city}")
print(f"Bendras kritulių kiekis: {max_value:.2f} mm")
Daugiausia kritulių (2023–2025 m.) iškrito savivaldybėje: Plungės AMS Bendras kritulių kiekis: 2627.30 mm
df_krituliai['dg_obstime'] = pd.to_datetime(df_krituliai['dg_obstime'])
df_zaibai['obstime'] = pd.to_datetime(df_zaibai['obstime'])
rain = df_krituliai[df_krituliai['dg_name'] == 'Plungės AMS'].copy()
rain = rain.groupby(rain['dg_obstime'].dt.floor('h'))['rr_per'].sum()
lightning = df_zaibai[df_zaibai['vardas'] == 'Plungės r. sav.'].copy()
lightning = lightning.groupby(lightning['obstime'].dt.floor('h'))['kiekis'].sum()
all_hours = rain.index.union(lightning.index)
fig, ax1 = plt.subplots(figsize=(15,5))
bar_width = 0.6
offset = pd.Timedelta(minutes=15)
ax1.bar(all_hours - offset, [rain.get(h,0) for h in all_hours], width=bar_width, color='#006064', label='Krituliai')
ax2 = ax1.twinx()
ax2.bar(all_hours + offset, [lightning.get(h,0) for h in all_hours], width=bar_width, color='#FF6F00', label='Žaibai')
ax1.set_xlabel('Laikas')
ax1.set_ylabel('Krituliai (mm)', color='#006064')
ax2.set_ylabel('Žaibų kiekis', color='#FF6F00')
ax1.tick_params(axis='y', labelcolor='#006064')
ax2.tick_params(axis='y', labelcolor='#FF6F00')
ax1.set_xlim(pd.to_datetime('2023-01-01'), pd.to_datetime('2025-09-30'))
plt.title('Plungės AMS krituliai ir Plungės r. sav. žaibai')
fig.tight_layout()
plt.show()
Daugiausiai žaibų išlydžių per visą laikotarpį buvo:
df_zaibai['obstime'] = pd.to_datetime(df_zaibai['obstime'])
df_zaibai['hour'] = df_zaibai['obstime'].dt.floor('h')
hourly_sum = df_zaibai.groupby(['vardas', 'hour'])['kiekis'].sum().reset_index()
total_sum = hourly_sum.groupby('vardas')['kiekis'].sum().reset_index()
total_sum = total_sum.sort_values('kiekis', ascending=False)
max_city = total_sum.iloc[0]['vardas']
max_value = total_sum.iloc[0]['kiekis']
print(f"Daugiausia žaibų buvo savivaldybėje: {max_city}")
print(f"Bendras žaibų kiekis: {int(max_value)}")
Daugiausia žaibų buvo savivaldybėje: Panevėžio r. sav. Bendras žaibų kiekis: 13590
df_krituliai['dg_obstime'] = pd.to_datetime(df_krituliai['dg_obstime'])
df_zaibai['obstime'] = pd.to_datetime(df_zaibai['obstime'])
rain = df_krituliai[df_krituliai['dg_name'] == 'Panevėžio AMS'].copy()
rain = rain.groupby(rain['dg_obstime'].dt.floor('h'))['rr_per'].sum()
lightning = df_zaibai[df_zaibai['vardas'] == 'Panevėžio r. sav.'].copy()
lightning = lightning.groupby(lightning['obstime'].dt.floor('h'))['kiekis'].sum()
all_hours = rain.index.union(lightning.index)
fig, ax1 = plt.subplots(figsize=(15,5))
bar_width = 0.6
offset = pd.Timedelta(minutes=15)
ax1.bar(all_hours - offset, [rain.get(h,0) for h in all_hours], width=bar_width, color='#006064', label='Krituliai')
ax2 = ax1.twinx()
ax2.bar(all_hours + offset, [lightning.get(h,0) for h in all_hours], width=bar_width, color='#FF6F00', label='Žaibai')
ax1.set_xlabel('Laikas')
ax1.set_ylabel('Krituliai (mm)', color='#006064')
ax2.set_ylabel('Žaibų kiekis', color='#FF6F00')
ax1.tick_params(axis='y', labelcolor='#006064')
ax2.tick_params(axis='y', labelcolor='#FF6F00')
ax1.set_xlim(pd.to_datetime('2023-01-01'), pd.to_datetime('2025-09-30'))
plt.title('Panevėžio AMS krituliai ir Panevėžio r. sav. žaibai')
fig.tight_layout()
plt.show()
10 meteorologijos stočių, kuriose 1 val. iškrito daugiausiai kritulių:
df_period = df_krituliai[df_krituliai['dg_obstime'].dt.year.between(2023, 2025)]
top10 = df_period.nlargest(10, 'rr_per').copy()
df_top10 = top10[['dg_name', 'dg_obstime', 'rr_per']].copy()
df_top10.columns = ['Stotis', 'Laikas', 'Kritulių kiekis (mm)']
df_top10.reset_index(drop=True, inplace=True)
display(df_top10)
| Stotis | Laikas | Kritulių kiekis (mm) | |
|---|---|---|---|
| 0 | Klaipėdos AMS | 2023-08-06 05:00:00 | 53.5 |
| 1 | Skuodo AMS | 2024-05-25 17:00:00 | 45.4 |
| 2 | Varėnos AMS | 2023-08-05 19:00:00 | 36.2 |
| 3 | Laukuvos AMS | 2024-08-18 22:00:00 | 35.9 |
| 4 | Pakruojo AMS | 2023-08-18 00:00:00 | 35.3 |
| 5 | Varėnos AMS | 2025-09-03 16:00:00 | 33.7 |
| 6 | Šakių AMS | 2025-07-11 00:00:00 | 33.1 |
| 7 | Rietavo AMS | 2025-07-28 15:00:00 | 32.4 |
| 8 | Nidos AMS | 2025-09-14 16:00:00 | 32.4 |
| 9 | Dūkšto AMS | 2023-08-05 20:00:00 | 32.3 |
station_to_savivaldybe = {'Klaipėdos AMS': 'Klaipėdos r. sav.','Skuodo AMS': 'Skuodo r. sav.','Varėnos AMS': 'Varėnos r. sav.',
'Laukuvos AMS': 'Šilalės r. sav.','Pakruojo AMS': 'Pakruojo r. sav.','Šakių AMS': 'Šakių r. sav.',
'Rietavo AMS': 'Rietavo sav.', 'Nidos AMS': 'Neringos sav.', 'Dūkšto AMS': 'Ignalinos r. sav.',}
top10_cases = df_top10[['Stotis', 'Laikas']].copy()
top10_cases['date'] = top10_cases['Laikas'].dt.date.astype(str)
top10_cases['savivaldybe'] = top10_cases['Stotis'].map(station_to_savivaldybe)
fig, axes = plt.subplots(5, 2, figsize=(15, 14), sharex=True)
axes = axes.flatten()
rain_color = '#1f77b4'
lightning_color = '#ff7f0e'
for idx, case in enumerate(top10_cases.itertuples()):
station = case.Stotis
date = case.date
savivaldybe = case.savivaldybe
ax1 = axes[idx]
ax2 = ax1.twinx()
df_rain = df_krituliai[
(df_krituliai['dg_name'] == station) &
(df_krituliai['dg_obstime'].dt.date.astype(str) == date)
]
rain_hourly = df_rain.groupby(df_rain['dg_obstime'].dt.hour)['rr_per'] \
.sum() \
.reindex(range(24), fill_value=0)
df_lightning = df_zaibai[
(df_zaibai['vardas'] == savivaldybe) &
(df_zaibai['obstime'].dt.date.astype(str) == date)
].copy()
df_lightning['kiekis'] = df_lightning['kiekis'].clip(lower=0)
zaibai_hourly = df_lightning.groupby(df_lightning['obstime'].dt.hour)['kiekis'] \
.sum() \
.reindex(range(24), fill_value=0)
hours = range(24)
ax1.plot(hours, rain_hourly.values, color=rain_color, linewidth=2, label='Krituliai (mm)')
ax2.plot(hours, zaibai_hourly.values, color=lightning_color, linestyle='--', linewidth=2, label='Žaibai (vnt)')
ax1.set_title(f"{date} {station} / {savivaldybe}", fontsize=11)
ax1.set_xticks(range(0, 24, 2))
ax1.set_ylim(bottom=0)
ax2.set_ylim(bottom=0)
ax1.set_ylabel('Krituliai (mm)', color=rain_color, fontsize=10)
ax2.set_ylabel('Žaibai (vnt)', color=lightning_color, fontsize=10)
lines1, labels1 = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper right', fontsize=9)
plt.xlabel('Valanda')
plt.suptitle('10 MS, kuriose per 1 val. iškrito daugiausiai kritulių ir tos dienos žaibų išlydžių pasiskirstymas', fontsize=14)
plt.tight_layout(rect=[0, 0, 1, 0.96])
plt.show()
10 savivaldybių, kuriose per 1 val. fiksuotas didžiausias žaibų kiekis:
df_zaibai['obstime'] = pd.to_datetime(df_zaibai['obstime'])
df_period = df_zaibai[(df_zaibai['obstime'].dt.year.between(2023, 2025)) & (df_zaibai['obstime'] < '2025-09-30')].copy()
df_period['valanda'] = df_period['obstime'].dt.floor('h')
df_sum = (df_period.groupby(['vardas', 'valanda'], as_index=False)['kiekis'].sum())
df_zaibai_top10 = df_sum.nlargest(10, 'kiekis')
df_zaibai_top10.reset_index(drop=True, inplace=True)
df_zaibai_top10
| vardas | valanda | kiekis | |
|---|---|---|---|
| 0 | Panevėžio r. sav. | 2023-08-07 08:00:00 | 1167 |
| 1 | Kėdainių r. sav. | 2024-07-11 13:00:00 | 1000 |
| 2 | Joniškio r. sav. | 2023-08-07 08:00:00 | 936 |
| 3 | Zarasų r. sav. | 2023-08-30 14:00:00 | 927 |
| 4 | Vilkaviškio r. sav. | 2023-08-06 19:00:00 | 911 |
| 5 | Jurbarko r. sav. | 2023-08-30 00:00:00 | 851 |
| 6 | Vilkaviškio r. sav. | 2023-08-30 15:00:00 | 839 |
| 7 | Panevėžio r. sav. | 2024-07-13 15:00:00 | 827 |
| 8 | Molėtų r. sav. | 2024-07-13 09:00:00 | 817 |
| 9 | Joniškio r. sav. | 2023-06-19 14:00:00 | 805 |
savivaldybe_to_station = {'Panevėžio r. sav.': 'Panevėžio AMS','Kėdainių r. sav.': 'Dotnuvos AMS','Joniškio r. sav.': 'Joniškio AMS',
'Zarasų r. sav.': 'Zarasų AMS','Vilkaviškio r. sav.': 'Kybartų AMS','Jurbarko r. sav.': 'Jurbarko AMS',
'Molėtų r. sav.': 'Molėtų AMS'}
df_zaibai_top10['date'] = df_zaibai_top10['valanda'].dt.date.astype(str)
df_zaibai_top10['hour'] = df_zaibai_top10['valanda'].dt.hour
df_zaibai_top10['station'] = df_zaibai_top10['vardas'].map(savivaldybe_to_station)
fig, axes = plt.subplots(5, 2, figsize=(15, 14), sharex=True)
axes = axes.flatten()
rain_color = '#1f77b4'
lightning_color = '#ff7f0e'
for idx, row in df_zaibai_top10.iterrows():
sav = row['vardas']
station = row['station']
date = row['date']
ax1 = axes[idx]
ax2 = ax1.twinx()
df_rain = df_krituliai[
(df_krituliai['dg_name'] == station) &
(df_krituliai['dg_obstime'].dt.date.astype(str) == date)
]
rain_hourly = df_rain.groupby(df_rain['dg_obstime'].dt.hour)['rr_per'] \
.sum() \
.reindex(range(24), fill_value=0)
df_lightning = df_zaibai[
(df_zaibai['vardas'] == sav) &
(df_zaibai['obstime'].dt.date.astype(str) == date)
].copy()
df_lightning['kiekis'] = df_lightning['kiekis'].clip(lower=0)
zaibai_hourly = df_lightning.groupby(df_lightning['obstime'].dt.hour)['kiekis'] \
.sum() \
.reindex(range(24), fill_value=0)
hours = range(24)
ax1.bar(hours, rain_hourly.values, color=rain_color, label='Krituliai (mm)')
ax2.plot(hours, zaibai_hourly.values, color=lightning_color, linestyle='--', linewidth=2)
ax1.set_title(f"{date} {sav} / {station}", fontsize=11)
ax1.set_xticks(range(0, 24, 2))
ax1.set_ylim(bottom=0)
ax2.set_ylim(bottom=0)
ax1.set_ylabel('Krituliai (mm)', color=rain_color)
ax2.set_ylabel('Žaibai (vnt)', color=lightning_color)
plt.xlabel('Valanda')
plt.suptitle('10 savivaldybių, kuriose per 1 val. fiksuotas didžiausias žaibų kiekis ir tos dienos kritulių kiekio pasiskirstymas', fontsize=14)
plt.tight_layout(rect=[0, 0, 1, 0.96])
plt.show()
Ryšys tarp žaibų ir kritulių:
df_krituliai['dg_obstime'] = pd.to_datetime(df_krituliai['dg_obstime'])
df_zaibai['obstime'] = pd.to_datetime(df_zaibai['obstime'])
df_krituliai['hour'] = df_krituliai['dg_obstime'].dt.floor('h')
df_zaibai['hour'] = df_zaibai['obstime'].dt.floor('h')
krituliai_per_val = df_krituliai.groupby('hour')['rr_per'].sum().reset_index()
zaibai_per_val = df_zaibai.groupby('hour')['kiekis'].sum().reset_index()
df_valanda = pd.merge(krituliai_per_val, zaibai_per_val, on='hour', how='outer')
df_valanda = df_valanda.fillna(0)
sns.regplot(data=df_valanda, x='kiekis', y='rr_per')
plt.xlabel('Žaibų skaičius per valandą')
plt.ylabel('Kritulių kiekis per 1 val. (mm)')
plt.title('Krituliai bei žaibai per 1 val.')
plt.show()
*Išvados*
Išnagrinėjus 2023-2025 m. žaibų išlydžių kiekio pasiskirstymą, matoma, kad skirtingais metais žaibų kiekis ir jo pasiskirstymas kinta, tačiau bendra tendencija, kad žaibų išlydžiai dažniausiai fiksuojami vasaros laikotarpiu pasitvirtina.
Vertinant bendrą šalies tendenciją ne visais atvejais didelis kritulių kiekis indikuoja apie didelį žaibų išlydžių kiekį.
Analizuojant dienų ir konkrečių meteorologijos stočių, kuriose buvo išmatuotas didelis kritulių kiekis atvejus, matoma tendencija, kad esant dideliam kritulių kiekiui, stebimas ir didesnis žaibų išlydžių kiekis, tačiau ryšys nėra ryškus, nes fiksuojami ir atvejai su krituliais be žaibų ir su žaibais be kritulių.
Vertinant savivaldybes, kuriose tam tikromis valandomis užfiksuotas didžiausias žaibų išlydžių skaičius ir kritulių kiekio pasiskirstymas, matyti, kad beveik visais atvejais, esant dideliam žaibų išlydžių kiekiui, stebimas ir didesnis kritulių kiekis. Todėl galima daryti išvadą, kad didelis žaibų išlydžių kiekis turi stipresnį ryšį su kritulių kiekiu nei atvejai, kai fiksuojamas tik didelis kritulių kiekis.
Didelė duomenų sklaida, tais laikotarpiais, kai žaibų ir kritulių reikšmės mažos yra labai tipiška gamtos reiškiniams, kurie iš tiesų kintantys ir nevienodi. Todėl galima teikti, kad ryšys tarp kritulių kiekio ir žaibų išlydžių skaičiaus yra, tačiau ne visuomet glaudus.
*Duomenų šaltinis*
Darbe naudojami 55 meteorologijos stočių kritulių kiekio kiekvienos valandos duomenys, bei žaibų išlydžių Lietovos teritorijoje duomenys iš Lietuvos hidrometeorologijos tarnybos (www.meteo.lt)