Python and GIS tutorials
55 Python tutorials, each run end-to-end before publishing: download the scripts and you should get the same figures and numbers you see on the page. Alongside them, 5 QGIS and ArcGIS Pro walkthroughs. Filter by what you want to learn, or follow a learning path or a series.
All tutorials and articles
-
H3 hexagon grids in Python: indexing, aggregating and smoothing 541,000 London places with Uber's H3
A practical guide to Uber's H3 hexagonal grid in Python with the h3-py v4 API: index points, choose a resolution, fill polygons, count 541,081 Overture places across London, smooth with k-rings, do the same in DuckDB's h3 extension, and compare hexagons with square grids of equal area.
-
Methane plume detection in Python with NASA EMIT: mapping and quantifying landfill plumes
Detect and quantify methane plumes in Python with NASA's EMIT imaging spectrometer: load open EMIT methane enhancement data from NASA VEDA without a login, separate three Dallas-Fort Worth landfill plumes from the noise, compute the integrated mass enhancement, estimate emission rates with ERA5 winds, and compare them with EPA greenhouse gas inventory figures.
-
Make a map in Python with matplotlib and cartopy: projections, classified choropleths, scale bars, north arrows and inset maps
A cartopy tutorial for publication-quality maps in Python: choose a projection, draw a classified choropleth of Census 2021 population density with a proper legend, add a scale bar, a true-north arrow, an inset locator map and gridlines, style it for light and dark backgrounds, export at 300 dpi to PNG, PDF and SVG, and shade the Copernicus DEM for Greater Manchester.
-
Earthquake damage mapping with Sentinel-1 in Python: log ratio and z-scores in Antakya
Map earthquake damage from free Sentinel-1 radar in Python. Compute the log ratio and a z-score against a pre-event stack for Antakya after the February 2023 Türkiye earthquakes, aggregate to a 200 m grid, and score the map against 730 destroyed buildings mapped in OpenStreetMap.
-
Raster to vector in Python: polygonize with rasterio, rasterize boundaries and convert a GeoTIFF to a Cloud Optimized GeoTIFF
Convert raster to vector in Python with rasterio.features.shapes on 10 m ESA WorldCover for Greater Manchester: polygonize water and built-up land, fix invalid polygons, simplify without gaps, rasterize ONS district boundaries for land-cover shares, then write and validate a Cloud Optimized GeoTIFF with rio-cogeo and measure HTTP range reads.
-
Rooftop solar potential from LiDAR in Python: pvlib, PVGIS and shading for every roof
Estimate rooftop solar potential in Python for 2,148 buildings in Manchester: take a 1 m Environment Agency LiDAR DSM and Overture Maps footprints, compute roof slope and aspect, trace horizon angles for shading from neighbours and trees, build a sun map from a PVGIS typical year with pvlib, check it against pvlib's Perez model and PVGIS, then estimate kWp and kWh per year per roof and rank the best roofs.
-
Sentinel-1 soil moisture in Python: change detection checked against COSMOS-UK
Estimate surface soil moisture from free Sentinel-1 radar in Python with the TU Wien change-detection method. Build dry and wet references per orbit, map relative soil moisture at 100 m, and test it honestly against four COSMOS-UK stations and their rain gauges.
-
Spatial joins in GeoPandas: sjoin, predicates, sjoin_nearest and point in polygon
A practical guide to spatial joins in GeoPandas with real Greater Manchester data: 13,187 NaPTAN bus stops, 1,386 OpenStreetMap schools, 215 ONS wards and 1,702 LSOAs. Covers point in polygon with sjoin, predicates, counts per polygon, how='left'/'inner'/'right', sjoin_nearest with max_distance, clip and overlay, and a timing comparison of a naive loop against the spatial index.
-
Coordinate reference systems in Python: EPSG codes, pyproj transforms and reprojecting vectors and rasters
A practical guide to coordinate reference systems in Python with pyproj, GeoPandas and rasterio, tested on real Greater Manchester data. Covers EPSG codes, WGS 84 vs British National Grid (EPSG:27700), the always_xy axis-order trap, OSTN15 vs Helmert datum shifts checked against 13,187 NaPTAN bus stops, measured area and distance errors in the wrong CRS, and reprojecting a GeoDataFrame and a Copernicus DEM raster.
-
Viewshed analysis in Python: line of sight and a wind farm ZTV with GDAL and numpy
Run a viewshed analysis in Python on a real DEM: compute what one wind turbine can see with gdal.ViewshedGenerate, rebuild the same line-of-sight algorithm in numpy, correct for earth curvature and refraction, build a cumulative zone of theoretical visibility (ZTV) from 26 turbines, draw line-of-sight profiles, and measure how much trees and buildings in a LiDAR DSM shrink a bare-earth viewshed.
-
Habitat mapping with Sentinel-2 in Python: spectral index rules and an honest accuracy assessment
Map blanket bog, heath, bracken, grassland, woodland, water and built-up land in the Peak District from 2023 Sentinel-2 seasonal composites with an eight-rule spectral index classifier, then assess it properly: a confusion matrix, user's and producer's accuracy, kappa and its caveats, block-bootstrap confidence intervals, and why a random train/test split overstates accuracy.
-
Canopy height map in Python: Meta 1 m and ETH 10 m maps checked against UK LiDAR (Forest of Dean)
Read the open Meta/WRI global 1 m canopy height map from AWS with no login, compare it with ETH Global Canopy Height 2020, and validate both against a canopy height model made from Environment Agency LiDAR in the Forest of Dean: CRS alignment, bias, RMSE, hexbin plots, height classes and honest limitations.
-
InSAR time series in Python: Svartsengi inflation cycles validated with GNSS
Build an SBAS InSAR time series in Python from 364 COMET LiCSAR Sentinel-1 interferograms of the Svartsengi volcano in Iceland. Check unwrapping with phase closure, invert pixel by pixel with weighted least squares, project GNSS east, north and up into the line of sight, and validate six inflation–eruption cycles against the SENG station.
-
SAR speckle filtering in Python: Lee, refined Lee, Frost and Gamma-MAP on Sentinel-1
Write the classic SAR speckle filters (boxcar, Lee, refined Lee, enhanced Lee, Frost and Gamma-MAP) in NumPy and SciPy, run them on Sentinel-1 over Rutland Water, and compare them by equivalent number of looks, edge preservation and speed.
-
Zonal statistics in Python: exactextract vs rasterstats, with partial pixels, land-cover fractions and a benchmark
Calculate zonal statistics in Python with exactextract and rasterstats on real data: ONS 2021 LSOA boundaries for Cumbria with GHSL population, the Copernicus DEM and ESA WorldCover. Covers partial-pixel weighting vs pixel centroids, CRS alignment, categorical land-cover fractions, a speed benchmark, GeoPackage export and choropleth maps.
-
ERA5 in Python with xarray: mapping the July 2022 UK heatwave
Read ERA5 climate reanalysis in Python with xarray from free, login-free cloud Zarr stores, clip it to the UK, compute area-weighted means and anomalies against 1991–2020, export a Cloud Optimised GeoTIFF and check it against Met Office stations.
-
Habitat classification with LightGBM in Python: Sentinel-2, Sentinel-1 and terrain fusion
Classify nine upland habitats in the Peak District with LightGBM on 77 multi-temporal features: seasonal Sentinel-2 bands and indices, Sentinel-1 VV and VH backscatter and Copernicus DEM terrain. Tune with spatial-fold cross-validation and class weights, run an S2 / S2+S1 / S2+S1+terrain ablation, explain the model with TreeSHAP and permutation importance, and compare it with a random forest and the Part 1 rules on the same test blocks.
-
Mogi model inversion in Python: magma depth and volume from InSAR at Svartsengi, Iceland
Invert Sentinel-1 InSAR for a volcanic source in Python: write Mogi point-source and Okada (1985) sill forward models in NumPy, downsample ascending and descending LOS maps with a quadtree, fit depth and volume change by weighted least squares with scipy.optimize, and estimate uncertainties with a Monte Carlo of correlated noise, compared with published results.
-
Sentinel-2 cloud and cloud-shadow masking in Python: SCL vs s2cloudless vs OmniCloudMask
Mask clouds and cloud shadows in Sentinel-2 L2A imagery with Python. Compare the Scene Classification Layer (SCL), s2cloudless, OmniCloudMask and a simple threshold over the Lake District, measure how far they agree, score them against 186 reference points and build a cloud-free median composite.
-
Snow cover mapping with NDSI in Python: Sentinel-2 and MODIS over the Cairngorms
Map snow cover in Python with the Normalised Difference Snow Index (NDSI) from Sentinel-2 and the daily MODIS snow product on the Microsoft Planetary Computer: choosing the NDSI threshold, separating snow from cloud, snow-covered area through the winter of 2025–26 in the Cairngorms, and the snowline by elevation and aspect with the Copernicus DEM.
-
AlphaEarth satellite embeddings in Python: few-shot habitat mapping, uncertainty and area estimates
Use Google DeepMind's AlphaEarth Foundations satellite embeddings, a geospatial foundation model, in Python without a login. Classify nine Peak District habitats with a linear model, compare a few-shot learning curve against raw Sentinel-2 bands, map uncertainty, check calibration, simulate active learning, and estimate habitat areas with confidence intervals from a stratified random sample (Olofsson et al. 2014).
-
Glacier velocity in Python with NASA ITS_LIVE: Jakobshavn Isbræ, 1985–2025
Map glacier velocity in Python with NASA's ITS_LIVE Zarr datacubes on AWS, with no login: velocity maps, a flowline traced from the velocity field, 40 years of speed profiles, seasonal and multi-year time series from 80,568 filtered image pairs, and strain rates and flow directions on Jakobshavn Isbræ (Sermeq Kujalleq), Greenland's fastest glacier.
-
InSAR volcano deformation in Python: mapping magma inflation at Svartsengi, Iceland, with Sentinel-1
Map volcano deformation with Sentinel-1 InSAR in Python: stream free COMET LiCSAR interferograms of the Svartsengi volcanic system in Iceland, read wrapped and unwrapped phase and coherence, count fringes, convert phase to line-of-sight millimetres, and combine ascending and descending tracks into vertical and east–west motion, checked against GNSS.
-
Object-based image analysis in Python: OBIA habitat classification with Sentinel-2
Segment 2023 Sentinel-2 seasonal composites of the Peak District into image objects with scikit-image SLIC and Felzenszwalb, tune the segment size against Living England boundaries, compute per-object statistics, shape and GLCM texture with NumPy, classify the objects with LightGBM and compare OBIA with a pixel-based classifier on accuracy, salt-and-pepper noise and patch counts. Then export the habitat objects as GeoPackage polygons.
-
Satellite image time series classification with deep learning: TempCNN and L-TAE in PyTorch on a CPU
Classify habitats from a full year of cloudy, irregular Sentinel-2 observations with two temporal neural networks in PyTorch: a 1D convolutional TempCNN and a lightweight temporal attention encoder (L-TAE) with day-of-year positional encoding. Compare masking with gap-filling, test against a LightGBM baseline on spatial blocks, read which dates matter from attention and occlusion, and predict a wall-to-wall 10 m map on a CPU.
-
Coastal erosion and shoreline change from Sentinel-2 in Python (Holderness, 2017–2026)
Measure shoreline change on one of Europe's fastest-eroding coasts with free Sentinel-2 imagery and Python: MNDWI and Otsu thresholding, sub-pixel shorelines with find_contours, shore-normal transects, a tide correction from open tide-gauge data, end-point and linear regression rates, and an honest comparison with East Riding of Yorkshire Council's cliff monitoring.
-
Deforestation detection in Python with Global Forest Change data (Rondônia, 2001–2025)
Map forest loss and deforestation in Python with the Hansen/UMD Global Forest Change v1.13 data: read the open tiles with no login, compute loss by year in hectares with correct pixel areas, compare Landsat and Sentinel-2 images before and after, and check the GFC loss year against Sentinel-2 NBR and MODIS burned area for central Rondônia, Brazil.
-
Hot spot analysis in Python: Getis-Ord Gi*, Moran's I and LISA on Birmingham road collisions
Run a hot spot analysis in Python with PySAL: aggregate 2025 STATS19 road collisions in Birmingham to a hexagon grid, test for clustering with global Moran's I, map Getis-Ord Gi* hot spots and LISA clusters with permutation inference and FDR correction, and see how spatial weights, the areal unit and exposure change the answer.
-
Deep learning inference on large rasters: sliding-window prediction, COGs and polygons in Python
Run a trained PyTorch U-Net over a whole Sentinel-2 scene of a city it has never seen: tiled sliding-window inference on a large GeoTIFF with overlapping, blended windows, a georeferenced Cloud Optimised GeoTIFF of classes and confidence, raster-to-vector polygons with rasterio.features.shapes in a GeoPackage, and an honest check against reference labels.
-
Kriging in Python with PyKrige: IDW vs ordinary kriging of UK NO₂ monitoring data
A practical spatial interpolation tutorial in Python: download real 2025 NO₂ annual means from the UK AURN network, fit spherical, exponential and Gaussian variograms, run ordinary kriging with PyKrige, compare it with inverse distance weighting, score both with leave-one-out cross-validation, map the kriging variance and add Sentinel-5P satellite NO₂ as a covariate.
-
U-Net satellite image segmentation in PyTorch: a TorchGeo and Sentinel-2 tutorial on a CPU
Train a U-Net to segment Sentinel-2 imagery into buildings, built-up land, trees, grass and water with PyTorch, segmentation_models_pytorch and TorchGeo's Sentinel-2 pretrained ResNet-18 weights, on a CPU in five minutes. Real loss curves, per-class IoU and F1, a confusion matrix and an honest look at what limits accuracy.
-
PMTiles vector tiles in Python and a MapLibre GL JS web map
Turn Overture Maps GeoParquet into PMTiles vector tiles with the GDAL that ships in pyogrio, no Tippecanoe needed, measure the zoom-level and size trade-offs, and serve an interactive MapLibre GL JS map of Bristol from static hosting.
-
Query Overture Maps with DuckDB spatial and GeoParquet in Python
Pull Bristol's 144,965 buildings and 20,727 places straight from the Overture Maps GeoParquet release with DuckDB, run spatial SQL joins and H3 aggregation, load the result into GeoPandas, write GeoParquet 1.1, and time it against Shapefile, GeoPackage and FlatGeobuf.
-
Training data for deep learning on satellite imagery: Sentinel-2 image chips in Python
Build a labelled deep learning dataset from free data: stream a Sentinel-2 L2A composite from the Planetary Computer, rasterise Overture building footprints over ESA WorldCover, cut georeferenced image chips, split them by spatial block so the test set does not leak, check the class balance and load it all as a TorchGeo dataset.
-
Sentinel-5P NO₂ in Python: mapping air pollution from TROPOMI over the UK and north-west Europe
Map nitrogen dioxide air pollution from Sentinel-5P TROPOMI Level-2 data in Python: stream a full year of orbits from the Planetary Computer, apply the qa_value > 0.75 filter, grid swaths to a regular raster, build monthly and seasonal composites, rank cities and measure the weekend drop, with an honest explanation of what a tropospheric column is.
-
InSAR ground subsidence in Python: one year of Mexico City sinking, from Sentinel-1
Map ground subsidence with Sentinel-1 InSAR in Python: stream 170 real interferograms of Mexico City, convert unwrapped phase to millimetres of line-of-sight motion, mask low coherence, invert a small-baseline network into a time series, and cross-check the velocity with MintPy.
-
Burn severity mapping with Sentinel-2 and dNBR in Python (Saddleworth Moor 2018)
Map wildfire burn severity in Python with free Sentinel-2 imagery: NBR calculation, cloud and water masking with SCL, dNBR with an offset, USGS severity classes and burned hectares, a burn perimeter, fire progression, RdNBR and an eight-year recovery record for the 2018 Saddleworth Moor fire.
-
Extract building footprints and heights from LiDAR in Python (USGS 3DEP, downtown Madison)
Turn classified LiDAR into building footprints with heights in Python: stream USGS 3DEP COPC tiles, build a DTM and a building nDSM from ASPRS class 6 points, polygonise and regularise the mask, split roofs at height steps, compute height statistics per building, score the result against OpenStreetMap with IoU, and export a GeoPackage and a 3D view.
-
Sentinel-1 crop monitoring in Python: SAR time series for wheat and oilseed rape
Monitor crops through cloud with free Sentinel-1 radar. Build VV, VH and VH/VV ratio time series for 247 fields in Cambridgeshire, beat speckle by field-averaging, read the growth signatures of winter wheat and oilseed rape, and compare with the gaps that cloud leaves in Sentinel-2 NDVI.
-
Segment Anything on satellite and aerial imagery in Python: a samgeo tutorial
Run Meta's Segment Anything Model on high-resolution aerial imagery with segment-geospatial (samgeo), on a CPU. Generate masks automatically, vectorise them to a GeoPackage, filter them by area, shape and NDVI to find buildings, and prompt SAM with points and boxes, checked against OpenStreetMap.
-
Land surface temperature from Landsat in Python: mapping London's urban heat island
Calculate land surface temperature from Landsat 8 and 9 Collection 2 Level-2 data in Python: ST_B10 scale and offset, QA_PIXEL cloud masking, LST by land cover and NDVI, an urban-rural transect, hotspots with OpenStreetMap and an honest comparison with air temperature, for London in the July 2022 heatwave.
-
Land cover classification in Python: a Sentinel-2 random forest with scikit-learn
Supervised land cover classification in Python: build seasonal Sentinel-2 composites with odc-stac, sample labels from ESA WorldCover, train a scikit-learn random forest, test it with spatial cross-validation and map Sheffield and the Peak District.
-
NDVI time series in Python with Sentinel-2, odc-stac and xarray
Build a five-year Sentinel-2 NDVI time series in Python: load a lazy dask datacube with odc-stac, mask cloud with SCL, make monthly composites, extract field curves and derive crop phenology.
-
Sentinel-1 ship detection in Python: a CA-CFAR detector off the Port of Rotterdam
Detect ships in free Sentinel-1 SAR imagery with a cell-averaging CFAR detector written in NumPy and SciPy: mask the land, set a threshold from a speckle model, cluster detections into targets, reject wind turbines, sidelobes and ambiguities, compare VV with VH and export the vessels as GeoJSON.
-
Watershed delineation in Python with pysheds: the River Derwent above Ladybower
Delineate a catchment and its stream network from a free DEM in Python with pysheds: fill pits and depressions, D8 flow direction, flow accumulation, snapping the pour point, catchment polygon and area, Strahler stream order and drainage density, all checked against the official NRFA boundary for the River Derwent at Yorkshire Bridge in the Peak District.
-
Monitoring reservoir water quality from space with Sentinel-2 and Python (Peak District case study)
Track chlorophyll, turbidity and peat colour proxies in four Peak District reservoirs with free Sentinel-2 imagery: cloud and water masking for small, dark upland lakes, NDCI and NDTI time series from 2019 to 2026, anomaly ranking, maps, tidy CSVs and an honest check against Environment Agency samples.
-
Sentinel-1 SAR flood mapping in Python: the 2022 Pakistan floods
Map the 2022 Sindh floods with free Sentinel-1 radar from the Microsoft Planetary Computer: convert backscatter to decibels, remove speckle with a Lee filter, pick a water threshold with Otsu's method, and measure the flood extent and how it receded over seven months.
-
LiDAR point clouds in Python with laspy: from a LAZ file to a DTM, DSM and canopy height model
Stream free USGS 3DEP lidar of Washington, D.C., read and inspect a LAZ file with laspy, remove noise, grid the points into a 1 m DTM, DSM and canopy height model, and use the result to measure the Washington Monument to within 44 cm.
-
From DEM to 3D-printable STL with Python and NumPy
Stream a Copernicus 30 m DEM of the Edale valley, reproject it to British National Grid, scale it to a 150 mm print and write a watertight binary STL using only NumPy, with checks that prove the mesh is printable.
-
Fast vector geoprocessing in Python: spatial indexes, overlays and modern file formats
Benchmark point-in-polygon joins, buffers, overlays and dissolves on 200,000 points with GeoPandas and Shapely 2, see why spatial indexes give a 100x+ speed-up, and compare Shapefile, GeoPackage, FlatGeobuf and GeoParquet.
-
Interactive web maps from Python with Folium and GeoPandas .explore()
Turn GeoDataFrames into shareable Leaflet web maps: a one-line choropleth with .explore(), then a hand-built Folium map with custom styling, tooltips, clustered markers, switchable basemaps and plugins — saved as a single HTML file.
-
Street network analysis with OSMnx: routes, isochrones and walking accessibility
Download Sheffield's walkable street network from OpenStreetMap with OSMnx, find the shortest walk across the city, draw 5–20 minute isochrones and map how far every street is from the nearest supermarket.
-
Measuring Lake Mead's shrinking shoreline with Sentinel-2, STAC and Python
Search seven summers of Sentinel-2 imagery with pystac-client, stream only the bands you need from Cloud Optimised GeoTIFFs, mask clouds, compute NDWI and MNDWI and measure how much of Lake Mead dried up between 2019 and 2025.
-
Terrain analysis in Python: stream, clip and analyse a DEM with rasterio and rioxarray
Read only the pixels you need from a cloud-hosted Copernicus DEM, reproject to British National Grid, derive hillshade, slope and aspect with NumPy, compute zonal statistics and draw an elevation profile — all in one script.
-
Getting started with GeoPandas: projections, spatial joins and choropleth maps
Load Natural Earth vector data with GeoPandas, reproject to an equal-area CRS, calculate population density, join cities to countries, dissolve to continents and draw publication-ready choropleths.
-
Visualising a Cycle Track in 3D
Turning a GPX track of the Wharncliffe Woods cycle route into a 3D scene and elevation profile in ArcGIS Pro.
-
Performing Bivariate Correlation Analysis using Census and Crime Data
Exploring the relationship between census variables and recorded crime with bivariate correlation analysis in ArcGIS Pro.
-
How to Add Google Maps and OpenStreetMap Layers to QGIS
Add OpenStreetMap, satellite and Google basemaps to QGIS 3.40 LTR, 3.44 and 4.x as XYZ Tiles connections: the correct tile URLs, the OpenStreetMap tile usage policy, the licence-safe ways to get Google, Esri and Sentinel-2 imagery, and the same basemaps from PyQGIS, folium, leafmap and contextily.
-
Creating a 3D Printed Digital Elevation Model in QGIS
From a digital elevation model to a physical 3D print: preparing terrain in QGIS and exporting it for slicing.
-
Monitoring Lake Mead Drought
A look at the dramatic fall in Lake Mead's water level during the 2022 drought.
Nothing matches all of those filters.
Try fewer filters, or search the whole site, which also covers the country data guides.
Learning paths
Each path runs from a first step to research-grade analysis, in an order where every tutorial builds on the one before. Jump in wherever the level suits you.
Python GIS foundations
Vector data, projections, joins and maps, then rasters, zonal statistics and cloud-native formats.
- Getting started with GeoPandas: projections, spatial joins and choropleth maps Beginner
- Coordinate reference systems in Python: EPSG codes, pyproj transforms and reprojecting vectors and rasters Beginner
- Spatial joins in GeoPandas: sjoin, predicates, sjoin_nearest and point in polygon Beginner
- Make a map in Python with matplotlib and cartopy: projections, classified choropleths, scale bars, north arrows and inset maps Beginner
- Interactive web maps from Python with Folium and GeoPandas .explore() Beginner
- Terrain analysis in Python: stream, clip and analyse a DEM with rasterio and rioxarray Intermediate
- Zonal statistics in Python: exactextract vs rasterstats, with partial pixels, land-cover fractions and a benchmark Intermediate
- Raster to vector in Python: polygonize with rasterio, rasterize boundaries and convert a GeoTIFF to a Cloud Optimized GeoTIFF Intermediate
- Fast vector geoprocessing in Python: spatial indexes, overlays and modern file formats Intermediate
- Query Overture Maps with DuckDB spatial and GeoParquet in Python Intermediate
Remote sensing and Earth observation
Search Sentinel-2 with STAC, mask clouds, build index time series, then measure fire, water, heat, snow and gas.
- Measuring Lake Mead's shrinking shoreline with Sentinel-2, STAC and Python Intermediate
- Sentinel-2 cloud and cloud-shadow masking in Python: SCL vs s2cloudless vs OmniCloudMask Intermediate
- NDVI time series in Python with Sentinel-2, odc-stac and xarray Intermediate
- Burn severity mapping with Sentinel-2 and dNBR in Python (Saddleworth Moor 2018) Intermediate
- Monitoring reservoir water quality from space with Sentinel-2 and Python (Peak District case study) Intermediate
- Land surface temperature from Landsat in Python: mapping London's urban heat island Intermediate
- Snow cover mapping with NDSI in Python: Sentinel-2 and MODIS over the Cairngorms Intermediate
- Sentinel-5P NO₂ in Python: mapping air pollution from TROPOMI over the UK and north-west Europe Intermediate
- Coastal erosion and shoreline change from Sentinel-2 in Python (Holderness, 2017–2026) Advanced
- Methane plume detection in Python with NASA EMIT: mapping and quantifying landfill plumes Advanced
SAR and InSAR
Radar from first principles: speckle, floods, ships and crops with Sentinel-1, then interferometry and source modelling.
- SAR speckle filtering in Python: Lee, refined Lee, Frost and Gamma-MAP on Sentinel-1 Intermediate
- Sentinel-1 SAR flood mapping in Python: the 2022 Pakistan floods Intermediate
- Sentinel-1 ship detection in Python: a CA-CFAR detector off the Port of Rotterdam Intermediate
- Sentinel-1 crop monitoring in Python: SAR time series for wheat and oilseed rape Intermediate
- Sentinel-1 soil moisture in Python: change detection checked against COSMOS-UK Intermediate
- Earthquake damage mapping with Sentinel-1 in Python: log ratio and z-scores in Antakya Intermediate
- InSAR ground subsidence in Python: one year of Mexico City sinking, from Sentinel-1 Advanced
- InSAR volcano deformation in Python: mapping magma inflation at Svartsengi, Iceland, with Sentinel-1 Advanced
- Mogi model inversion in Python: magma depth and volume from InSAR at Svartsengi, Iceland Advanced
- InSAR time series in Python: Svartsengi inflation cycles validated with GNSS Advanced
Machine learning and AI
From rule-based maps and random forests to U-Nets, transformers and foundation-model embeddings, validated honestly.
- Habitat mapping with Sentinel-2 in Python: spectral index rules and an honest accuracy assessment Beginner
- Land cover classification in Python: a Sentinel-2 random forest with scikit-learn Intermediate
- Habitat classification with LightGBM in Python: Sentinel-2, Sentinel-1 and terrain fusion Intermediate
- Segment Anything on satellite and aerial imagery in Python: a samgeo tutorial Intermediate
- Training data for deep learning on satellite imagery: Sentinel-2 image chips in Python Intermediate
- U-Net satellite image segmentation in PyTorch: a TorchGeo and Sentinel-2 tutorial on a CPU Advanced
- Deep learning inference on large rasters: sliding-window prediction, COGs and polygons in Python Advanced
- Object-based image analysis in Python: OBIA habitat classification with Sentinel-2 Advanced
- Satellite image time series classification with deep learning: TempCNN and L-TAE in PyTorch on a CPU Advanced
- AlphaEarth satellite embeddings in Python: few-shot habitat mapping, uncertainty and area estimates Advanced
Multi-part series
One project, followed from raw data to result over several tutorials. Read them in order.
-
Geospatial Python essentials
- Coordinate reference systems in Python: EPSG codes, pyproj transforms and reprojecting vectors and rasters
- Spatial joins in GeoPandas: sjoin, predicates, sjoin_nearest and point in polygon
- Raster to vector in Python: polygonize with rasterio, rasterize boundaries and convert a GeoTIFF to a Cloud Optimized GeoTIFF
-
AI habitat classification with Python
- Habitat mapping with Sentinel-2 in Python: spectral index rules and an honest accuracy assessment
- Habitat classification with LightGBM in Python: Sentinel-2, Sentinel-1 and terrain fusion
- Object-based image analysis in Python: OBIA habitat classification with Sentinel-2
- Satellite image time series classification with deep learning: TempCNN and L-TAE in PyTorch on a CPU
- AlphaEarth satellite embeddings in Python: few-shot habitat mapping, uncertainty and area estimates
-
Volcano deformation with InSAR in Python
-
Deep learning for satellite imagery with Python
-
Mapping NO₂ air pollution from space and from the ground
-
Cloud-native vector GIS with Python