Hazard assessment: Visualise climate indicators#

Preparation work#

Load libraries#

import os

import cartopy.crs as ccrs
import cartopy.feature as cfeature
from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
import matplotlib.pyplot as plt
import numpy as np
import xarray as xr

Area of interest#

region_name = 'IT'

Path configuration#

This notebook processes NetCDF files containing data about the number of days where maximum temperature exceeds specific thresholds (e.g., 35°C, 40°C, 45°C) that was calculates previously in the notebook “02_UERRA_indicatorsCalculation.ipynb” and generates maps visualizing these exceedances over Italy.

  • We load a shapefile of Europe, then we isolate the portion of the shapefile that corresponds to Italy.

  • We search for the indicators_path for all NetCDF files that start with ‘NumbDays’, which contain the number of days with temperatures exceeding the thresholds. These files are sorted for further processing.

# Path to the folder containing the NetCDF files
indicators_path = f'../data_{region_name}/indicators/uerra'

# Path to save the maps
output_maps = os.path.join(indicators_path, 'maps')
os.makedirs(output_maps, exist_ok=True)

Plotting helpers#

def configure_map(ax, title=None):
    ax.add_feature(cfeature.COASTLINE)
    ax.add_feature(cfeature.BORDERS, linestyle='-', edgecolor='black')
    gl = ax.gridlines(draw_labels=True, linewidth=0.5, color='gray', alpha=0.0)
    gl.top_labels = False
    gl.right_labels = False
    gl.xformatter = LongitudeFormatter()
    gl.yformatter = LatitudeFormatter()
    if title is not None:
        ax.set_title(title)

Maps of the number of days of above 35, 40 and 45°C#

For each NetCDF file, we extract the variabble tx_days_above, which represents the number of days exceeding the temperature thresholds. We create a mask using the Italy shapefile to limit the data to within Italy’s borders, and the masked data are stored for later use.

thresholds = [35, 40, 45]  # °C

NumbDays_arrays = {}
global_min_NumbDays =  np.inf
global_max_NumbDays = -np.inf

for threshold in thresholds:
    NumbDays = xr.open_dataarray(os.path.join(indicators_path, f"NumbDaysAbove{threshold}.nc"))
    NumbDays_arrays[threshold] = NumbDays
    # Keep track of min and max values for colorbar scaling
    global_min_NumbDays = np.nanmin([global_min_NumbDays, np.nanmin(NumbDays.values)])
    global_max_NumbDays = np.nanmax([global_max_NumbDays, np.nanmax(NumbDays.values)])

print(f"Global min: {global_min_NumbDays}, Global max: {global_max_NumbDays}")
Global min: 0.0, Global max: 54.8
fig, axs = plt.subplots(nrows=1, ncols=3, figsize=(16, 5), subplot_kw={'projection': ccrs.PlateCarree()})
fig.suptitle('Number of Days above Maximum Temperature Exceeded (UERRA)', fontweight='bold')

plot_kwargs = {
    'cmap': 'Reds',
    'vmin': global_min_NumbDays,
    'vmax': global_max_NumbDays,
    'transform': ccrs.PlateCarree()
}
for ax, threshold in zip(axs, thresholds):
    configure_map(ax, title=f'Days above {threshold}°C')
    da = NumbDays_arrays[threshold]
    im = ax.pcolormesh(da['longitude'], da['latitude'], da.values, **plot_kwargs)

fig.colorbar(im, ax=axs, orientation='horizontal', fraction=0.05, pad=0.1, label='Number of Days')

fig.savefig(os.path.join(output_maps, "UERRA_NumDaysTempExceeded_comparison.png"))
../../../../_images/36f0182e43ff673922a5299f1f0890073af31006b9b455f33ae41b509a6d25cb.png

Maps of the percentiles of extreme temperature#

percentiles = [95., 99.9]

TempPercentile_arrays = {}
global_min_TempPercentile =  np.inf
global_max_TempPercentile = -np.inf

for percentile in percentiles:
    perc_filename = str(percentile).rstrip("0").replace(".", "")
    TempPercentile = xr.open_dataarray(os.path.join(indicators_path, f"Temp_P{perc_filename}.nc"))
    TempPercentile_arrays[percentile] = TempPercentile
    # Keep track of max and min values for colorbar scaling
    global_min_TempPercentile = np.nanmin([global_min_TempPercentile, np.nanmin(TempPercentile.values)])
    global_max_TempPercentile = np.nanmax([global_max_TempPercentile, np.nanmax(TempPercentile.values)])

print(f"Global min: {global_min_TempPercentile}, Global max: {global_max_TempPercentile}")
Global min: 10.918024063110352, Global max: 47.45762634277344
fig, axs = plt.subplots(nrows=1, ncols=2, figsize=(11, 5), subplot_kw={'projection': ccrs.PlateCarree()})
fig.suptitle('Maximum Temperature (UERRA)', fontweight='bold')

