Plotting Geospatial Data with Cartopy | by Andrew Udell | Towards Data Science

With the age of big data comes the age of big geospatial data. Researchers increasingly have access to geographic information which can do anything from track the migration patterns of endangered species to map every donut shop in the country.
To help visualize this information, the python library Cartopy can create professional and publishable maps with only a few lines of code. Built with Matplotlib in mind, its syntax is familiar and easy to understand.
To start, we’ll create the simplest possible world map. Before writing any heavy code, the Cartopy and Matplotlib libraries in python should be installed.
import cartopy.crs as crsimport cartopy.feature as cfeatureimport matplotlib.pyplot as plt
Above, the prerequisite libraries are imported and ready to use.
# Initialize the figurefigure = plt.figure(figsize=(8,6))# use the Mercator projectionax = figure.add_subplot(1,1,1, projection=crs.Mercator(())# Add feature to the mapax.stock_img()plt.show()
The next few lines of code go through the basic process of creating a map:
Initialize the map and specify the size of the figure with the figsize argumentAdd a subplot which specifies the projection usedAdd features to the subplot
Initialize the map and specify the size of the figure with the figsize argument
Add a subplot which specifies the projection used
Add features to the subplot
With only a few lines of codes, the bare minimum for a map is created. Unfortunately, this map is rather bland, so we’ll add some extra features to it.
figure = plt.figure(figsize=(8,6))ax = figure.add_subplot(1,1,1, projection=crs.Mercator())# adds a stock image as a backgroundax.stock_img()# adds national bordersax.add_feature(cfeature.BORDERS)# add coastlinesax.add_feature(cfeature.COASTLINE)plt.show()
By modifying the variable ax, more information is added to the map. In this case, national borders and coastlines are drawn. Additional features, such as major rivers and lakes map also be included with the same method. A full list of features can be found here.
The above maps use the famous Mercator projection. While perfectly sufficient in most cases, Mercator map distorts land sizes because it stretches a sphere onto a square. Luckily, Cartopy supports other projections.
figure = plt.figure(figsize=(8,6))# set the projection to Mollweideax = figure.add_subplot(1,1,1, projection=crs.Mollweide())ax.stock_img()plt.show()
By changing the projection argument from crs.Mercator() to crs.Molleweide(), a different, more elliptical (and accurate) projection is created.
figure = plt.figure(figsize=(8,6))# Set the projection to Interrupted Goode Homolosineax = figure.add_subplot(1,1,1, projection=crs.InterruptedGoodeHomolosine())ax.stock_img()plt.show()
An even more accurate projection can be produced by using InterruptedGoodeHomolosine() in the projection argument.
These are by no means the only projections Cartopy can map. A full list can be found here.
While world maps are useful in many contexts, oftentimes data needs to be represented in a local area, such as a continent or a country.
figure = plt.figure(figsize=(8,6))ax = figure.add_subplot(1,1,1, projection=crs.Mercator())ax.add_feature(cfeature.COASTLINE)ax.add_feature(cfeature.STATES)# Zoom in on the US by setting longitude/latitude parametersax.set_extent(    [        -135, # minimum latitude        -60, # min longitude        20, # max latitude        55 # max longitude    ],    crs=crs.PlateCarree())plt.show()
After the map is initialized and the usual features are added, the ax variable is additionally modified with the set_extent() method, which specifies the ranges of longitude and latitude to set the focus on the map.
Note the argument crs, which specifies which coordinate system to use. The general convention is to use the coordinates of the Plate Carrée projection even if it disagrees with the projection of the map, because it produces more predictable results.
So far, we’ve only talked about producing generic maps, but now we’ll discussing plotting data onto those maps. The only requirement is that each observation have a valid latitude and longitude. To demonstrate, a source file of 341 airports from the US is taken from Kaggle and will be plotted on a scatter map.
import pandas as pd# Read the datadf = pd.read_csv("airports.csv")
Before any mapping is done, the Pandas library is imported to structure data and the CSV file is read into a DataFrame.
figure = plt.figure(figsize=(8,6))ax = figure.add_subplot(1,1,1, projection=crs.PlateCarree())ax.add_feature(cfeature.COASTLINE)ax.add_feature(cfeature.STATES)ax.set_extent(    [-135, -60, 20, 55],    crs=crs.PlateCarree())# modify the plot by adding a scatterplot over the mapplt.scatter(    x=df["LONGITUDE"],    y=df["LATITUDE"],    color="red",    s=4,    alpha=1,    transform=crs.PlateCarree())plt.show()
Essentially, after creating a map, Matplotlib adds a scatterplot on top of the image. To those familiar with the popular graphing library, the syntax should look very familiar. To those who aren’t, the breakdown of the arguments are:
x: the data on the x-axis. In this case, longitude
y: the data on the y-axis. In this case, latitude
color: the color of the markers
s: the size of the markers
alpha: the transparency of the markers, from 0 to 1
Additional arguments may be passed on the scatterplot to customize it further. A full list may be found here.
Also note the transform argument, which, by convention, uses the Plate Carrée projection for a similar reason as set_extent().
Cartopy is a diverse map library. Allowing for various projections and coordinate systems, it supports a wide range of possible use cases from ecological tracking to business intelligence.
Its integration with Matplotlib, however, stands out as an incredible data analysis tool. While only a simple scatter map was demonstrated, its broad and flexible use of Matplotlib means a diverse number of plots and graphs may be projected onto a map.