Meteo: Air temperature (TA) (2005-2024)#

Author: Lukas Hörtnagl (holukas@ethz.ch)

Variable#

varname = 'VPD_T1_2_1'
var = "VPD"  # Name shown in plots
units = "kPa"

Imports#

import importlib.metadata
import warnings
from datetime import datetime
from pathlib import Path
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

import diive as dv
from diive.core.io.files import save_parquet, load_parquet
from diive.core.plotting.cumulative import CumulativeYear
from diive.core.plotting.bar import LongtermAnomaliesYear

warnings.filterwarnings(action='ignore', category=FutureWarning)
warnings.filterwarnings(action='ignore', category=UserWarning)
version_diive = importlib.metadata.version("diive")
print(f"diive version: v{version_diive}")
diive version: v0.87.0

Load data#

SOURCEDIR = r"../80_FINALIZE"
FILENAME = r"81.1_FLUXES_M15_MGMT_L4.2_NEE_GPP_RECO_LE_H_FN2O_FCH4.parquet"
FILEPATH = Path(SOURCEDIR) / FILENAME
df = load_parquet(filepath=FILEPATH)
df
Loaded .parquet file ..\80_FINALIZE\81.1_FLUXES_M15_MGMT_L4.2_NEE_GPP_RECO_LE_H_FN2O_FCH4.parquet (1.553 seconds).
    --> Detected time resolution of <30 * Minutes> / 30min 
.PREC_RAIN_TOT_GF1_0.5_1_MEAN3H-12 .PREC_RAIN_TOT_GF1_0.5_1_MEAN3H-18 .PREC_RAIN_TOT_GF1_0.5_1_MEAN3H-24 .PREC_RAIN_TOT_GF1_0.5_1_MEAN3H-6 .SWC_GF1_0.15_1_gfXG_MEAN3H-12 .SWC_GF1_0.15_1_gfXG_MEAN3H-18 .SWC_GF1_0.15_1_gfXG_MEAN3H-24 .SWC_GF1_0.15_1_gfXG_MEAN3H-6 .TS_GF1_0.04_1_gfXG_MEAN3H-12 .TS_GF1_0.04_1_gfXG_MEAN3H-18 .TS_GF1_0.04_1_gfXG_MEAN3H-24 .TS_GF1_0.04_1_gfXG_MEAN3H-6 .TS_GF1_0.15_1_gfXG_MEAN3H-12 .TS_GF1_0.15_1_gfXG_MEAN3H-18 .TS_GF1_0.15_1_gfXG_MEAN3H-24 ... GPP_NT_CUT_50_gfRF RECO_DT_CUT_50_gfRF GPP_DT_CUT_50_gfRF RECO_DT_CUT_50_gfRF_SD GPP_DT_CUT_50_gfRF_SD G_GF1_0.03_1 G_GF1_0.03_2 G_GF1_0.05_1 G_GF1_0.05_2 G_GF4_0.02_1 G_GF5_0.02_1 LW_OUT_T1_2_1 NETRAD_T1_2_1 PPFD_OUT_T1_2_2 SW_OUT_T1_2_1
TIMESTAMP_MIDDLE
2005-01-01 00:15:00 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... 0.918553 0.093071 0.0 0.080016 0.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2005-01-01 00:45:00 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... 0.917972 0.092682 0.0 0.079688 0.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2005-01-01 01:15:00 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... 0.163001 0.093071 0.0 0.080016 0.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2005-01-01 01:45:00 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... 0.190890 0.093071 0.0 0.080016 0.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2005-01-01 02:15:00 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... 0.167042 0.092295 0.0 0.079361 0.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
2024-12-31 21:45:00 0.0 0.0 0.0 0.0 52.229004 52.226300 52.226689 52.216796 3.458828 3.150402 3.115260 3.660897 4.335667 4.347764 4.385967 ... -0.334996 1.091028 0.0 0.265808 0.0 NaN NaN -9.097370 -7.880106 NaN NaN 311.167160 -5.883538 0.0 0.0
2024-12-31 22:15:00 0.0 0.0 0.0 0.0 52.227858 52.227986 52.224528 52.214211 3.522570 3.187638 3.103440 3.643396 4.338551 4.342880 4.379524 ... -0.310533 1.078751 0.0 0.264327 0.0 NaN NaN -9.561669 -8.172388 NaN NaN 310.079817 -6.269816 0.0 0.0
2024-12-31 22:45:00 0.0 0.0 0.0 0.0 52.226640 52.229837 52.222456 52.209876 3.578745 3.230037 3.095339 3.624025 4.343767 4.339440 4.372636 ... -0.225651 1.079759 0.0 0.264447 0.0 NaN NaN -10.138718 -8.527732 NaN NaN 309.604987 -6.934394 0.0 0.0
2024-12-31 23:15:00 0.0 0.0 0.0 0.0 52.224375 52.231151 52.221324 52.238293 3.624160 3.278488 3.093806 3.601135 4.350872 4.336333 4.366082 ... -0.558285 1.062164 0.0 0.262373 0.0 NaN NaN -10.649611 -8.871628 NaN NaN 308.812117 -5.696729 0.0 0.0
2024-12-31 23:45:00 0.0 0.0 0.0 0.0 52.222007 52.230632 52.222701 52.273511 3.656167 3.331678 3.103003 3.579020 4.360311 4.334225 4.359530 ... -0.317543 1.047483 0.0 0.260688 0.0 NaN NaN -10.944774 -9.138224 NaN NaN 307.372117 -8.102484 0.0 0.0

