Summarize geospatial raster datasets based on vector geometries
—
Core input/output utilities and data handling classes that support rasterstats functionality. These utilities handle reading vector data from various sources, managing raster data access, and providing coordinate system transformations.
The Raster class provides unified access to raster data from files or numpy arrays.
from rasterstats.io import Raster
class Raster:
"""
Raster abstraction for data access to 2/3D array-like things.
Use as a context manager to ensure dataset gets closed properly.
Parameters:
- raster: 2/3D array-like data source (path to raster file or numpy array)
- affine: Affine transformation (required if raster is ndarray)
- nodata: Override nodata value (default: None)
- band: Raster band number, counting from 1 (default: 1)
"""
def __init__(self, raster, affine=None, nodata=None, band=1): ...
def index(self, x, y):
"""
Convert (x, y) coordinates in CRS to (row, column) indices.
Parameters:
- x: X coordinate in coordinate reference system
- y: Y coordinate in coordinate reference system
Returns:
Tuple of (row, column) indices
"""
def read(self, bounds=None, window=None, masked=False, boundless=True):
"""
Read data from the raster source.
Parameters:
- bounds: Bounding box (w, s, e, n) (default: None)
- window: Rasterio-style window ((row_start, row_stop), (col_start, col_stop)) (default: None)
- masked: Return masked numpy array (default: False)
- boundless: Allow reading beyond dataset extent (default: True)
Returns:
Raster object with updated affine and array info
Raises:
ValueError if both bounds and window specified or neither specified
"""
# Context manager methods
def __enter__(self): ...
def __exit__(self, *args): ...Functions for reading vector data from various sources including files, GeoJSON, and geometric objects.
from rasterstats.io import read_features, read_featurecollection
def read_features(obj, layer=0):
"""
Read vector features from various input sources.
Supports:
- File paths (Shapefile, GeoJSON, etc.)
- GeoJSON strings or dictionaries
- Feature collections
- Iterables of feature-like objects
- Objects with __geo_interface__
- WKT/WKB geometry strings/bytes
Parameters:
- obj: Vector data source
- layer: Layer index or name for multi-layer sources (default: 0)
Returns:
Iterator yielding GeoJSON-like Feature dictionaries
Raises:
ValueError if object is not a recognized source of features
"""
def read_featurecollection(obj, layer=0):
"""
Read vector features and return as GeoJSON FeatureCollection.
Parameters:
- obj: Vector data source (same as read_features)
- layer: Layer index or name (default: 0)
Returns:
GeoJSON FeatureCollection dictionary with all features loaded
"""
def parse_feature(obj):
"""
Parse a single object into a GeoJSON-like Feature.
Attempts to convert various input formats:
- Objects with __geo_interface__
- WKT/WKB strings/bytes
- GeoJSON geometry or feature dictionaries
Parameters:
- obj: Object to parse as feature
Returns:
GeoJSON-like Feature dictionary
Raises:
ValueError if object cannot be parsed as a feature
"""Functions for coordinate system transformations and window calculations.
from rasterstats.io import rowcol, bounds_window, window_bounds
def rowcol(x, y, affine, op=math.floor):
"""
Convert x/y coordinates to row/column indices.
Parameters:
- x: X coordinate
- y: Y coordinate
- affine: Affine transformation
- op: Rounding operation function (default: math.floor)
Returns:
Tuple of (row, column) indices
"""
def bounds_window(bounds, affine):
"""
Create rasterio-style window from bounding box.
Parameters:
- bounds: Bounding box (west, south, east, north)
- affine: Affine transformation
Returns:
Window tuple ((row_start, row_stop), (col_start, col_stop))
"""
def window_bounds(window, affine):
"""
Calculate bounding box from rasterio-style window.
Parameters:
- window: Window tuple ((row_start, row_stop), (col_start, col_stop))
- affine: Affine transformation
Returns:
Bounding box tuple (west, south, east, north)
"""
def beyond_extent(window, shape):
"""
Check if window references pixels beyond raster extent.
Parameters:
- window: Window tuple ((row_start, row_stop), (col_start, col_stop))
- shape: Raster shape tuple (height, width)
Returns:
Boolean indicating if window extends beyond raster bounds
"""Functions for handling boundless array operations and data access.
from rasterstats.io import boundless_array
def boundless_array(arr, window, nodata, masked=False):
"""
Extract array data for window that may extend beyond array bounds.
Areas outside the array extent are filled with nodata values.
Parameters:
- arr: Input numpy array (2D or 3D)
- window: Window tuple ((row_start, row_stop), (col_start, col_stop))
- nodata: Value to use for areas outside array bounds
- masked: Return masked array (default: False)
Returns:
Numpy array (optionally masked) with data for requested window
Raises:
ValueError if array is not 2D or 3D
"""Custom warning classes for I/O operations.
from rasterstats.io import NodataWarning
class NodataWarning(UserWarning):
"""
Warning raised for nodata handling issues.
Issued when:
- No nodata value is specified and default (-999) is used
- Dataset masks are detected and masked reading is automatically enabled
"""from rasterstats.io import Raster
from affine import Affine
import numpy as np
# Using file-based raster
with Raster("elevation.tif") as rast:
# Get pixel indices for coordinates
row, col = rast.index(100.5, 200.7)
# Read full raster
full_data = rast.read()
# Read specific window
window = ((10, 50), (20, 60))
subset = rast.read(window=window, masked=True)
# Read by bounding box
bounds = (100, 200, 150, 250) # w, s, e, n
clipped = rast.read(bounds=bounds, boundless=True)
# Using numpy array
raster_array = np.random.rand(100, 100) * 1000
transform = Affine.translation(0, 100) * Affine.scale(1, -1)
with Raster(raster_array, affine=transform, nodata=-999) as rast:
subset = rast.read(bounds=(10, 10, 50, 50))
print(f"Shape: {subset.array.shape}")
print(f"Affine: {subset.affine}")from rasterstats.io import read_features, read_featurecollection
# Read from shapefile
features = list(read_features("watersheds.shp"))
print(f"Found {len(features)} features")
# Read from GeoJSON string
geojson_str = '''{"type": "Point", "coordinates": [100, 200]}'''
point_features = list(read_features(geojson_str))
# Read from feature collection
fc = read_featurecollection("polygons.geojson")
print(f"FeatureCollection with {len(fc['features'])} features")
# Read from list of geometries
geometries = [
{"type": "Point", "coordinates": [100, 200]},
{"type": "Point", "coordinates": [150, 250]}
]
point_list = list(read_features(geometries))
# Handle multi-layer sources
layers = list(read_features("multilayer.gpkg", layer="roads"))from rasterstats.io import rowcol, bounds_window, window_bounds
from affine import Affine
import math
# Create sample transform
transform = Affine.translation(100, 200) * Affine.scale(1, -1)
# Convert coordinates to pixel indices
row, col = rowcol(105.5, 195.3, transform)
print(f"Pixel location: row {row}, col {col}")
# Using ceiling operation for different rounding
row_ceil, col_ceil = rowcol(105.5, 195.3, transform, op=math.ceil)
# Create window from bounds
bounds = (100, 150, 200, 250) # w, s, e, n
window = bounds_window(bounds, transform)
print(f"Window: {window}")
# Get bounds back from window
calculated_bounds = window_bounds(window, transform)
print(f"Bounds: {calculated_bounds}")from rasterstats.io import boundless_array, beyond_extent
import numpy as np
# Create sample array
arr = np.random.rand(50, 50) * 100
shape = arr.shape
# Define window that extends beyond array
large_window = ((45, 65), (45, 65)) # Extends 15 pixels beyond
if beyond_extent(large_window, shape):
print("Window extends beyond array bounds")
# Extract data with nodata fill
result = boundless_array(arr, large_window, nodata=-999, masked=True)
print(f"Result shape: {result.shape}")
print(f"Original array shape: {arr.shape}")
print(f"Nodata pixels: {(result == -999).sum()}")from typing import Union, List, Dict, Any, Optional, Tuple, Iterator
from numpy import ndarray
from affine import Affine
# Input types
VectorSource = Union[str, Dict, List[Dict], bytes] # Various vector input formats
RasterSource = Union[str, ndarray] # File path or numpy array
LayerSpec = Union[int, str] # Layer index or name
GeometryDict = Dict[str, Any] # GeoJSON geometry dictionary
FeatureDict = Dict[str, Any] # GeoJSON feature dictionary
# Coordinate types
Bounds = Tuple[float, float, float, float] # (west, south, east, north)
Window = Tuple[Tuple[int, int], Tuple[int, int]] # ((row_start, row_stop), (col_start, col_stop))
Coordinates = Tuple[float, float] # (x, y) coordinate pair
PixelIndices = Tuple[int, int] # (row, column) indices
# Array types
BoundlessArray = Union[ndarray, np.ma.MaskedArray] # Regular or masked array
ArrayShape = Tuple[int, int] # (height, width) for 2D arraysInstall with Tessl CLI
npx tessl i tessl/pypi-rasterstats