Introduction¶
The Australian Synoptic Weather Types (SWTs) are set of 30 distinct circulation patterns over the Australian continent that characterise the weather over Australia. The dataset is generated from ERA5 reanalysis data by k-means clustering the 12z 850hPa wind field, producing a daily characterisation of the continent-wide circulation. Barnes et. al 2025 describes the synoptic weather types and their characteristics in more detail.

Mean sea level pressure (black contours at 4 hPa intervals, vertically integrated water vapour greater than 48 (green shading) and wind speed greater than 20 (blue shading), 315 K (solid magenta) and 330 K (dashed magenta) 2 potential vorticity unit (PVU, 1 PVU = ) contour. Closed lows (blue L) and highs (red H) in the mean sea level pressure field are also shown.
This notebook provides an overview of the tools and usage of the SWTs, including opening and using the climatology and some basic plotting tools and use cases. Most notably, one can assign any 850hPa gridded wind field to a SWT, allowing users to use the SWT framework in most gridded model datasets. The full set of tools is provided and continually updated in the Australian Synoptic Weather Types repository.
import os
from datetime import datetime
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import xarray as xr
from cartopy.feature import LAND
from swt_assign import assign_grid_to_SWT
from swt_plotting import SWTcolors, plot_synoptic_PVless_ERA5
import warnings
warnings.filterwarnings("ignore")Datasets¶
# Download the data, it can take a few minutes
!python download_swt.pyOpen the climatology of SWTs. The data is stored both in a netcdf and csv format called SWT_climatology.nc or SWT_climatology.csv. Includes daily SWTs from January 1952 to April 2026 and is based on the ERA5 850hPa u and v wind fields. Previous versions of this climatology are additionally available in the Australian Synoptic Weather Types repository.
SWT_climatology = xr.open_dataset("data/SWT_climatology.nc")
SWT_climatologyOpen the SWT dataset. This dataset comprises of the original set of 30 SWTs as described in Barnes et. al 2025 together with the wind centroids required in order to assign a grid to a SWT.
The data is stored as netcdf called SWT_data.nc.
SWT_data = xr.open_dataset("data/SWT_data.nc")
SWT_dataHandling the SWT dataset¶
Plot a synoptic composite from ERA5 together with the relevant SWT code for 01/09/2025. Various plotting options are available within the Australian Synoptic Weather Types repository!
indt = datetime(2025, 9, 1, 12)
indt_SWT = SWT_climatology.sel(time=indt).assigned_SWT.item()
plot_synoptic_PVless_ERA5(indt_SWT, indt)
Seasonal distribution of SWTs¶
Here we will plot the running mean seasonal distribution of the SWTs centred on the summer months to show how the SWTs change seasonally. We will use the SWT_climatology.nc dataset.
inrundays = 15 # Days to use for the running mean
SWT_climatology = SWT_climatology.sel(time=slice(datetime(1900, 1, 1), datetime(2025, 1, 1, 0)))
SWTnames = SWT_climatology.SWTs # Get the names of the 30 synoptic types in teh typical order
cluster_series = (
SWT_climatology.assigned_SWT
) # Get the assigned daily SWT codes in the climatology
cluster_series.coords["mmdd"] = cluster_series["time"].dt.strftime(
"%m%d"
) # Get the day-month
grouped = cluster_series.groupby("mmdd") # Group by the day and month
mmdds = list(grouped.groups.keys())
mmdds.remove("0229") # Remove the extra leap year dates
def periodic_rolling_sum_centered(arr, window):
arr = np.asarray(arr)
pad = window // 2
padded = np.pad(arr, (pad, pad), mode="wrap")
kernel = np.ones(window, dtype=arr.dtype)
out = np.convolve(padded, kernel, mode="valid")
# If window is even, trim to original length
return out[: len(arr)]We need to reorder and reorganise the data to prepare for plotting the climatology centered in the summer months.
reorder_st = np.where(np.array(mmdds) == "0801")[0][0]
mmdds = mmdds[reorder_st::] + mmdds[0:reorder_st]
cluster_labels = np.zeros((len(set(SWT_climatology.time.dt.year.values)), len(mmdds)))
cluster_spread = np.zeros((len(SWTnames), len(mmdds)))
for i, mmdd in enumerate(mmdds):
selected_group = grouped.groups[mmdd]
temp = cluster_series.isel(time=selected_group)
cluster_labels[:, i] = xr.DataArray(
pd.Categorical(temp.values, categories=SWTnames).codes,
coords=temp.coords,
dims=temp.dims,
name="assigned_SWT_index",
)
for it, t in enumerate(range(cluster_labels.shape[1])):
for im, m in enumerate(range(cluster_labels.shape[0])):
SWTindex = int(cluster_labels[im, it])
cluster_spread[SWTindex, it] = cluster_spread[SWTindex, it] + 1
for im in range(cluster_spread.shape[0]):
cluster_spread[im, :] = periodic_rolling_sum_centered(
cluster_spread[im, :], inrundays
)
cluster_spread_freq = cluster_spread / (
inrundays * len(set(SWT_climatology.time.dt.year.values))
)
datetimes = [datetime.strptime(mmdd, "%m%d") for mmdd in mmdds]
month_ticks = [i for i, date in enumerate(datetimes) if date.day == 1]
month_ticklabels = [datetimes[m].strftime("%b") for m in month_ticks]# Plot the seasonal distribution climatology as a timeseries
fig, ax = plt.subplots(figsize=(15, 8))
# Number of bars (columns)
num_bars = cluster_spread_freq.shape[1]
x = np.arange(num_bars)
bottom = np.zeros(num_bars)
regticks = [4, 6, 11, 14, 17, 19, 25]
for i, (row, color) in enumerate(zip(cluster_spread_freq, SWTcolors)):
# Draw the bar
bars = plt.bar(
x,
row,
bottom=bottom,
color=color,
label=SWTnames.values[i],
edgecolor=color, # removes outline
linewidth=1, # extra safety
)
bottom += row
ax.legend(loc="upper right", bbox_to_anchor=(1.10, 1.025), ncols=1)
xticks = ax.set_xticks(month_ticks)
xticklabs = ax.set_xticklabels(month_ticklabels, rotation=90)
ax.set_xlabel("Day of the Year")
ax.tick_params(length=0)
ax.grid(axis="x", color="k", linestyle="-", linewidth=2)
ax.set_xlim([0, len(datetimes)])
plt.show()
Assigning a 850hPa wind field to a SWT¶
The Australian Synoptic Weather Types repository hosts a set of tools to assign any gridded 850hPa wind field to a SWT. This is done by de assign_grid_to_SWT() function. The function handles xarray dataarrays of u and v wind fields and handle all grid interpolation. The result of running the function outputs the assigned SWT as a string and prints it out if required. Below is an example of using the assignment functionality using ECMWF IFS NWP data.
## Load the data
inpath = "data/"
ufn = inpath + "20250204120000-24h-enfo-ef_u_850_0.grib2"
u = xr.open_dataset(
ufn, engine="cfgrib", backend_kwargs={"indexpath": ""}, decode_timedelta=True
)
vfn = inpath + "20250204120000-24h-enfo-ef_v_850_0.grib2"
v = xr.open_dataset(
vfn, engine="cfgrib", backend_kwargs={"indexpath": ""}, decode_timedelta=True
)## Plot the 850hPa wind field to be assigned
u1 = u.reindex(latitude=list(reversed(u.latitude))).sel(
longitude=slice(80, 180), latitude=slice(-65, 0)
)
v1 = v.reindex(latitude=list(reversed(v.latitude))).sel(
longitude=slice(80, 180), latitude=slice(-65, 0)
)
fig, ax = plt.subplots(
1, 1, figsize=(10, 8), subplot_kw=dict(projection=ccrs.PlateCarree())
)
plot_extent = [90, 175, -60, -5]
ax.set_extent(plot_extent, crs=ccrs.PlateCarree())
ax.streamplot(
u1.longitude.values, u1.latitude.values, u1.u.values, v1.v.values, density=5
)
ax.add_feature(LAND, facecolor="lightgrey")
ax.coastlines(linewidths=0.4)
plt.show()
Below is an example of how to assign any gridded field to a SWT. The inputs expected are u and v-wind fields in xarray dataarray format. The function automatically interpolates the dataset to a 1.5-degree grid. If your data matches the grid provided in the the “SWT_data.nc” file, you can set interpolation=False to avoid this part of the process.
SWT = assign_grid_to_SWT(
u.u,
v.v,
latname="latitude",
lonname="longitude",
cluster_filename= "data/SWT_data.nc",
quiet=False,
)Synoptic Weather Type: AM-D
Printing the assign_grid_to_SWT() documentation to show its usage and inputs
print(assign_grid_to_SWT.__doc__)Assign a 850hPa wind field to a Australian Synoptic Weather Type
Created by Frans Liqui Lung (Monash University) and Michael A. Barnes (ARC CoE 21st Century Weather, Monash University)
Parameters
----------
u : xr.DataArray with shape (latitude,longitude) and dtype float64
The 850hPa zonal wind field.
v : xr.DataArray with shape (latitude,longitude) and dtype float64
The 850hPa meridional wind field.
Options
-------
latname : str (default: "latitude")
Name of the latitude variable name in the input u and v DataArrays
lonname : str (default: "longitude")
Name of the longitude variable name in the input u and v DataArrays
cluster_filename : str (default: "SWT_fields/SWT_data.nc")
Location of the netcdf containing the clustered SWT fields.
interpolate : bool (default: True)
If false, does not do any interpolation on the grid. Note: if false, grids must be exactly the same.
quiet : bool (default: False)
If false, prints out the SWT label, else simply and quietly returns the variables as specified.
silence_warning : bool (default: False)
If false, prints out any defined warnings (e.g. if NaNs are present), otherwise silences them.
Returns
-------
SWT : str
The Synoptic Weather Type code.
- Barnes, M. A., Lung, F. L., Jakob, C., Gunn, A., & Reeder, M. J. (2025). Australian Synoptic Weather Types. Journal of Geophysical Research: Atmospheres, 130(24). 10.1029/2025jd043873