plot_kwargs = {
    'cmap': 'Reds',
    'vmin': global_min_TempPercentile,
    'vmax': global_max_TempPercentile,
    'transform': ccrs.PlateCarree()
}
for ax, percentile in zip(axs, percentiles):
    configure_map(ax, title=f'{percentile} Percentile')
    da = TempPercentile_arrays[percentile]
    im = ax.pcolormesh(da['longitude'], da['latitude'], da.values, **plot_kwargs)

fig.colorbar(im, ax=axs, orientation='horizontal', fraction=0.05, pad=0.1, label='Temperature [°C]')

fig.savefig(os.path.join(output_maps, "UERRA_Temp_percentiles_comparison.png"))
../../../../_images/17ef1d6059d2beeb68ec9c218bf4c04d0deeb8350fc15035564310f4f00a9a00.png

Maps of Percentiles 99, 99.5 and 99.9 of Precipitation#

percentiles = [99., 99.5, 99.9]

PrecipPercentile_arrays = {}
global_min_PrecipPercentile =  np.inf
global_max_PrecipPercentile = -np.inf

for percentile in percentiles:
    perc_filename = str(percentile).rstrip("0").replace(".", "")
    PrecipPercentile = xr.open_dataarray(os.path.join(indicators_path, f"Precip_P{perc_filename}.nc"))
    PrecipPercentile_arrays[percentile] = PrecipPercentile
    # Keep track of max and min values for colorbar scaling
    global_min_PrecipPercentile = np.nanmin([global_min_PrecipPercentile, np.nanmin(PrecipPercentile.values)])
    global_max_PrecipPercentile = np.nanmax([global_max_PrecipPercentile, np.nanmax(PrecipPercentile.values)])

print(f"Global min: {global_min_PrecipPercentile}, Global max: {global_max_PrecipPercentile}")
Global min: 14.556718826293945, Global max: 143.30715942382812
fig, axs = plt.subplots(nrows=1, ncols=3, figsize=(16, 5), subplot_kw={'projection': ccrs.PlateCarree()})
fig.suptitle('Percentile of Extreme Precipitation (UERRA)', fontweight='bold')

plot_kwargs = {
    'cmap': 'Blues',
    'vmin': global_min_PrecipPercentile,
    'vmax': global_max_PrecipPercentile,
    'transform': ccrs.PlateCarree()
}
for ax, percentile in zip(axs, percentiles):
    configure_map(ax, title=f'{percentile} Percentile')
    da = PrecipPercentile_arrays[percentile]
    im = ax.pcolormesh(da['longitude'], da['latitude'], da.values, **plot_kwargs)

fig.colorbar(im, ax=axs, orientation='horizontal', fraction=0.05, pad=0.1, label='Precipitation [mm/day]')

fig.savefig(os.path.join(output_maps, "UERRA_Precip_percentile_comparison.png"))
../../../../_images/bbda518b295a23313f4162338409d9e809a5efb917dc7cf67843c776b00edc34.png

Maps of Return Levels based on the Return Periods 10, 20, 30, 50, 100, 150 years#

return_ds = xr.open_dataset(os.path.join(indicators_path, 'return_levels_gumbel.nc'))
return_periods = [10, 20, 30, 50, 100, 150]

global_min_ReturnPeriod = np.min([return_ds[f"return_period_{period}_y"].min() for period in return_periods])
global_max_ReturnPeriod = np.max([return_ds[f"return_period_{period}_y"].max() for period in return_periods])

print(f"Global min: {global_min_ReturnPeriod}, Global max: {global_max_ReturnPeriod}")
Global min: 33.809383392333984, Global max: 246.80722045898438
fig, axs = plt.subplots(nrows=2, ncols=3, figsize=(16, 9), subplot_kw={'projection': ccrs.PlateCarree()})
fig.suptitle('Precipitation Levels from Return Periods (UERRA)', fontweight='bold')


plot_kwargs = {
    'cmap': 'Blues',
    'vmin': global_min_ReturnPeriod,
    'vmax': global_max_ReturnPeriod,
    'transform': ccrs.PlateCarree()
}
for ax, period in zip(axs.flatten(), return_periods):
    configure_map(ax, title=f'Return period {period} years')
    da = return_ds[f"return_period_{period}_y"]
    im = ax.pcolormesh(da['longitude'], da['latitude'], da.values, **plot_kwargs)

fig.colorbar(im, ax=axs, orientation='horizontal', fraction=0.05, pad=0.1, label='Precipitation Levels [mm]')

fig.savefig(os.path.join(output_maps, "UERRA_returnPeriod_comparison.png"))
../../../../_images/2818f0d405e1fc4d0afe23f1f3d34adf9ba2ae0271be33760d2af4c05a7e0d64.png