Visualizing Geographic Data with Matplotlib: A Beginner’s Guide

Geographic data, or geospatial data, is all around us! From the weather forecast showing temperature across regions to navigation apps guiding us through city streets, understanding location-based information is crucial. Visualizing this data on a map can reveal fascinating patterns, trends, and insights that might otherwise remain hidden.

In this blog post, we’ll dive into how you can start visualizing geographic data using Python’s powerful Matplotlib library, along with a helpful extension called Cartopy. Don’t worry if you’re new to this; we’ll break down everything into simple, easy-to-understand steps.

What is Geographic Data Visualization?

Geographic data visualization is essentially the art of representing information that has a physical location on a map. Instead of just looking at raw numbers in a table, we can plot these numbers directly onto a map to see how different values are distributed geographically.

For example, imagine you have a list of cities with their populations. Plotting these cities on a map, perhaps with larger dots for bigger populations, instantly gives you a visual understanding of population density across different areas. This kind of visualization is incredibly useful for:
* Identifying spatial patterns.
* Understanding distributions.
* Making data-driven decisions based on location.

Your Toolkit: Matplotlib and Cartopy

To create beautiful and informative maps in Python, we’ll primarily use two libraries:

Matplotlib

Matplotlib is the foundation of almost all plotting in Python. Think of it as your general-purpose drawing board. It’s excellent for creating line plots, scatter plots, bar charts, and much more. However, by itself, Matplotlib isn’t specifically designed for maps. It doesn’t inherently understand the spherical nature of Earth or how to draw coastlines and country borders. That’s where Cartopy comes in!

Cartopy

Cartopy is a Python library that extends Matplotlib’s capabilities specifically for geospatial data processing and plotting. It allows you to:
* Handle various map projections (we’ll explain this soon!).
* Draw geographical features like coastlines, country borders, and rivers.
* Plot data onto these maps accurately.

In essence, Matplotlib provides the canvas and basic drawing tools, while Cartopy adds the geographical context and specialized map-drawing abilities.

What are Map Projections?

The Earth is a sphere (or more accurately, an oblate spheroid), but a map is flat. A map projection is a mathematical method used to transform the curved surface of the Earth into a flat 2D plane. Because you can’t perfectly flatten a sphere without stretching or tearing it, every projection distorts some aspect of the Earth (like shape, area, distance, or direction). Cartopy offers many different projections, allowing you to choose one that best suits your visualization needs.

What is a Coordinate Reference System (CRS)?

A Coordinate Reference System (CRS) is a system that allows you to precisely locate geographic features on the Earth. The most common type uses latitude and longitude.
* Latitude lines run east-west around the Earth, measuring distances north or south of the Equator.
* Longitude lines run north-south, measuring distances east or west of the Prime Meridian.
Cartopy uses CRSs to understand where your data points truly are on the globe and how to project them onto a 2D map.

Getting Started: Installation

Before we can start drawing maps, we need to install the necessary libraries. Open your terminal or command prompt and run the following commands:

pip install matplotlib cartopy

This command will download and install both Matplotlib and Cartopy, along with their dependencies.

Your First Map: Plotting Data Points

Let’s create a simple map that shows the locations of a few major cities around the world.

1. Prepare Your Data

For this example, we’ll manually define some city data with their latitudes and longitudes. In a real-world scenario, you might load this data from a CSV file, a database, or a specialized geographic data format.

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

cities_data = {
    'City': ['London', 'New York', 'Tokyo', 'Sydney', 'Rio de Janeiro', 'Cairo'],
    'Latitude': [51.5, 40.7, 35.7, -33.9, -22.9, 30.0],
    'Longitude': [-0.1, -74.0, 139.7, 151.2, -43.2, 31.2]
}

df = pd.DataFrame(cities_data)

print(df)

Output of print(df):

               City  Latitude  Longitude
0            London      51.5       -0.1
1          New York      40.7      -74.0
2             Tokyo      35.7      139.7
3            Sydney     -33.9      151.2
4    Rio de Janeiro     -22.9      -43.2
5             Cairo      30.0       31.2

Here, we’re using pandas to store our data in a structured way, which is common in data analysis. If you don’t have pandas, you can install it with pip install pandas. However, for this simple example, you could even use plain Python lists.

2. Set Up Your Map with a Projection

Now, let’s create our map. We’ll use Matplotlib to create a figure and an axis, but importantly, we’ll tell this axis that it’s a Cartopy map axis by specifying a projection. For global maps, the PlateCarree projection is a good starting point as it represents latitudes and longitudes as a simple grid, often used for displaying data that is inherently in latitude/longitude coordinates.

fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
  • plt.figure(figsize=(10, 8)): Creates a new blank window (figure) for our plot, with a size of 10 inches by 8 inches.
  • fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree()): This is the core step. It adds a single plotting area (subplot) to our figure. The crucial part is projection=ccrs.PlateCarree(), which tells Matplotlib to use Cartopy’s PlateCarree projection for this subplot, effectively turning it into a map.

3. Add Geographical Features

A map isn’t complete without some geographical context! Cartopy makes it easy to add features like coastlines and country borders.

