Mathew K Analytics

Lesson 29 · Data visualisation in python

Introduction to GeoPandas: Working with Shapefiles and Geospatial Maps in Python

GeoPandas helps us analyze and visualize geographic data in Python, like locations, boundaries, and real-world maps. In this lesson, we will: Understand…

What you'll learn

Datasets used in this lesson

Save these next to the notebook. In Google Colab, upload them with the 📁 icon on the left first.

📓 Full notebook

Download .ipynb

Introduction to GeoPandas: Shapefiles and Maps#

GeoPandas helps us analyze and visualize geographic data in Python, like locations, boundaries, and real-world maps.

In this lesson, we will:

  • Understand geospatial data basics
  • Read and inspect shapefiles
  • Plot simple maps
  • Explore a real-world mapping mini-project

You do not need previous experience with GIS or mapping.

Let us get started!

import warnings
warnings.filterwarnings("ignore")
# This suppresses warning messages to keep our output clean.

What is geospatial data?#

Geospatial data is information connected to locations on the Earth.

  • Points show places (like schools).
  • Lines show paths (like roads).
  • Polygons show areas (like city boundaries).

This type of data helps us answer questions about where things are and how they relate on a map.

# Let us install GeoPandas if it is not already here.
import sys
try:
    import geopandas
except ImportError:
    !{sys.executable} -m pip install geopandas
    
# Let us import the main tools.
import geopandas as gpd
import pandas as pd
import matplotlib.pyplot as plt

What is a shapefile?#

A shapefile stores map shapes:

  • Points (like post office locations)
  • Lines (like rivers)
  • Polygons (like country borders)

Shapefiles usually have the .shp file plus other helper files.

GeoPandas can read them easily.

# Data setup
# Let us download a US States shapefile from a simple URL.
# Source: Census Bureau. This is public data.
url = "https://www2.census.gov/geo/tiger/GENZ2018/shp/cb_2018_us_state_500k.zip"
import os
shpzip = "cb_2018_us_state_500k.zip"
if not os.path.exists(shpzip):
    import urllib.request
    urllib.request.urlretrieve(url, shpzip)
