# Import modules
import numpy as np
import pandas as pd
import geopandas as gpd
import matplotlib.pyplot as plt
from scipy.interpolate import CloughTocher2DInterpolator, LinearNDInterpolator
89 Built-in spatial interpolators
Spatial interpolation is a technique where regaurly spaced or irregularly spaced data points distributed across a region are used to estimate the value at unsampled points. In this tutorial, we will use Scipy’s LinearNDInterpolator
and CloughTocher2DInterpolator
functions for approximating soil moisture values at unsampled locations between non-regularly spaced observations.
The LinearNDInterpolator
consists of a piece-wise linear interpolation to estimate values at arbitrary locations within the convex hull formed by the input data points.
The CloughTocher2DInterpolator
uses a triangular interpolation, which provides a smoother and potentially more accurate representation of the data’s spatial variation. This method constructs a continuous surface over the input data by fitting quadratic surfaces for each triangle formed by the data points.
# Define coordiante reference systems
= 32614 # UTM Zone 14
crs_utm = 4326 # WGS84 crs_wgs
# Read dataset
= pd.read_csv('../datasets/spatial/soil_moisture_surveys/kona_15_jul_2019.csv')
df
# Inspect a few rows
3) df.head(
TimeStamp | Record | Zone | Latitude | Longitude | Moisture | Period | Attenuation | Permittivity | Probe Model | Sensor | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 7/15/2019 7:15 | 320 | ZONE 00001 | 39.11060 | -96.61089 | 38.88 | 1.6988 | 1.8181 | 23.8419 | CD659 12cm rods | 3543 |
1 | 7/15/2019 7:17 | 321 | ZONE 00001, ZONE 00011 | 39.11058 | -96.61116 | 41.71 | 1.7474 | 1.8310 | 26.7794 | CD659 12cm rods | 3543 |
2 | 7/15/2019 7:17 | 322 | ZONE 00001, ZONE 00011 | 39.11055 | -96.61146 | 40.59 | 1.7271 | 1.7911 | 25.5712 | CD659 12cm rods | 3543 |
# Drop lines with NaN in 'Moisture' column
='Moisture', inplace=True)
df.dropna(subset=True, inplace=True) df.reset_index(drop
# Convert Dataframe to GeoDataframe
= gpd.GeoDataFrame(df) gdf
# Add Point geometry from lat and long values
'points'] = gpd.points_from_xy(gdf['Longitude'], gdf['Latitude'])
gdf['points', drop=True, inplace=True, crs=crs_wgs) gdf.set_geometry(
# Inspect spatial data
=(5,4))
plt.figure(figsize'KONA field')
plt.title(=plt.gca(), edgecolor='k', marker='.', s=80, column='Moisture',
gdf.plot(ax='Spectral', scheme='equal_interval', k=8, legend=True,
cmap={'loc':'upper left',
legend_kwds'bbox_to_anchor':(1.05,1),
'title':'Soil moisture (%)'})
'Longitude')
plt.xlabel('Latitude')
plt.ylabel( plt.show()
# Convert point coordinates to UTM, so that we can work in meters
# to compute distances within the field
=crs_utm, inplace=True) gdf.to_crs(crs
# Get values of longitude (x) and latitude (y) in meters
= gdf['geometry'].x.values
x = gdf['geometry'].y.values
y = gdf['Moisture'].values
z
# Create tuple of points
= (x, y) points
# Generate grid
= np.linspace(x.min(), x.max(), num=100)
x_vec = np.linspace(y.min(), y.max(), num=100)
y_vec
# Create grid
= np.meshgrid(x_vec, y_vec)
X_grid, Y_grid print(X_grid.shape)
(100, 100)
# Interpolation using LinearNDInterpolator
= LinearNDInterpolator(list(zip(x, y)), z)
NDinterp = NDinterp(X_grid, Y_grid) Z_grid_NDinterp
# Interpolation using CloughTocher
= CloughTocher2DInterpolator(list(zip(x, y)), z)
CTinterp = CTinterp(X_grid, Y_grid) Z_grid_CTinterp
=(10,4))
plt.figure(figsize
1,2,1)
plt.subplot('Piecewise linear')
plt.title(= plt.pcolormesh(X_grid, Y_grid, Z_grid_NDinterp,
p1 ='Spectral', vmin=z.min(), vmax=z.max())
cmap='k', marker='.', s=5)
plt.scatter(x, y, color='Soil moisture(%)')
plt.colorbar(p1, label"equal")
plt.axis('Easting')
plt.xlabel('Northing')
plt.ylabel(
1,2,2)
plt.subplot('CloughTocher')
plt.title(= plt.pcolormesh(X_grid, Y_grid, Z_grid_CTinterp,
p2 ='Spectral', vmin=z.min(), vmax=z.max())
cmap='k', marker='.', s=5)
plt.scatter(x, y, color='Soil moisture(%)')
plt.colorbar(p2, label"equal")
plt.axis('Easting')
plt.xlabel('Northing')
plt.ylabel(
=0.3)
plt.subplots_adjust(wspace plt.show()