350640 rows × 812 columns

series = df[varname].copy()
series.plot(x_compat=True);
series
TIMESTAMP_MIDDLE
2005-01-01 00:15:00    0.099893
2005-01-01 00:45:00    0.097606
2005-01-01 01:15:00    0.091683
2005-01-01 01:45:00    0.071157
2005-01-01 02:15:00    0.058333
                         ...   
2024-12-31 21:45:00    0.000011
2024-12-31 22:15:00    0.000011
2024-12-31 22:45:00    0.000011
2024-12-31 23:15:00    0.000010
2024-12-31 23:45:00    0.000010
Freq: 30min, Name: VPD_T1_2_1, Length: 350640, dtype: float64
../../_images/ba1a8f1f71663551c8ce7e8148d73cebd4f4f772f0437bea5997796e568d4698.png
xlabel = f"{var} ({units})"
xlim = [series.min(), series.max()]

Stats#

Overall mean#

_yearly_avg = series.resample('YE').mean()
_overall_mean = _yearly_avg.mean()
_overall_sd = _yearly_avg.std()
print(f"Overall mean: {_overall_mean} +/- {_overall_sd}")
Overall mean: 0.31121955791661643 +/- 0.04902864837566863

Yearly means#

ym = series.resample('YE').mean()
ym
TIMESTAMP_MIDDLE
2005-12-31    0.376433
2006-12-31    0.225410
2007-12-31    0.328995
2008-12-31    0.310836
2009-12-31    0.311359
2010-12-31    0.297305
2011-12-31    0.366753
2012-12-31    0.359951
2013-12-31    0.271216
2014-12-31    0.256449
2015-12-31    0.343164
2016-12-31    0.268533
2017-12-31    0.358312
2018-12-31    0.381314
2019-12-31    0.309646
2020-12-31    0.303856
2021-12-31    0.221246
2022-12-31    0.346967
2023-12-31    0.334818
2024-12-31    0.251827
Freq: YE-DEC, Name: VPD_T1_2_1, dtype: float64
ym.sort_values(ascending=False)
TIMESTAMP_MIDDLE
2018-12-31    0.381314
2005-12-31    0.376433
2011-12-31    0.366753
2012-12-31    0.359951
2017-12-31    0.358312
2022-12-31    0.346967
2015-12-31    0.343164
2023-12-31    0.334818
2007-12-31    0.328995
2009-12-31    0.311359
2008-12-31    0.310836
2019-12-31    0.309646
2020-12-31    0.303856
2010-12-31    0.297305
2013-12-31    0.271216
2016-12-31    0.268533
2014-12-31    0.256449
2024-12-31    0.251827
2006-12-31    0.225410
2021-12-31    0.221246
Name: VPD_T1_2_1, dtype: float64

Monthly averages#

