Skip to content

The interpolate function

This file defines the interpolate function's top and mid-level definitions, allowing the low level definitions to be Define the API as well as the toplevel conversion methods

julia
function interpolate(interpolator::AbstractInterpolationMethod, target, sources; kwargs...)
    return interpolate(interpolator, GI.trait(target), GI.trait(sources), target, sources; kwargs...)
end

Address the possibility that the target is a single geometry. In this case, we return weights. Should we return a Feature, though?

julia
function interpolate(interpolator::AbstractInterpolationMethod, ::Union{GI.PolygonTrait, GI.MultiPolygonTrait}, ft::Union{GI.FeatureCollectionTrait, Nothing}, target, sources; features = nothing, kwargs...)
    source_geometries, source_values = decompose_to_geoms_and_values(sources; features)
    source_rtree = SortTileRecursiveTree.STRtree(source_geometries)

It's the FC -> FC level that has to deal with reconstructing features, so we don't do that here.

julia
    return interpolate(interpolator, target, source_geometries, source_values, GO.area.(source_geometries), source_rtree; kwargs...)
end

An algorithm which benefits from batching, or has a single processing step for the whole source collection, should override the version of interpolate that this calls.

julia
function interpolate(interpolator::AbstractInterpolationMethod, TargetTrait::Union{GI.FeatureCollectionTrait, Nothing}, SourceTrait::Union{GI.FeatureCollectionTrait, Nothing}, target, sources; features = nothing, threaded = true, kwargs...)

First, we extract the geometry and values from the source FeatureCollection

julia
    source_geometries, source_values = decompose_to_geoms_and_values(sources; features)

Then, we also extract the geometries from the target FeatureCollection. In this case, we explicitly request all features, so that we can reconstruct the featurecollection later.

julia
    target_geometries, target_values = decompose_to_geoms_and_values(target; features = setdiff(Tables.columnnames(target), GI.geometrycolumns(target)))

We build an STRtree for the source geometries

julia
    source_rtree = SortTileRecursiveTree.STRtree(source_geometries)

Finally, we interpolate the polygons one by one. This is done by passing them to the "kernel" which is defined per interpolator.

julia
    source_areas = GO.area.(source_geometries)
    function _interp_poly(polygon)
        interpolate(interpolator, polygon, source_geometries, source_values, source_areas, source_rtree; kwargs...)
    end
    interpolated_feature_values = if threaded
        OhMyThreads.tmap(_interp_poly, target_geometries)
    else
        map(_interp_poly, target_geometries)
    end

The result of map above is a canonical row table form, being a Vector of NamedTuples. We can convert it directly into a column table, i.e., a NamedTuple of Vectors, using Tables.

julia
    new_feature_columns = Tables.columntable(interpolated_feature_values)

We create the final "column table", a NamedTuple of Vectors, by merging the target geometries with the target values and the new feature columns.

julia
    final_namedtuple = merge(
        NamedTuple{(first(GI.geometrycolumns(target)),)}((target_geometries,)),
        target_values,
        new_feature_columns
    )

Finally, we reconstruct and return – currently as a DataFrame, but in the future we should reconstruct based on the type of target. GeometryOps can help there. For Tables, we could use Tables.materializer, but should check - if materializer returns Tables.columntable, then we substitute that for DataFrame(x; copycols = false).

julia
    return DataFrames.DataFrame(final_namedtuple)
end

This page was generated using Literate.jl.