How to interpolate geospatial points to contours with Python and GDAL - Tutorial
/We have developed an alternative to a common procedure in GIS that is to create contours from a point shapefile but just with Python commands. By the use of Python and the GDAL library we can store this process into a function and perform contours from several point sets or different point queries.
The tutorial covers two steps:
Step 1: Creating an interpolated raster
Step2: Create contours from raster
Two options are presented to perform the contours: As a detailed description of all the involved steps and a compiled version of the script on a funcion that is called from a Jupyter notebook.
More infomation on the Gdal tools to perform rasters: https://gdal.org/programs/gdal_grid.html
Tutorial
Code
This is the whole Python
import fiona
import numpy as np
from osgeo import osr
from osgeo import ogr
from osgeo import gdal
Step 1: Creating an interpolated raster
# open point shapefile
gwShp = fiona.open('../Shp/gwWells.shp')
# get spatial bounds
gwBounds = gwShp.bounds
gwBounds
(-74.8156722, 40.2675333, -74.8083056, 40.27368889)
# review attribute table for first row
gwShp[0]
{'type': 'Feature',
'id': '0',
'properties': OrderedDict([('SiteNo', 401603074485301.0),
('Latitude', 40.2675333),
('Longitude', -74.8143306),
('LatLonDatu', 'NAD83'),
('SurfaceEle', 150.02),
('ElevationD', 'NAVD88'),
('HoleDepth', 48.0)]),
'geometry': {'type': 'Point', 'coordinates': (-74.8143306, 40.2675333)}}
# create geospatial raster
rasterDs = gdal.Grid('../Rst/interpolatedElevations.tif', '../Shp/gwWells.shp', format='GTiff',
algorithm='invdist', zfield='SurfaceEle')
rasterDs.FlushCache()
Step2: Create contours from raster
# get raster system of reference
proj = osr.SpatialReference(wkt=rasterDs.GetProjection())
proj.ExportToWkt()
'GEOGCS["NAD83",DATUM["North_American_Datum_1983",SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],AUTHORITY["EPSG","6269"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AXIS["Latitude",NORTH],AXIS["Longitude",EAST],AUTHORITY["EPSG","4269"]]'
# get raster band
rasterBand = rasterDs.GetRasterBand(1)
# get elevation as numpy array
elevArray = rasterBand.ReadAsArray()
print(elevArray[:4,:4])
[[153.22245789 153.19668579 153.1703949 153.15008545]
[153.222229 153.19682312 153.17120361 153.15127563]
[153.22180176 153.19685364 153.17160034 153.15223694]
[153.22125244 153.19676208 153.17181396 153.15299988]]
# define not a number
demNan = -32768
# get dem max and min
demMax = elevArray.max()
demMin = elevArray[elevArray!=demNan].min()
print("Maximun dem elevation: %.2f, minimum dem elevation: %.2f"%(demMax,demMin))
Maximun dem elevation: 175.56, minimum dem elevation: 143.39
# define output shapefile
contourPath = '../shp/contoursIncremental.shp'
contourDs = ogr.GetDriverByName("ESRI Shapefile").CreateDataSource(contourPath)
# define layer name and coordinate system
contourShp = contourDs.CreateLayer('contour', proj)
# define fields of id and elev
fieldDef = ogr.FieldDefn("ID", ogr.OFTInteger)
contourShp.CreateField(fieldDef)
fieldDef = ogr.FieldDefn("elev", ogr.OFTReal)
contourShp.CreateField(fieldDef)
0
#define number of contours and range
conNum = 10
conList =[int(x) for x in np.linspace(demMin,demMax,conNum)]
# write shapefile using noDataValue
#ContourGenerate(Band srcBand, double contourInterval, double contourBase, int fixedLevelCount, int useNoData, double noDataValue,
# Layer dstLayer, int idField, int elevField
gdal.ContourGenerate(rasterBand, 0, 0, conList, 1, -32768.,
contourShp, 0, 1)
contourDs.Destroy()
And this is the function version of the code
from workingTools import createContours
createContours('../Shp/gwWells.shp', #point shapefile
'SurfaceEle', #column name
'../Rst/interpolatedElevations2.tif', #raster file
'../Shp/contoursIncremental2.shp', #contour shapefile
20)
Maximun dem elevation: 175.56, minimum dem elevation: 143.39
Input files
You can download the input files from this link.