2

I have a geographic point layer with field values that are independent of slope (all green points below), and I need to estimate those field values for a second point layer (all red points below).

So for example, the value of point 1 (first red point) might be interpolated to something like 770, and the value of point 2 (second red point) might be something like 1500. It's fine that the output would be a rough estimate - I'm looking for a tool or methods that can do this without any raster info/slope info inputted, and ideally averaging all nearby points within a given radius rather than just nearest neighbor. I think IDW interpolation may be what I'm looking for, but want to confirm since I don't have the Esri Spatial Analyst license for it (and am not working in 3D anyway).

Point Estimation

1
  • Generate near table with big radius and transfer z values to it. Average by in_fid Commented yesterday

1 Answer 1

2

You could use IDW in python (without Spatial Analyst) with the GDAL library which is included in the standard ArcGIS Pro python install (arcgispro-py3).

Here is some example code that uses gdal.Grid IDW interpolation to generate an interpolated raster from the green points, sample the interpolated values under the red points and then writes out a CSV file that you could then join back to the red points. For more information on GDAL gridding interpolation options see the gdal_grid documentation and GDAL Grid Tutorial.

from math import floor, ceil
from osgeo import (gdal, ogr)
import pandas as pd

gdal.UseExceptions()

def sample(raster, points, id_field="ID", sample_field="VALUE", layer=None):
    ras_ds=gdal.Open(raster)
    gt_forward=ras_ds.GetGeoTransform()
    gt_reverse=gdal.InvGeoTransform(gt_forward)
    rb=ras_ds.GetRasterBand(1)

    pt_ds=ogr.Open(points)

    if layer is None:
        lyr = pt_ds.GetLayer()
    else:
        lyr = pt_ds.GetLayerByName(layer)

    data = {
        id_field: [],
        sample_field: []
    }

    for feat in lyr:
        geom = feat.GetGeometryRef()
        mx,my=geom.GetX(), geom.GetY()  #coord in map units

        #Convert from map to pixel coordinates.
        px, py = gdal.ApplyGeoTransform(gt_reverse, mx, my)
        px = floor(px) #x pixel
        py = floor(py) #y pixel

        intval = rb.ReadAsArray(px, py, 1, 1)
        data[id_field].append(feat.GetField(id_field))
        data[sample_field].append(intval[0][0])  #intval is a numpy array, length=1,1 as we only asked for 1 pixel value

    return pd.DataFrame(data)


def interpolate(input_points, input_field, output_raster, pixel_size, input_layer=None):

    pt_ds = ogr.Open(input_points)
    if input_layer is None:
        lyr = pt_ds.GetLayer()
        layers = None
    else:
        lyr = pt_ds.GetLayerByName(input_layer)
        layers = [input_layer]

    xmin, xmax, ymin, ymax = lyr.GetExtent()
    ncols = ceil((xmax - xmin) / pixel_size)
    nrows = ceil((ymax - ymin) / pixel_size)

    gdal.Grid(
        output_raster,
        input_points,
        layers=layers,
        zfield=input_field,
        algorithm="invdist",
        format='GTiff',
        width=ncols,
        height=nrows
    )


if __name__ == "__main__":
    # Example using shapefiles
    input_points = "green.shp"
    input_field = "VALUE"

    sample_points = "red.shp"
    sample_field = "VALUE"
    id_field = "ID"
    output_raster = "idw.tif"

    output_csv = "values.csv"

    pixel_size = 50

    interpolate(input_points, input_field, output_raster, pixel_size)

    samples = sample(output_raster, sample_points, id_field, sample_field)
    samples.to_csv(output_csv, index=False)

    # Example using FileGDB feature classes
    input_points = "points.gdb"
    input_layer = "green"
    input_field = "VALUE"

    sample_points = "points.gdb"
    sample_layer = "red"
    sample_field = "VALUE"
    id_field = "ID"

    output_raster = "idw.tif"
    output_csv = "values.csv"

    pixel_size = 50

    interpolate(input_points, input_field, output_raster, pixel_size, input_layer=input_layer)

    samples = sample(output_raster, sample_points, id_field, sample_field, sample_layer)
    samples.to_csv(output_csv, index=False)

And here is the output (using QGIS as I'm not at work today and don't have access to ArcGIS Pro):

values.csv:

ID VALUE
1 881.000793457031
2 1311.878662109375

enter image description here

1
  • Thanks so much - I got it working. I initally got thrown errors about "Access window out of range in RasterIO()" where the requested raster size during sampling exceeded the size of the initial interpolation. It worked when I multiplied px by 0.995 (the highest decimal that worked) in addition to floor(), and it was still accurate enough for my needs. I also had to make sure my layers were in the same coordinate system. Appreciate the time you took to solve my example and give context. I have limited experience with GDAL, but will be looking at it more as an alternative to ArcGIS Pro. Commented 2 hours ago

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.