Skip to content

Commit

Permalink
Merge pull request python-rasters#26 from gregory-halverson-jpl/main
Browse files Browse the repository at this point in the history
inverse distance weighting point extraction
  • Loading branch information
gregory-halverson authored Nov 7, 2024
2 parents 333ce61 + 904f54f commit c84b06f
Showing 1 changed file with 49 additions and 4 deletions.
53 changes: 49 additions & 4 deletions rasters/raster.py
Original file line number Diff line number Diff line change
Expand Up @@ -969,12 +969,25 @@ def bbox(self) -> BBox:
def geolocation(self) -> Raster:
return self.contain(geometry=self.geometry.geolocation)

def to_point(self, point: Point):
def to_point(self, point: Point, method: str = None, **kwargs):
if not self.geometry.intersects(point):
return np.nan

if method is None:
if np.issubdtype(self.dtype, np.integer):
method = "nearest"
elif np.issubdtype(self.dtype, np.floating):
method = "IDW"
else:
method = "nearest"

index = self.geometry.index_point(point)
value = self.array[index].item()
if method == "nearest":
index = self.geometry.index_point(point)
value = self.array[index].item()
elif method == "IDW":
value = self.IDW(geometry=point, **kwargs)
else:
raise ValueError(f"unrecognized point sampling method: {method}")

return value

Expand Down Expand Up @@ -1146,17 +1159,49 @@ def pixel_centroids(self) -> gpd.GeoDataFrame:
def pixel_outlines(self) -> gpd.GeoDataFrame:
return gpd.GeoDataFrame({"value": self.array.flatten()}, geometry=list(self.geometry.pixel_outlines))

def IDW(self, geometry: VectorGeometry, power: float = 2):
def IDW(self, geometry: VectorGeometry, power: float = 2) -> Union[float, gpd.GeoDataFrame]:
"""
Performs Inverse Distance Weighting (IDW) interpolation on a given geometry.
Args:
geometry (VectorGeometry): The target geometry for interpolation.
power (float, optional): The power parameter controlling the rate of decay of distance influence. Defaults to 2.
Returns:
Union[float, gpd.GeoDataFrame]:
- If the input geometry is a single point, returns the interpolated value as a float.
- If the input geometry is a GeoDataFrame, returns a new GeoDataFrame with the interpolated values.
Raises:
ValueError: If the input geometry is not supported.
"""

if isinstance(geometry, shapely.geometry.Point):
# Wrap the point geometry for efficient distance calculations
geometry = wrap_geometry(geometry)

# Get the centroids of the pixels in the underlying raster
pixel_centroids = self.geometry.pixel_centroids

# Calculate distances between the input point and pixel centroids
distances = geometry.distances(pixel_centroids)

# Extract values from the raster array
value = self.array.flatten()

# Convert distances to a NumPy array
distance = np.array(distances["distance"])

# Calculate weights based on inverse distance
weight = 1 / distance ** power

# Calculate weighted values
weighted = value * weight

# Calculate the interpolated value using weighted summation
result = np.nansum(weighted) / np.nansum(weight)

# Return the result based on the input geometry type
if isinstance(geometry, SingleVectorGeometry):
return result
else:
Expand Down

0 comments on commit c84b06f

Please sign in to comment.