seriesdf = pd.DataFrame(series)
seriesdf['MONTH'] = seriesdf.index.month
seriesdf['YEAR'] = seriesdf.index.year
monthly_avg = seriesdf.groupby(['YEAR', 'MONTH'])[varname].mean().unstack()
monthly_avg
MONTH 1 2 3 4 5 6 7 8 9 10 11 12
YEAR
2005 0.133255 0.125461 0.320798 0.435624 0.631945 0.892239 0.703919 0.504649 0.379947 0.193942 0.133325 0.048627
2006 0.042295 0.079210 0.150229 0.200371 0.318859 0.548187 0.802910 0.202061 0.182587 0.095968 0.047289 0.023285
2007 0.074036 0.069035 0.159711 0.538353 0.442551 0.609129 0.679132 0.486520 0.387438 0.240121 0.143102 0.105334
2008 0.101163 0.166638 0.268867 0.270890 0.640051 0.579719 0.624814 0.467921 0.274886 0.190829 0.078831 0.054863
2009 0.054268 0.089716 0.207986 0.475443 0.553480 0.530131 0.565989 0.602001 0.351871 0.161345 0.073599 0.055018
2010 0.034755 0.114424 0.250507 0.450694 0.309132 0.641680 0.775310 0.427092 0.296411 0.141553 0.086047 0.031565
2011 0.074014 0.114899 0.251863 0.581882 0.666643 0.590370 0.568899 0.682791 0.413194 0.205884 0.090626 0.142344
2012 0.143005 0.136775 0.382794 0.406973 0.603079 0.595387 0.611613 0.677814 0.332750 0.174978 0.127317 0.113257
2013 0.094633 0.118700 0.151919 0.296454 0.270358 0.545255 0.791319 0.515140 0.281154 0.089021 0.066108 0.023130
2014 0.027523 0.072557 0.203056 0.259976 0.371139 0.634490 0.447117 0.435652 0.328777 0.173127 0.051202 0.062999
2015 0.087011 0.080146 0.237306 0.421110 0.411199 0.630129 0.951911 0.668726 0.309405 0.137561 0.119234 0.042231
2016 0.085863 0.143620 0.210320 0.261039 0.408584 0.398482 0.625289 0.506644 0.396226 0.111058 0.051096 0.017171
2017 0.063720 0.120993 0.276426 0.338306 0.588850 0.842018 0.701453 0.599454 0.311367 0.252083 0.109643 0.077889
2018 0.137392 0.107644 0.165561 0.549344 0.466748 0.671946 1.003826 0.806515 0.436501 0.138281 0.021613 0.048886
2019 0.046392 0.133999 0.290680 0.316956 0.312127 0.762132 0.866354 0.456032 0.309308 0.114732 0.041034 0.055166
2020 0.038153 0.238026 0.222998 0.550285 0.479921 0.454533 0.654878 0.533983 0.330215 0.098995 0.033549 0.011433
2021 0.026035 0.082336 0.215003 0.379660 0.336810 0.511504 0.321846 0.359091 0.292334 0.100865 0.015050 0.011092
2022 0.037497 0.151235 0.319133 0.306950 0.470408 0.627205 0.910720 0.748110 0.311619 0.149694 0.072762 0.037093
2023 0.074762 0.137025 0.220513 0.216325 0.383360 0.916441 0.648015 0.614304 0.419083 0.220624 0.100025 0.058283
2024 0.074640 0.111231 0.206013 0.344785 0.330871 0.445858 0.536684 0.562334 0.223922 0.080089 0.054793 0.043635

Number of days below …#

# plotdf = df[[varname]].copy()
# plotdf = plotdf.resample('D').min()
# belowzero = plotdf.loc[plotdf[varname] < 0].copy()
# belowzero = belowzero.groupby(belowzero.index.year).count()
# belowzero["YEAR"] = belowzero.index
# belowzero
# belowzero.plot.bar(x="YEAR", y=varname, title=f"Number of days with {varname} < 0°");
# display(belowzero)
# print(f"Average per year: {belowzero[varname].mean()} +/- {belowzero[varname].std():.2f} SD")

Number of days above …#

plotdf = df[[varname]].copy()
plotdf = plotdf.resample('D').max()
above = plotdf.loc[plotdf[varname] > 2].copy()
above = above.groupby(above.index.year).count()
above["YEAR"] = above.index
above.plot.bar(x="YEAR", y=varname, title=f"Number of days with {varname} > 2 {units}");
display(above)
print(f"Average per year: {above[varname].mean()} +/- {above[varname].std():.2f} SD")
VPD_T1_2_1 YEAR
TIMESTAMP_MIDDLE
2005 26 2005
2006 32 2006
2007 30 2007
2008 37 2008
2009 48 2009
2010 49 2010
2011 40 2011
2012 20 2012
2013 36 2013
2014 20 2014
2015 49 2015
2016 28 2016
2017 48 2017
2018 72 2018
2019 45 2019
2020 46 2020
2021 29 2021
2022 60 2022
2023 57 2023
2024 32 2024
Average per year: 40.2 +/- 13.72 SD
../../_images/e8debb06b372c446162d2503abf7bc7e1b3101d34b42a3431d3dc3872d7f02d0.png