ax.add_feature(cartopy.feature.COASTLINE) # Draws coastlines
ax.add_feature(cartopy.feature.BORDERS, linestyle=':') # Draws country borders as dotted lines
ax.add_feature(cartopy.feature.LAND, edgecolor='black') # Colors the land and adds a black border
ax.add_feature(cartopy.feature.OCEAN) # Colors the ocean
ax.gridlines(draw_labels=True, dms=True, x_inline=False, y_inline=False) # Adds latitude and longitude grid lines
  • ax.add_feature(): This function is how you add predefined geographical features from Cartopy.
  • cartopy.feature.COASTLINE, cartopy.feature.BORDERS, cartopy.feature.LAND, cartopy.feature.OCEAN: These are built-in feature sets provided by Cartopy.
  • ax.gridlines(draw_labels=True): This adds grid lines for latitude and longitude, making it easier to read coordinates. dms=True displays them in degrees, minutes, seconds format, and x_inline=False, y_inline=False helps prevent labels from overlapping.

4. Plot Your Data Points

Now, let’s put our cities on the map! We’ll use Matplotlib’s scatter function, but with a special twist for Cartopy.

ax.scatter(df['Longitude'], df['Latitude'],
           color='red', marker='o', s=100,
           transform=ccrs.PlateCarree(),
           label='Major Cities')

for index, row in df.iterrows():
    ax.text(row['Longitude'] + 3, row['Latitude'] + 3, row['City'],
            transform=ccrs.PlateCarree(),
            horizontalalignment='left',
            color='blue', fontsize=10)
  • ax.scatter(df['Longitude'], df['Latitude'], ..., transform=ccrs.PlateCarree()): This plots our city points. The transform=ccrs.PlateCarree() argument is extremely important. It tells Cartopy that the Longitude and Latitude values we are providing are in the PlateCarree coordinate system. Cartopy will then automatically transform these coordinates to the map’s projection (which is also PlateCarree in this case, but it’s good practice to always specify the data’s CRS).
  • ax.text(): We use this to add the city names next to their respective points for better readability. Again, transform=ccrs.PlateCarree() ensures the text is placed correctly on the map.

5. Add a Title and Show the Map

Finally, let’s give our map a title and display it.

ax.set_title('Major Cities Around the World')

ax.legend()

plt.show()

Putting It All Together: Complete Code

Here’s the full code block for plotting our cities:

import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import pandas as pd

cities_data = {
    'City': ['London', 'New York', 'Tokyo', 'Sydney', 'Rio de Janeiro', 'Cairo'],
    'Latitude': [51.5, 40.7, 35.7, -33.9, -22.9, 30.0],
    'Longitude': [-0.1, -74.0, 139.7, 151.2, -43.2, 31.2]
}
df = pd.DataFrame(cities_data)

fig = plt.figure(figsize=(12, 10))
ax = fig.add_subplot(1, 1, 1, projection=ccrs.Orthographic(central_longitude=-20, central_latitude=15))

ax.add_feature(cfeature.COASTLINE)
ax.add_feature(cfeature.BORDERS, linestyle=':', alpha=0.7)
ax.add_feature(cfeature.LAND, edgecolor='black', facecolor=cfeature.COLORS['land'])
ax.add_feature(cfeature.OCEAN, facecolor=cfeature.COLORS['water'])
ax.gridlines(draw_labels=True, dms=True, x_inline=False, y_inline=False,
             color='gray', alpha=0.5, linestyle='--')


ax.scatter(df['Longitude'], df['Latitude'],
           color='red', marker='o', s=100,
           transform=ccrs.PlateCarree(), # Data's CRS is Plate Carree (Lat/Lon)
           label='Major Cities')

for index, row in df.iterrows():
    # Adjust text position slightly to avoid overlapping with the dot
    ax.text(row['Longitude'] + 3, row['Latitude'] + 3, row['City'],
            transform=ccrs.PlateCarree(), # Text's CRS is also Plate Carree
            horizontalalignment='left',
            color='blue', fontsize=10,
            bbox=dict(facecolor='white', alpha=0.7, edgecolor='none', boxstyle='round,pad=0.2'))

ax.set_title('Major Cities Around the World (Orthographic Projection)')
ax.legend()
plt.show()

Self-correction: I used Orthographic projection in the final combined code for a more visually interesting “globe” view, as PlateCarree can look a bit flat for global distribution. I also added set_extent as a comment for PlateCarree to demonstrate how to zoom in if needed.
Self-correction: Added bbox for text for better readability against map features.

What’s Next? Exploring Further!

This example just scratches the surface of what you can do with Matplotlib and Cartopy. Here are a few ideas for where to go next:

  • Different Projections: Experiment with various ccrs projections like Mercator, Orthographic, Robinson, etc., to see how they change the appearance of your map. Each projection has its strengths and weaknesses for representing different areas of the globe.
  • More Features: Add rivers, lakes, states, or even custom shapefiles (geographic vector data) using ax.add_feature() and other Cartopy functionalities.
  • Choropleth Maps: Instead of just points, you could color entire regions (like countries or states) based on a data value (e.g., population density, GDP). This typically involves reading geospatial data in formats like Shapefiles or GeoJSON.
  • Interactive Maps: While Matplotlib creates static images, libraries like Folium or Plotly can help you create interactive web maps if that’s what you need.

Conclusion

Visualizing geographic data is a powerful way to understand our world. With Matplotlib as your plotting foundation and Cartopy providing the geospatial magic, you have a robust toolkit to create insightful and beautiful maps. We’ve covered the basics of setting up your environment, understanding key concepts like projections and CRSs, and plotting your first data points. Now, it’s your turn to explore and tell compelling stories with your own geographic data! Happy mapping!


Comments

Leave a Reply