Skip to article frontmatterSkip to article content

Calculating climate normals of temperature and precipitation

This notebook shows how to calculate monthly climate normals for temperature and precipitation for districts in Sierra Leone based on data from ERA5-Land. Climate normals (see definition) are used as a baseline to evaluate year-to-year variability for weather and climate.

We will use earthkit, xarray and pandas (both included in earthkit) to perform the analysis.

import earthkit.data
from earthkit import transforms

Loading climate data

Use earthkit.data to load a NetCDF file containing monthly temperature and precipitation values since 1990:

file = "../data/era5-land-monthly-temp-precip-1990-2025-sierra-leone.nc"
data = earthkit.data.from_source("file", file)

This file was downloaded from the “ERA5-Land monthly averaged data from 1950 to present” dataset. See this tutorial for how to download data from the Climate Data Store.

We convert the data returned to an xarray dataset and display the contents:

dataset = data.to_xarray()
dataset
Loading...

The dataset is covering Sierra Leone, and contains two data variables:

  • t2m: Temperature 2m above surface

  • tp: Total precipitation

The spatial resoulution for this gridded dataset is approximately 9x9 km, and the temporal resolution is monthly values.

We can drop the variables that we don’t need in our analysis. We will keep time (valid_time) and space (latitude and longitude) dimensions.

dataset_clean = dataset.drop_vars(['number', 'expver'])

Calculate climate normals

To calculate climate normals we need to select the 30 years reference period (1991-2020).

dataset_period = dataset_clean.sel(valid_time=slice('1991-01-01', '2020-12-01'))

This will give us 30 years of montly data. We can check that the valid_time dimension has 360 items (30 years x 12 months).

dataset_period.dims
FrozenMappingWarningOnValuesAccess({'valid_time': 360, 'latitude': 33, 'longitude': 33})

Temperature normals

Before we can compute the temperature normal, we extract the temperature variable from the dataset (t2m), and make sure to subtract 273.15 to convert from kelvin to celcius.

temp = dataset_period['t2m'] - 273.15

To calculate the climate normal across the 30 year period, we group the data by calendar month (all Januaries, all Februaries, etc), and compute the mean across all years to obtain a single representative value for each calendar month.

temp_month = temp.groupby('valid_time.month').mean()

Precipitation

For precipitation normals, we need to make sure these are expressed in millimeters rather than meters and monthly totals rather than daily averages. We multiply each value by 1000 to go from meters to millimeters, and the numer of days per month to get the total precipitation for each month.

precip = dataset_period['tp'] * 1000 * dataset_period.valid_time.dt.days_in_month

We can now calculate the mean precipitation for each of the 12 calendar month across all years.

precip_month = precip.groupby('valid_time.month').mean()

Climate normals for districts

The last step is to calculate the climate normals for each district in Sierra Leone. First we need to load the districts from a GeoJSON file downloaded from DHIS2 Maps.

district_file = "../data/sierra-leone-districts.geojson"
features = earthkit.data.from_source("file", district_file)

To aggregate the temperature data to the org unit features we use the spatial.reduce function of earthkit-transforms, to get the spatial average of temperature normals in each org unit. See this notebook for more information.

temp_agg = transforms.spatial.reduce(temp_month, features, mask_dim="id", how='mean')

We can convert the result to a dataframe to display the normal temperature in degrees celcius for each month (1-12).

temp_df = temp_agg.to_dataframe()
temp_df.loc['O6uvpzGd5pu'] # Bo district
Loading...

We can do the same to calculate the spatial average of the normal monthly precipitation (mm) for each district:

precip_agg = transforms.spatial.reduce(precip_month, features, mask_dim="id", how='mean')
precip_df = precip_agg.to_dataframe()
precip_df.loc['O6uvpzGd5pu'] # Bo district
Loading...

If you have access to the DHIS2 Climate app you can check if the climate normals calculated are similar to the values calculated using Google Earth Engine.

See more examples from Copernicus Climate Change Service (C3S) of how to calculate climate normals.