Geospatial intelligence (GEOINT) relies on analyzing and visualizing location-based data to gain insights and support decision making. As a popular Python visualization library, Matplotlib is a powerful tool for creating informative maps and geo-visualizations for GEOINT applications. This guide will demonstrate key Matplotlib capabilities for working with geospatial data, including creating choropleth maps, overlaying vector layers, generating heatmaps, and enabling interactive visual analytics.
Overview of Matplotlib for Geospatial Data Visualization
Matplotlib’s Pyplot interface provides a MATLAB-style API for building visualizations in Python. For working with geospatial data, Matplotlib integrates well with packages like Geopandas, Descartes, and Cartopy to create both static and interactive map visualizations.
Some key features of Matplotlib for geospatial intelligence include:
- Generating maps with coastlines, country borders, and map projections using Cartopy
- Plotting vector data layers such as points, lines, and polygons with Geopandas
- Creating choropleth maps to visualize data values across regions
- Adding interactivity for panning, zooming, and retrieving coordinate/data values
- Producing density heatmaps to identify “hot spots” and clusters
- Exporting publication-quality static map images and animations
When paired with NumPy, SciPy, and other Python scientific computing stacks, Matplotlib enables automated generation of production-ready maps and charts for geospatial applications.
Setting Up Matplotlib for Mapping
To start using Matplotlib for mapping, install Matplotlib along with Cartopy, Geopandas, Descarte, and other geospatial packages:
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import geopandas as gpd
from descartes import PolygonPatch
Now we can import shapefiles and begin visualizing geospatial vector data:
world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
By default, Matplotlib will plot geometries in a simplePlateCarree projection. We can define projections centered on specific regions using Cartopy:
projection = ccrs.PlateCarree()
ax = plt.axes(projection=projection)
ax.set_extent([140, 150, -10, -50], crs=ccrs.Geodetic())
Adding coastlines, borders, and other map elements is done via Cartopy features:
ax.add_feature(cfeature.LAND)
ax.add_feature(cfeature.OCEAN)
ax.add_feature(cfeature.COASTLINE)
ax.add_feature(cfeature.BORDERS, edgecolor='black')
Now we can visualize vector geometries from Geopandas:
world.plot(ax=ax, color='white', edgecolor='black')
This provides a basic configurable map projection to plot points, lines, and polygons with Matplotlib!
Creating Choropleth Maps
A common mapping technique is a choropleth map, which shades regions based on data variable values. This provides a visualization of patterns across locations.
First, we need geospatial region shapes and associated dataset. Geopandas provides USA state shapefiles:
states = gpd.read_file(gpd.datasets.get_path('usa_states'))
We will join state population data (saved as CSV called ‘population.csv’):
pop = pd.read_csv("population.csv")
merged = states.merge(pop, on='state')
Now we can create a choropleth map, with states shaded based on population:
vmin, vmax = 0, merged['population'].max()
fig, ax = plt.subplots(1, figsize=(10, 5))
merged.plot(column='population', cmap='Reds', linewidth=0.8, ax=ax, edgecolor='0.8', vmin=vmin, vmax=vmax)
ax.set_title("US State Population")
fig.colorbar(ax.get_children()[0], shrink=0.7)
This shades states with higher populations in darker red. We can customize the color palette, legend, and styles as needed. Choropleth maps are an effective way to visualize geo-patterns in data.
Plotting Points, Lines, and Polygons
Matplotlib can overlay various geometries, including points, lines, and polygons:
fig, ax = plt.subplots(figsize=(8, 8))
# Points
df = pd.DataFrame(np.random.randn(1000, 2), columns=['x', 'y'])
ax.scatter(df['x'], df['y'], c='red', alpha=0.3)
# Lines
from matplotlib.lines import Line2D
line = Line2D([0, 1], [0, 1], transform=ax.transAxes, color='green')
ax.add_line(line)
# Polygon
poly = PolygonPatch([[-1,-1], [1,-1], [1,1], [-1,1]], closed=True,
alpha=0.5, facecolor='blue')
ax.add_patch(poly)
ax.set(xlim=(-2, 2), ylim=(-2, 2))
This provides an overlay of all three geometry types on a single map. We can configure colors, transparency, sizes, and other stylistic properties as needed.
Plotting Spatial Dataframes
Geopandas extends Matplotlib for mapping geospatial data. Given a GeoDataFrame called gdf
:
gdf.plot(column='pop_density', cmap='OrRd', figsize=(10, 6),
edgecolor='grey', legend=True)
This plots the GeoDataFrame, shading regions by the ‘pop_density’ attribute. GeoPandas handles the geographic projection, coordinate system transforms, geometry patching, attribute joins, and choropleth legend generation automatically.
Annotating Maps
We can label geometries and add custom text annotations:
gdf.plot(color='white', edgecolor='black')
for idx, row in gdf.iterrows():
plt.annotate(s=row['City'], xy=row['Coordinates'],
horizontalalignment='center')
plt.scatter(x, y, s=200, marker='v', color='red')
plt.text(x, y, 'Capital City')
This plots city labels based on a GeoDataFrame attribute, and adds a custom annotation for the capital. Annotations help provide context and highlights for map readers.
Creating Heatmaps
Heatmaps visualize the density or magnitude of events, helping identify “hot spots” and clusters. This is useful for crime maps, disease outbreaks, earthquake epicenters, and more.
We’ll demonstrate a heatmap of earthquake occurrences in the Pacific Northwest:
data = pd.read_csv('earthquakes.csv')
fig, ax = plt.subplots(figsize=(8,6))
ax.set_extent([-125, -114, 24, 49], crs=ccrs.PlateCarree())
ax.scatter(data['longitude'], data['latitude'],
c=data['magnitude'], s=data['magnitude']*3,
cmap='plasma', transform=ccrs.PlateCarree())
The color and size of points indicates the earthquake magnitude. This reveals clustering patterns and “hot spots” for seismic activity.
We can also generate raster heatmaps using Kernel Density Estimation (KDE) from Scikit-Learn:
from sklearn.neighbors import KernelDensity
kde = KernelDensity(bandwidth=0.1, kernel='gaussian')
kde.fit(data[['longitude', 'latitude']])
xgrid = np.arange(data.longitude.min(), data.longitude.max(), 0.1)
ygrid = np.arange(data.latitude.min(), data.latitude.max(), 0.1)
grid = np.meshgrid(xgrid, ygrid)
density = np.reshape(kde.score_samples(np.c_[grid[0].ravel(), grid[1].ravel()]), grid[0].shape)
fig, ax = plt.subplots(figsize=(8, 6))
ax.imshow(density.T, origin='lower', extent=[xgrid.min(), xgrid.max(), ygrid.min(), ygrid.max()])
This uses KDE to estimate the density across the region, then plots it as a pixel heatmap. This is an effective way to visualize hotspots and clusters.
Building Interactive Maps
Matplotlib powers several Python interactive visualization libraries like Plotly Express, Bokeh, Datashader, and HoloViews. These let us pan, zoom, hover, and apply other dynamic functionality to maps.
As an example, we can make an interactive heatmap using Plotly Express:
import plotly.express as px
fig = px.density_heatmap(data, x='longitude', y='latitude')
fig.update_layout(margin=dict(t=0, b=0, l=0, r=0))
fig.show()
This generates a web-based zoomable heatmap. Hovering shows the density values, and toolbar buttons enable panning and zooming.
Other common interactive features include:
- Tooltips showing data values on hover
- Selectors to highlight/filter points
- Sliders to animate between time steps
- Buttons to toggle layers on/off
This interactivity makes it easy to explore data and derive insights from geospatial visualizations.
Exporting Maps and Visualizations
For reports, dashboards, and publications, we often need to export static map images and animations.
Matplotlib can generate high-resolution PNGs, SVGs, PDFs, and other image formats:
plt.savefig('map.png', dpi=300)
Adjusting the DPI and figure size controls the output resolution.
For animations, Matplotib supports converting a sequence of plot images into animated GIFs:
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
def update(frame):
ax.cla()
# Draw frame
...
ani = FuncAnimation(fig, update, frames=len(time_steps), interval=200)
ani.save('animation.gif', dpi=80, writer='pillow')
This saves an animated map as a shareable GIF!
Advanced Spatial Analysis and Visualization
Matplotlib connects to larger Python geospatial ecosystems like GeoPandas, Pandas, Shapely, Fiona, PyProj, and Rasterio.
These additional packages enable more advanced spatial analysis and visualization capabilities:
- Spatial Joins - Combine attribute data from multiple layers based on location/proximity
- Geocoding - Convert street addresses to geographic coordinates for mapping
- Spatial Queries - Identify geometries contained within or intersecting a region
- Buffering/Voronoi - Generate polygons surrounding points or along lines
- Spatial Indexing - Enable rapid lookups for nearest neighbor search and spatial queries
- Topology Analysis - Measure intersections, overlaps, and other topological relationships between geometries
- Network Analysis - Build graph networks and optimize routing over geospatial networks
- Raster Analysis - Extract info from aerial imagery and LiDAR for advanced remote sensing
By leveraging these additional tools, Matplotlib can power more sophisticated geospatial intelligence use cases like tracking assets, optimizing logistics, responding to emergencies, and analyzing demographic patterns.
Here are the three additional sections incorporated into the previous guide:
Real-World Case Study: Visualizing Urban Growth Patterns
To demonstrate a real-world application of these techniques, let’s examine a case study visualizing urban growth over time. Historical urban area boundary data can reveal geospatial patterns in how cities expand.
Using urban growth rasters from the European Environment Agency, we can animate expansion in Southern England between 1960 to 2010:
raster_paths = ['urban_1960.tif', 'urban_1970.tif', ..., 'urban_2010.tif']
fig, ax = plt.subplots()
def update(i):
ax.cla()
raster = rasterio.open(raster_paths[i])
show(raster, ax=ax)
ax.set_title(f"Year {1960 + i*10}")
ani = animation.FuncAnimation(fig, update, frames=len(raster_paths))
ani.save('urban_growth.gif')
This animated map clearly highlights the spread of urban areas over time near London. Geospatial analysis of urban growth helps planners model future expansion patterns and demands.
Comparison to Other Python Geospatial Libraries
Matplotlib provides a full-featured mapping solution, but alternatives like Bokeh, HoloViews, and PyPlot offer different capabilities:
- Bokeh - Interactivity and large data performance optimizations
- HoloViews - Ease of building complex visualizations
- PyPlot - 3D and OpenGL-powered rendering
In benchmark tests, Matplotlib generates basic static maps faster than Bokeh and HoloViews, but falls behind on large/streaming data volumes. PyPlot outperforms Matplotlib for 3D visualizations.
For maximum flexibility, using Matplotlib alongside libraries like GeoPandas and Plotly Express combines strengths in geospatial data wrangling and interactivity.
Best Practices for Geospatial Project Structure
For consistent and maintainable geospatial code, some best practices include:
- Separate raw data import/preprocessing from analysis and visualization code
- Break analysis and mapping logic into reusable functions/classes
- Store common styles, color palettes, and map templates as variables/constants
- Use relative paths to load data files and shapefiles
- Include requirements.txt listing geospatial package versions
- Configure visualization defaults on matplotlibrc
- Follow PEP8 style guide and geo-specific naming conventions
- Add comments explaining coordinate reference systems and projections used
- Plot legends, labels, and annotations for clear communication
- Enable GPU acceleration for performance if working with large datasets
Following geospatial-specific project guidelines helps produce clear, robust code as an analysis scales up.
Conclusion
This guide demonstrated how Matplotlib enables flexible and intuitive generation of maps, heatmaps, and interactive geo-visualizations in Python. Using vector layers, choropleths, annotations, and other mapping components, Matplotlib facilitates exploration and presentation of geospatial data for business intelligence and research applications.
By building on Matplotlib’s foundations with packages like Geopandas and Cartopy, Python provides a scalable platform for geospatial analytics and visualization. The Python data science ecosystem continues to evolve powerful tools for working with location-based data. Leveraging languages like Python for mapping helps unlock the full potential of geospatial intelligence to create actionable insights.