02_Xarray: Plotting#
Overview#
Work with an Xarray
Dataset
Select a variable from the dataset
Create a contour plot of gridded ERA5 reanalysis data
Imports#
import xarray as xr
import pandas as pd
import numpy as np
from metpy.units import units
import metpy.calc as mpcalc
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib.pyplot as plt
Work with an Xarray Dataset
#
An Xarray Dataset consists of one or more DataArray
s. Let’s continue to work with the ERA5 NetCDF file from the previous notebook.
ds = xr.open_dataset('/spare11/atm350/data/199303_era5.nc')
Examine the SLP dataset
ds
<xarray.Dataset> Size: 7GB Dimensions: (latitude: 721, level: 13, longitude: 1440, time: 124) Coordinates: * latitude (latitude) float32 3kB 90.0 89.75 ... -89.75 -90.0 * level (level) int64 104B 50 100 150 200 ... 850 925 1000 * longitude (longitude) float32 6kB 0.0 0.25 ... 359.5 359.8 * time (time) datetime64[ns] 992B 1993-03-01 ... 1993-0... Data variables: geopotential (time, level, latitude, longitude) float32 7GB ... mean_sea_level_pressure (time, latitude, longitude) float32 515MB ...
One attribute of a dataset is its size. We can access that via its nbytes
attribute.
print (f'Size of dataset: {ds.nbytes / 1e9} GB')
Size of dataset: 7.2095483 GB
Select a variable from the dataset and assign it to a DataArray
object
slp = ds['mean_sea_level_pressure']
slp
<xarray.DataArray 'mean_sea_level_pressure' (time: 124, latitude: 721, longitude: 1440)> Size: 515MB [128741760 values with dtype=float32] Coordinates: * latitude (latitude) float32 3kB 90.0 89.75 89.5 ... -89.5 -89.75 -90.0 * longitude (longitude) float32 6kB 0.0 0.25 0.5 0.75 ... 359.2 359.5 359.8 * time (time) datetime64[ns] 992B 1993-03-01 ... 1993-03-31T18:00:00 Attributes: long_name: Mean sea level pressure short_name: msl standard_name: air_pressure_at_mean_sea_level units: Pa
Create a contour plot of gridded data#
We got a quick plot in the previous notebook. Let’s now customize the map, and focus on a particular region. We will use Cartopy and Matplotlib to plot our SLP contours. Matplotlib has two contour methods:
We will draw contour lines in hPa, with a contour interval of 4.
As we’ve done before, let’s first define some variables relevant to Cartopy.#
The dataset’s x- and y- coordinates are longitude and latitude … thus, its projection is Plate Carree. However, we wish to display the data on a regional map that uses Lambert Conformal. So we will define two Cartopy projection objects here. We will need to transform the data from its native projection to the map’s projection when it comes time to draw the contours.
latN = 55
latS = 20
lonW = -90
lonE = -60
cLon = (lonW + lonE ) / 2
cLat = (latS + latN ) / 2
proj_data = ccrs.PlateCarree() # Our data is lat-lon; thus its native projection is Plate Carree.
proj_map = ccrs.LambertConformal(central_longitude=cLon, central_latitude=cLat) # Map projection
res = '50m'
Now define the range of our contour values and a contour interval. 4 hPa is standard for a sea-level pressure map on a synoptic-scale region.#
minVal = 900
maxVal = 1076
cint = 4
cintervals = np.arange(minVal, maxVal, cint)
cintervals
array([ 900, 904, 908, 912, 916, 920, 924, 928, 932, 936, 940,
944, 948, 952, 956, 960, 964, 968, 972, 976, 980, 984,
988, 992, 996, 1000, 1004, 1008, 1012, 1016, 1020, 1024, 1028,
1032, 1036, 1040, 1044, 1048, 1052, 1056, 1060, 1064, 1068, 1072])
Matplotlib’s contour methods require three arrays to be passed to them … x- and y- arrays (longitude and latitude in our case), and a 2-d array (corresponding to x- and y-) of our data variable. So we need to extract the latitude and longitude coordinate variables from our DataArray. We’ll also extract the third coordinate value, time.#
lats = ds.latitude
lons = ds.longitude
times = ds.time
Let’s use Xarray’s sel
method to specify one time from the DataArray
.
slp_singleTime = slp.sel(time='1993-03-14-18:00:00')
slp_singleTime
<xarray.DataArray 'mean_sea_level_pressure' (latitude: 721, longitude: 1440)> Size: 4MB [1038240 values with dtype=float32] Coordinates: * latitude (latitude) float32 3kB 90.0 89.75 89.5 ... -89.5 -89.75 -90.0 * longitude (longitude) float32 6kB 0.0 0.25 0.5 0.75 ... 359.2 359.5 359.8 time datetime64[ns] 8B 1993-03-14T18:00:00 Attributes: long_name: Mean sea level pressure short_name: msl standard_name: air_pressure_at_mean_sea_level units: Pa
Note the units are in Pascals. We will exploit MetPy’s unit conversion library soon, but for now let’s just divide the array by 100.
slp_singleTimeHPA = slp_singleTime / 100
We’re set to make our map. After creating our figure, setting the bounds of our map domain, and adding cartographic features, we will plot the contours. We’ll assign the output of the contour method to an object, which will then be used to label the contour lines.#
fig = plt.figure(figsize=(18,12))
ax = plt.subplot(1,1,1,projection=proj_map)
ax.set_extent ([lonW,lonE,latS,latN])
ax.add_feature(cfeature.COASTLINE.with_scale(res))
ax.add_feature(cfeature.STATES.with_scale(res))
CL = ax.contour(lons,lats,slp_singleTimeHPA,cintervals,transform=proj_data,linewidths=1.25,colors=['green','red','red'])
ax.clabel(CL, inline_spacing=0.2, fontsize=11, fmt='%.0f');

fig
