The world’s leading publication for data science, AI, and ML professionals.

Plotting Geospatial Data with Cartopy

A Python library for making high quality static maps

Photo by Capturing the human heart. on Unsplash
Photo by Capturing the human heart. on Unsplash

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.

Simple Maps

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 crs
import cartopy.feature as cfeature
import matplotlib.pyplot as plt

Above, the prerequisite libraries are imported and ready to use.

# Initialize the figure
figure = plt.figure(figsize=(8,6))
# use the Mercator projection
ax = figure.add_subplot(1,1,1, projection=crs.Mercator(())
# Add feature to the map
ax.stock_img()
plt.show()
A textured world map. Figure produced by author.
A textured world map. Figure produced by author.

The next few lines of code go through the basic process of creating a map:

  1. Initialize the map and specify the size of the figure with the figsize argument
  2. Add a subplot which specifies the projection used
  3. 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 background
ax.stock_img()
# adds national borders
ax.add_feature(cfeature.BORDERS)
# add coastlines
ax.add_feature(cfeature.COASTLINE)
plt.show()
A world map with borders. Figure produced by author.
A world map with borders. Figure produced by author.

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.

Different Projections

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 Mollweide
ax = figure.add_subplot(1,1,1, projection=crs.Mollweide())
ax.stock_img()
plt.show()
The Mollweide projection. Figure produced by author.
The Mollweide projection. Figure produced by author.

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 Homolosine
ax = figure.add_subplot(1,1,1, projection=crs.InterruptedGoodeHomolosine())
ax.stock_img()
plt.show()
The Interrupted Goode Homolosine projection. Figure produced by author.
The Interrupted Goode Homolosine projection. Figure produced by author.

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.

Zooming in and out of Regions

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 parameters
ax.set_extent(
    [
        -135, # minimum latitude
        -60, # min longitude
        20, # max latitude
        55 # max longitude
    ],
    crs=crs.PlateCarree()
)
plt.show()
A simple map of the United States. Figure produced by author.
A simple map of the United States. Figure produced by author.

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 Carrée projection even if it disagrees with the projection of the map, because it produces more predictable results.

Scatter Maps

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 data
df = 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 map
plt.scatter(
    x=df["LONGITUDE"],
    y=df["LATITUDE"],
    color="red",
    s=4,
    alpha=1,
    transform=crs.PlateCarree()
)
plt.show()
Airports across the continental US. Figure produced by author.
Airports across the continental US. Figure produced by author.

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 Carrée projection for a similar reason as set_extent().

Conclusions

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.


Related Articles