Raster–Vector Operations

Note — All operations shown here work identically on WolfArrayModel / vectorModel / zoneModel (no GUI dependency). See the Model/GUI architecture tutorial for details.

WolfArray provides a rich set of methods that combine raster data with vector geometries (polygons, polylines):

  • Masking cells inside / outside polygons

  • Extracting values inside a polygon or under a polyline

  • Interpolating Z-values from vector vertices onto the raster grid

  • Cropping to a bounding box

[1]:
from wolfhece.wolf_array import WolfArray, header_wolf
from wolfhece.PyVertexvectors import vector, zone, wolfvertex
import numpy as np
import matplotlib.pyplot as plt

Setup: a DEM-like Raster and a Polygon

[2]:
h = header_wolf()
h.shape = (100, 100)
h.set_resolution(1., 1.)
h.set_origin(0., 0.)

dem = WolfArray(srcheader=h)
# Synthetic terrain: a saddle surface
x = np.linspace(-1, 1, 100)
y = np.linspace(-1, 1, 100)
X, Y = np.meshgrid(x, y, indexing='ij')  # F-order indexing
dem.array[:, :] = 100. + 20. * X**2 - 15. * Y**2

# A polygon defining a region of interest
roi = vector(name='ROI')
roi.add_vertices_from_array(np.array([
    [20, 30], [70, 25], [80, 60], [50, 80], [15, 65]
]))
roi.closed = True
roi.find_minmax()

fig, ax = dem.plot_matplotlib()
roi.plot_matplotlib(ax)
ax.set_title('DEM + ROI polygon')
[2]:
Text(0.5, 1.0, 'DEM + ROI polygon')
../_images/tutorials_raster_vector_operations_3_1.png

Masking Outside a Polygon

mask_outsidepoly() masks all cells whose center falls outside the given polygon. This is the typical “clip to boundary” operation.

[3]:
clipped = WolfArray(mold=dem)  # copy
clipped.mask_outsidepoly(roi)
clipped.plot_matplotlib()
print(f"Valid cells after clip: {clipped.count()} / {dem.count()}")
Valid cells after clip: 2595 / 10000
../_images/tutorials_raster_vector_operations_5_1.png

Masking Inside a Polygon

mask_insidepoly() does the opposite — it removes cells inside the polygon.

[4]:
hole = WolfArray(mold=dem)
hole.mask_insidepoly(roi)
hole.plot_matplotlib()
print(f"Valid cells with hole: {hole.count()}")
Valid cells with hole: 7395
../_images/tutorials_raster_vector_operations_7_1.png

Extracting Values Inside a Polygon

get_values_insidepoly() returns the array values (and optionally their coordinates) that fall inside the polygon.

[5]:
vals, xy = dem.get_values_insidepoly(roi, getxy=True)
print(f"Number of cells inside polygon: {len(vals)}")
print(f"Elevation range: {vals.min():.2f}{vals.max():.2f}")

# Show histogram
fig, ax = plt.subplots()
ax.hist(vals, bins=30)
ax.set_xlabel('Elevation')
ax.set_ylabel('Count')
Number of cells inside polygon: 2595
Elevation range: 94.67 – 108.98
[5]:
Text(0, 0.5, 'Count')
../_images/tutorials_raster_vector_operations_9_2.png

Extracting Values along a Polyline

get_values_underpoly() returns values along a polyline (profile extraction).

[6]:
profile_line = vector(name='profile')
profile_line.add_vertices_from_array(np.array([[10, 50], [90, 50]]))
profile_line.find_minmax()

vals_under = dem.get_values_underpoly(profile_line, getxy=True)
print(f"Cells under profile: {len(vals_under[0])}")

xy = np.array(vals_under[1])  # convert list to numpy array

fig, ax = plt.subplots()
ax.plot(xy[:, 0], vals_under[0])  # x-coordinate vs elevation
ax.set_xlabel('X')
ax.set_ylabel('Elevation')
ax.set_title('Profile at Y=50')
plt.show()
Cells under profile: 81
../_images/tutorials_raster_vector_operations_11_1.png

Interpolating on a Polygon

interpolate_on_polygon() fills raster cells inside a polygon by interpolating from vertex Z-values using SciPy griddata (linear, nearest, or cubic).

[7]:
# Create a polygon with Z-values at vertices
interp_poly = vector(name='interp_region')
interp_poly.add_vertices_from_array(np.array([
    [20, 20, 80],
    [60, 20, 90],
    [80, 50, 120],
    [50, 80, 110],
    [20, 60, 85]
]))
interp_poly.closed = True
interp_poly.find_minmax()

flat = WolfArray(srcheader=h)
flat.array[:, :] = 0.
flat.nullvalue = 0.
flat.interpolate_on_polygon(interp_poly, method='linear')
flat.plot_matplotlib()
[7]:
(<Figure size 640x480 with 1 Axes>, <Axes: >)
../_images/tutorials_raster_vector_operations_13_1.png

Cropping to a Bounding Box

crop_array() returns a new WolfArray trimmed to the given bounding box [[xmin, xmax], [ymin, ymax]].

[8]:
cropped = dem.crop_array([[30, 70], [20, 60]])
print(cropped)
cropped.plot_matplotlib()
Shape  : 40 x 40
Resolution  : 1.0 x 1.0
Spatial extent :
   - Origin : (30.0 ; 20.0)
   - End : (70.0 ; 60.0)
   - Width x Height : 40.0 x 40.0
   - Translation : (0.0 ; 0.0)
Null value : 0.0


[8]:
(<Figure size 640x480 with 1 Axes>, <Axes: >)
../_images/tutorials_raster_vector_operations_15_2.png

Zonal Statistics

Combine statistics(inside_polygon=...) with a list of polygons for zonal statistics.

[9]:
from shapely.geometry import box

zones_list = [
    ('NW', box(5, 55, 45, 95)),
    ('NE', box(55, 55, 95, 95)),
    ('SW', box(5, 5, 45, 45)),
    ('SE', box(55, 5, 95, 45)),
]

for name, poly in zones_list:
    s = dem.statistics(inside_polygon=poly)
    print(f"{name}: mean={s['Mean']:.2f}, std={s['Std']:.2f}, "
          f"min={s['Min']:.2f}, max={s['Max']:.2f}")
NW: mean=101.55, std=6.01, min=88.12, max=115.98
NE: mean=101.55, std=6.01, min=88.12, max=115.98
SW: mean=101.55, std=6.01, min=88.12, max=115.98
SE: mean=101.55, std=6.01, min=88.12, max=115.98