Heatmap plots#

Half-hourly#

fig, axs = plt.subplots(ncols=1, figsize=(6, 12), dpi=72, layout="constrained")
dv.heatmapdatetime(series=series, ax=axs, cb_digits_after_comma=0).plot()
../../_images/91d288f06865f441e39db01ebad154fe0fe0189e87adbebdf3ced2b684204733.png

Monthly#

fig, axs = plt.subplots(ncols=4, figsize=(21, 7), dpi=120, layout="constrained")
fig.suptitle(f'Per month', fontsize=32)
dv.heatmapyearmonth(series_monthly=series.resample('M').mean(), title="monthly mean", ax=axs[0], cb_digits_after_comma=0, zlabel="monthly mean").plot()
dv.heatmapyearmonth(series_monthly=series.resample('M').min(), title="monthly minimum", ax=axs[1], cb_digits_after_comma=0, zlabel="monthly minimum").plot()
dv.heatmapyearmonth(series_monthly=series.resample('M').max(), title="monthly maximum", ax=axs[2], cb_digits_after_comma=0, zlabel="monthly maximum").plot()
_range = series.resample('M').max().sub(series.resample('M').min())
dv.heatmapyearmonth(series_monthly=_range, title="monthly range", ax=axs[3], cb_digits_after_comma=0, zlabel="monthly range").plot()
../../_images/7284d256e641d021ffacfb78059d3eb7da58679f76b43c77576499c64e41b823.png

Monthly ranks#

# Figure
fig = plt.figure(facecolor='white', figsize=(17, 6))

# Gridspec for layout
gs = gridspec.GridSpec(1, 4)  # rows, cols
gs.update(wspace=0.35, hspace=0.3, left=0.03, right=0.97, top=0.97, bottom=0.03)
ax_mean = fig.add_subplot(gs[0, 0])
ax_mean_ranks = fig.add_subplot(gs[0, 1])
ax_max = fig.add_subplot(gs[0, 2])
ax_max_ranks = fig.add_subplot(gs[0, 3])
params = {'axlabels_fontsize': 10, 'ticks_labelsize': 10, 'cb_labelsize': 10}
dv.heatmapyearmonth_ranks(ax=ax_mean, series=series, agg='mean', ranks=False, zlabel=units, cmap="RdYlBu_r", show_values=False, **params).plot()

hm_mean_ranks = dv.heatmapyearmonth_ranks(ax=ax_mean_ranks, series=series, agg='mean', show_values=True, **params)
hm_mean_ranks.plot()

dv.heatmapyearmonth_ranks(ax=ax_max, series=series, agg='max', ranks=False, zlabel=units, cmap="RdYlBu_r", show_values=False, **params).plot()
dv.heatmapyearmonth_ranks(ax=ax_max_ranks, series=series, agg='max', show_values=True, **params).plot()

ax_mean.set_title(f"{var} mean", color='black')
ax_mean_ranks.set_title(f"{var} mean: ranks", color='black')
ax_max.set_title(f"{var} max", color='black')
ax_max_ranks.set_title(f"{var} max: ranks", color='black')

ax_mean.tick_params(left=True, right=False, top=False, bottom=True,
                    labelleft=True, labelright=False, labeltop=False, labelbottom=True)
ax_mean_ranks.tick_params(left=True, right=False, top=False, bottom=True,
                   labelleft=False, labelright=False, labeltop=False, labelbottom=True)
ax_max.tick_params(left=True, right=False, top=False, bottom=True,
                     labelleft=False, labelright=False, labeltop=False, labelbottom=True)
ax_max_ranks.tick_params(left=True, right=False, top=False, bottom=True,
                     labelleft=False, labelright=False, labeltop=False, labelbottom=True)

ax_mean_ranks.set_ylabel("")
ax_max.set_ylabel("")
ax_max_ranks.set_ylabel("")

fig.show()
../../_images/a04f2e193a0dee36e3e6666ecc0ee5fadd275b5d701a7d8980e777b0b162d2a0.png

Mean ranks per year#

hm_mean_ranks.hm.get_plot_data().mean(axis=1).plot(title="Mean ranks per year");
../../_images/facff22f6bc8c80e6edc46603276c275d2d7a694beb25f8356b66453aa7c3672.png

