Assignment: Characterising climate variability#
# Import the tools we are going to need today:
import matplotlib.pyplot as plt # plotting library
import numpy as np # numerical library
import xarray as xr # netCDF library
import cartopy # Map projections libary
import cartopy.crs as ccrs # Projections list
# Some defaults:
plt.rcParams['figure.figsize'] = (12, 5) # Default plot size
Temperature variability in ERA5#
Let’s read the temperature and invariant data files from last week:
ds = xr.open_dataset(r'../data/ERA5_LowRes_Monthly_t2m.nc')
ds_inv = xr.open_dataset(r'../data/ERA5_LowRes_Invariant.nc')
Global temperatures: variability over land and oceans#
Now compute and plot the annual average (not monthly) global temperature in °C.
This should be a time series.
💡 Tip: we did this in the lesson already — don’t forget the weights!
# Your answer here
Now compute the annual global mean temperature separately for land and ocean grid points. You can use the land–sea mask (ds_inv.lsm
, where 1
= land and 0
= sea) to select the appropriate grid cells (see lesson). Plot them on the same plot, with a legend.
💡 Tip: weighting masked data works exactly the same way as weighting unmasked data. You can apply the weights directly to masked fields.
# Your answer here
Interpret the plot.
# Your answer here
Now plot the temperature anomalies instead of the absolute temperatures. Use the 1979–1989 period as a reference, i.e. subtract the mean of those 11 years from each time series (global, land, and ocean). Plot the three anomaly time series on the same figure and add a legend.
💡 Tip: plotting anomalies instead of absolute values makes it easier to compare the warming trends over land and ocean, even if their baseline temperatures differ.
# Your answer here
Interpret the plot.
# Your answer here
So far, we’ve looked at long-term warming trends.
Now, try to remove the trend from the three anomaly time series (global, land, and ocean) to better highlight interannual variability.
You can detrend a time series in several ways — for example, by:
Fitting and subtracting a linear regression (using e.g.
scipy.stats.linregress
, which works well if the trend is linear)Using a high-pass filter or a rolling mean to isolate short-term fluctuations
⚡ This was not done in the lesson — you’ll need to do some research or use your favorite GenAI assistant to find the best method and syntax!
If you can’t figure it out, here is a suggested solution.
Once you’ve detrended the data, plot the results and comment briefly on what remains when the long term trend is removed. To better quantify variability, compute the standard deviation of the detrended time series. Comment.
# Your answer here
Variability in space#
Now repeat the analysis above, by starting again from the original dataset temperatures, and do not distinguish between land and ocean.
Compute the annual mean 2 m temperature over three increasingly smaller regions of your choice (from global to country level) — for example: Global, Europe, and Austria.
You can achieve this by selecting subset regions in your dataset, as demonstrated in the lesson.
Once again, don’t forget to apply the weights when computing the averages!
# Your answer here
Precipitation in ERA5#
Download the ERA5_LowRes_Monthly_tp
precipitation file.
Open the file with xarray and explore it. The units of monthly precipitation are wrongly labeled (unfortunately). They should read: m per day.
ds = xr.open_dataset('../data/ERA5_LowRes_Monthly_tp.nc')
ds.tp
<xarray.DataArray 'tp' (time: 552, latitude: 241, longitude: 480)> Size: 255MB [63855360 values with dtype=float32] Coordinates: * time (time) datetime64[ns] 4kB 1979-01-01T06:00:00 ... 2024-12-01T0... * latitude (latitude) float64 2kB 90.0 89.25 88.5 ... -88.5 -89.25 -90.0 * longitude (longitude) float64 4kB -179.6 -178.9 -178.1 ... 178.9 179.6 Attributes: long_name: Total precipitation units: m standard_name: unknown
Compute the average total annual precipitation (average precipitation over a year, in mm yr\(^{-1}\)) and store it in a variable called “annual_prcp”. Plot it.
# Your answer here
Draw a new plot of “annual_prcp”, this time with a new colormap (‘YlGnBu’) and with the following discrete levels specified: [50, 200, 500, 700, 1000, 1500, 2000, 3000, 5000]. Now have a look at the patterns again.
Where does it fall more than 3000 mm precipitation a year? Less than 50 mm precipitation a year? Note that it could be possible to use the “.where()” function (not taught yet) to highlight these areas easily. Bonus: can you come up with a plot showing these areas on the map?
# Your answer here
Now plot the average precipitation in January on a map. Do the same with precipitation in July, and choose the same levels for both maps in order to compare them. Discuss the patterns that you see.
# Your answer here
Now let’s explore precipitation variability instead of the mean. Compute the annual mean precipitation (in mm yr⁻¹) from your monthly data using resample
as usual. This gives you one precipitation value per year at each grid cell, i.e. a 3D array of dimensions (time (years), latitude, longitude). Then, calculate the standard deviation of these annual means across all years. This shows how much precipitation varies from year to year at each location.
Plot the resulting map of precipitation variability (standard deviation) using a suitable colormap (e.g. 'YlGnBu'
), and label your colorbar (e.g. “mm yr⁻¹”). Don’t forget to add coastlines, gridlines, and a descriptive title.
Interpret this map, especially in comparison to the annual mean precipitation map.
# Your answer here
Bonus: Coefficient of Variation (CV)
As a final step, compute the coefficient of variation (CV) of annual precipitation.
This older (and somewhat outdated) metric expresses variability relative to the mean.
Use your annual precipitation data from the previous step.
Compute the CV as:
[ \text{CV} = \frac{\text{standard deviation}}{\text{mean}} ]Plot a global map of the CV (no units — it’s a ratio).
💡 Tip:
The CV can highlight regions where precipitation is highly variable relative to the mean, such as deserts.
Be careful: dividing by very small means (near-zero precipitation) can produce extremely large or noisy values, so you might want to mask out those regions (e.g. where mean precipitation < 50 mm yr⁻¹).
# Your answer here