gdf = gpd.read_file("zip://" + shpzip)
print("Shape:", gdf.shape)
gdf.head()
Shape: (56, 10)
STATEFP STATENS AFFGEOID GEOID STUSPS NAME LSAD ALAND AWATER geometry
0 28 01779790 0400000US28 28 MS Mississippi 00 121533519481 3926919758 MULTIPOLYGON (((-88.50297 30.21524, -88.49176 ...
1 37 01027616 0400000US37 37 NC North Carolina 00 125923656064 13466071395 MULTIPOLYGON (((-75.72681 35.93584, -75.71827 ...
2 40 01102857 0400000US40 40 OK Oklahoma 00 177662925723 3374587997 POLYGON ((-103.00256 36.52659, -103.00219 36.6...
3 51 01779803 0400000US51 51 VA Virginia 00 102257717110 8528531774 MULTIPOLYGON (((-75.74241 37.80835, -75.74151 ...
4 54 01779805 0400000US54 54 WV West Virginia 00 62266474513 489028543 POLYGON ((-82.6432 38.16909, -82.643 38.16956,...
# The GeoDataFrame is like a spreadsheet, but one column is 'geometry'.
print("Columns:", list(gdf.columns))
print("Geometry column sample:")
print(gdf['geometry'].head(2))
Columns: ['STATEFP', 'STATENS', 'AFFGEOID', 'GEOID', 'STUSPS', 'NAME', 'LSAD', 'ALAND', 'AWATER', 'geometry']
Geometry column sample:
0    MULTIPOLYGON (((-88.50297 30.21524, -88.49176 ...
1    MULTIPOLYGON (((-75.72681 35.93584, -75.71827 ...
Name: geometry, dtype: geometry
# Let us plot the map using gdf.plot().
gdf.plot(figsize=(10,6), edgecolor="black", color="lightblue")
plt.title("US States Map")
plt.show()
No description has been provided for this image

Filtering geospatial data#

Sometimes, we only want certain rows.

For example, we might only want western states.

Let us see how to select by state name.

# Show some western US states only.
western = ["CA", "WA", "OR", "NV", "AZ", "NM"]
gdf_west = gdf[gdf['STUSPS'].isin(western)]
gdf_west.plot(figsize=(8,5), edgecolor="black", color="orange")
plt.title("Western US States")
plt.show()
No description has been provided for this image
# Let us label the states on the map.
ax = gdf_west.plot(figsize=(8,5), color="wheat", edgecolor="black")
for x, y, label in zip(gdf_west.geometry.centroid.x, gdf_west.geometry.centroid.y, gdf_west['NAME']):
    ax.text(x, y, label, fontsize=9)
plt.title("Western States with Labels")
plt.show()
No description has been provided for this image

What if there is an error?#

Geopandas might give errors if a file is missing or uses the wrong path.

You can check file existence with Python's os.path.exists.

Check column names if you get a column error.

# Practice: Try entering your own abbreviation.
abbr = input("Enter a US state abbreviation (e.g. CA): ")
if abbr in list(gdf['STUSPS']):
    state_row = gdf[gdf['STUSPS'] == abbr]
    state_row.plot(figsize=(5,5), color="lightgreen", edgecolor="black")
    plt.title(f"Map of {abbr}")
    plt.show()
else:
    print("Sorry, that state is not found.")
    
No description has been provided for this image
# Making new columns: let us compute the state area in square kilometers.
gdf['area_km2'] = gdf.to_crs(epsg=3395).geometry.area / 1e6
gdf[['STUSPS', 'NAME', 'area_km2']].head()
STUSPS NAME area_km2
0 MS Mississippi 174370.164994
1 NC North Carolina 193820.876339
2 OK Oklahoma 273201.007589
3 VA Virginia 166265.631920
4 WV West Virginia 102624.243952
# Plot the top 5 biggest states by area.
largest5 = gdf.nlargest(5, 'area_km2')
ax = gdf.plot(color='lightgrey', edgecolor='grey', figsize=(10,6))
largest5.plot(ax=ax, color='darkblue', edgecolor='white')
for x, y, abbr in zip(largest5.geometry.centroid.x, largest5.geometry.centroid.y, largest5['STUSPS']):
    ax.text(x, y, abbr, fontsize=11, color='white')
plt.title('Top 5 Largest US States')
plt.show()
No description has been provided for this image
# Save the filtered western states as a new shapefile.
gdf_west.to_file("western_states.shp")
print("Shapefile saved as western_states.shp")
Shapefile saved as western_states.shp

Mini-project: Map US states with earthquake data#

Let us add real earthquake locations to our states map.

We will use a small open dataset from the USGS.

# Download USGS earthquake data (past week, all M1+).
quakes_url = "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.csv"
quakes = pd.read_csv(quakes_url)
print("Quake count:", quakes.shape[0])
quakes[['place','mag','latitude','longitude']].head()
Quake count: 1920
place mag latitude longitude
0 6 km WNW of Cobb, CA 0.41 38.838501 -122.785004
1 18 km ESE of Little Lake, CA 0.30 35.873500 -117.719333
2 149 km NNE of Cruz Bay, U.S. Virgin Islands 3.76 19.573800 -64.232600
3 8 km NE of Banning, CA 0.89 33.984000 -116.824833
4 23 km ENE of King City, CA 1.86 36.351166 -120.940666
# Convert earthquake locations to GeoDataFrame points.
from shapely.geometry import Point
quake_gdf = gpd.GeoDataFrame(
    quakes, geometry=[Point(xy) for xy in zip(quakes.longitude, quakes.latitude)], crs='EPSG:4326')
# Plot earthquakes and state boundaries together.
ax = gdf.plot(figsize=(10,6), color='white', edgecolor='black')
quake_gdf.plot(ax=ax, markersize=quake_gdf['mag']*3, alpha=0.5, color='red')
plt.title('US Map: Recent Earthquakes')
plt.show()
No description has been provided for this image
# How many earthquakes in California this week?
from shapely.geometry import Polygon
ca_shape = gdf[gdf['STUSPS']=='CA'].geometry.values[0]
quakes_in_ca = quake_gdf[quake_gdf.within(ca_shape)]
print(f"Number of earthquakes in CA: {len(quakes_in_ca)}")
Number of earthquakes in CA: 652
# Clean up files created earlier (optional).
import glob
for ext in ["shp","shx","dbf","prj","cpg"]:
    for fname in glob.glob(f"western_states.{ext}"):
        os.remove(fname)
        

Recap & Next Steps#

  • GeoPandas lets us read, explore, and plot real maps
  • You can filter and style by attribute or location
  • Save maps or combine with other datasets

You have the basics for working with geographic data in Python!

Check out GeoPandas examples and official docs to dive deeper.

Extra: Try this Challenge#

Pick a US state you like. Show a map of earthquakes only in that state from the last week.

Label at least five largest quakes with their magnitudes.

Want more free Python tips? Subscribe to our channel and like this video!

Happy mapping!

Found this useful?

All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.