Ridgeline plots#

Yearly#

# rp = dv.ridgeline(series=series)
# rp.plot(
#     how='yearly',
#     kd_kwargs=None,  # params from scikit KernelDensity as dict
#     xlim=xlim,  # min/max as list
#     ylim=[0, 0.50],  # min/max as list
#     hspace=-0.8,  # overlap between months
#     xlabel=f"{var} ({units})",
#     fig_width=5,
#     fig_height=9,
#     shade_percentile=0.5,
#     show_mean_line=False,
#     fig_title=f"{var} per year (2005-2024)",
#     fig_dpi=72,
#     showplot=True,
#     ascending=False
# )

Monthly#

# rp.plot(
#     how='monthly',
#     kd_kwargs=None,  # params from scikit KernelDensity as dict
#     xlim=xlim,  # min/max as list
#     ylim=[0, 0.14],  # min/max as list
#     hspace=-0.6,  # overlap between months
#     xlabel=f"{var} ({units})",
#     fig_width=4.5,
#     fig_height=8,
#     shade_percentile=0.5,
#     show_mean_line=False,
#     fig_title=f"{var} per month (2005-2024)",
#     fig_dpi=72,
#     showplot=True,
#     ascending=False
# )

Weekly#

# rp.plot(
#     how='weekly',
#     kd_kwargs=None,  # params from scikit KernelDensity as dict
#     xlim=xlim,  # min/max as list
#     ylim=[0, 0.15],  # min/max as list
#     hspace=-0.6,  # overlap
#     xlabel=f"{var} ({units})",
#     fig_width=6,
#     fig_height=16,
#     shade_percentile=0.5,
#     show_mean_line=False,
#     fig_title=f"{var} per week (2005-2024)",
#     fig_dpi=72,
#     showplot=True,
#     ascending=False
# )

Single years per month#

# uniq_years = series.index.year.unique()
# for uy in uniq_years:
#     series_yr = series.loc[series.index.year == uy].copy()
#     rp = dv.ridgeline(series=series_yr)
#     rp.plot(
#         how='monthly',
#         kd_kwargs=None,  # params from scikit KernelDensity as dict
#         xlim=xlim,  # min/max as list
#         ylim=[0, 0.18],  # min/max as list
#         hspace=-0.6,  # overlap
#         xlabel=f"{var} ({units})",
#         fig_width=6,
#         fig_height=7,
#         shade_percentile=0.5,
#         show_mean_line=False,
#         fig_title=f"{var} per month ({uy})",
#         fig_dpi=72,
#         showplot=True,
#         ascending=False
#     )

Single years per week#

# uniq_years = series.index.year.unique()
# for uy in uniq_years:
#     series_yr = series.loc[series.index.year == uy].copy()
#     rp = dv.ridgeline(series=series_yr)
#     rp.plot(
#         how='weekly',
#         kd_kwargs=None,  # params from scikit KernelDensity as dict
#         xlim=xlim,  # min/max as list
#         ylim=[0, 0.3],  # min/max as list
#         hspace=-0.8,  # overlap
#         xlabel=f"{var} ({units})",
#         fig_width=9,
#         fig_height=18,
#         shade_percentile=0.5,
#         show_mean_line=False,
#         fig_title=f"{var} per week ({uy})",
#         fig_dpi=72,
#         showplot=True,
#         ascending=False
#     )

Cumulative plot#

CumulativeYear(
    series=series,
    series_units=units,
    start_year=2005,
    end_year=2024,
    show_reference=True,
    excl_years_from_reference=None,
    highlight_year=2024,
    highlight_year_color='#F44336').plot();
../../_images/a0a382a36b12f9f2a3d0711dc5d38d7d35246d2a180aa1473891701a004e2637.png

Long-term anomalies#

series_yearly_mean = series.resample('YE').mean()
series_yearly_mean.index = series_yearly_mean.index.year
series_label = f"CH-CHA: {varname}"
LongtermAnomaliesYear(series=series_yearly_mean,
                      series_label=series_label,
                      series_units=units,
                      reference_start_year=2005,
                      reference_end_year=2024).plot()
../../_images/e66f27a3e9aea1c9f911c3f442040a09512829a3a7e2404e38b3153bef7416b3.png

End of notebook#

dt_string = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print(f"Finished. {dt_string}")
Finished. 2025-05-16 13:10:31