Improving maps with Cartopy#

Cartopy is a library for creating plots on maps. We can use it to improve Xarray’s plots (see plotting basics for the basics of Xarray plotting)

Let’s load the data we used in the last page, surface temperature for the ACCESS1.0 AMIP run March 1984:

%matplotlib inline
import xarray
datapath = "http://dapds00.nci.org.au/thredds/dodsC/rr3/CMIP5/output1/CSIRO-BOM/ACCESS1-0/amip/mon/atmos/Amon/r1i1p1/latest/tas/tas_Amon_ACCESS1-0_amip_r1i1p1_197901-200812.nc"
data = xarray.open_dataset(datapath)
surface_temp_slice = data.tas.sel(time = '1984-03')
surface_temp_slice.plot()
<matplotlib.collections.QuadMesh at 0x7f0abc9dee80>
../_images/bb748f8480401ebb421449d14e3b5085783c5a86918697cb1eecbd557ce08d94.png

Projections#

Cartopy is based around projecting the data in different ways. To use it, we create an axis with a specific projection, then add plots onto that axis.

Note that we don’t need to tell the plot command about our co-ordinates, Xarray does that automatically for us

import cartopy.crs as ccrs
import matplotlib.pyplot as plt

ax = plt.axes(projection=ccrs.PlateCarree())

surface_temp_slice.plot(ax=ax)
<matplotlib.collections.QuadMesh at 0x7f0aaeb45dd8>
../_images/a2ae2f73700043b7aebe54bb765320015073b126e72ec503cf198a5b53ef9575.png

Cartopy has a bunch of different projections that you can use.

If the data is in a different projection to the axis it’s important to give a transform to plot(). Our data is on a lat-lon grid, so we need to tell Cartopy to transform it from a PlateCarree projection to LambertConfromal

ax = plt.axes(projection=ccrs.LambertConformal())

surface_temp_slice.plot(ax=ax, transform=ccrs.PlateCarree())
<matplotlib.collections.QuadMesh at 0x7f0aae197518>
../_images/abbb69d1a2bdb105db172408c3a40ed06fe95c4e28d894fe78500b73c3685bc5.png

Cartopy also has some helper functions for showing coastlines etc., which can make it easier to interpret a plot. These work regardless of what projection you are using

ax = plt.axes(projection=ccrs.Orthographic())

surface_temp_slice.plot(ax=ax, transform=ccrs.PlateCarree())

ax.coastlines()
<cartopy.mpl.feature_artist.FeatureArtist at 0x7f0aada05390>
../_images/a325ccbe72c279fdf6c2f031e4722d1e3aec60d4988da5d65bb4f1aaf5a72c84.png

To restrict the plot’s domain you can use ax.set_extent():

import cartopy.crs as ccrs
import matplotlib.pyplot as plt

ax = plt.axes(projection=ccrs.NearsidePerspective(central_latitude=-20, central_longitude=120))

surface_temp_slice.plot(ax=ax, transform=ccrs.PlateCarree())

ax.coastlines()
ax.set_extent([100,160,-45,0])
../_images/30c4721a2b73143bab847b2ca27c6717a3bd9f468795faa9513b08eb6cb58e42.png