Fast and direct raster I/O for use with Numpy and SciPy
—
Efficient reading and writing of rectangular subsets of raster data. The Window class and related functions support coordinate-based and index-based windowing with geometric operations for spatial subsetting.
Represents a rectangular subset of a raster dataset defined by pixel coordinates.
class Window:
"""Rectangular raster window."""
def __init__(self, col_off, row_off, width, height):
"""
Initialize window from pixel coordinates.
Parameters:
- col_off (float): Column (x) offset from dataset origin
- row_off (float): Row (y) offset from dataset origin
- width (float): Window width in pixels
- height (float): Window height in pixels
"""
# Properties
col_off: float # Column offset
row_off: float # Row offset
width: float # Window width
height: float # Window height
@property
def c(self):
"""Column offset (alias for col_off)."""
@property
def r(self):
"""Row offset (alias for row_off)."""
@property
def w(self):
"""Width (alias for width)."""
@property
def h(self):
"""Height (alias for height)."""
def flatten(self):
"""Return window as tuple (col_off, row_off, width, height)."""
def todict(self):
"""Return window as dictionary."""
def toslices(self):
"""Convert to array slices (row_slice, col_slice)."""
def round_lengths(self, op='floor', pixel_precision=3):
"""Round window dimensions."""
def round_offsets(self, op='floor', pixel_precision=3):
"""Round window offsets."""Usage examples:
from rasterio.windows import Window
# Create window from pixel coordinates
window = Window(100, 200, 512, 512) # col_off, row_off, width, height
# Access properties
print(f"Column offset: {window.col_off}") # 100
print(f"Row offset: {window.row_off}") # 200
print(f"Width: {window.width}") # 512
print(f"Height: {window.height}") # 512
# Alternative property access
print(f"Position: ({window.c}, {window.r})") # (100, 200)
print(f"Size: {window.w} x {window.h}") # 512 x 512
# Convert to different formats
window_tuple = window.flatten() # (100, 200, 512, 512)
window_dict = window.todict() # {'col_off': 100, 'row_off': 200, ...}
row_slice, col_slice = window.toslices() # Array slicing objects
# Use window for reading
with rasterio.open('large_raster.tif') as dataset:
# Read windowed data
data = dataset.read(1, window=window)
print(f"Read data shape: {data.shape}") # (512, 512)Utilities for creating windows from various spatial parameters.
def from_bounds(left, bottom, right, top, transform, height=None, width=None,
precision=None):
"""
Create window from geographic bounds.
Parameters:
- left (float): Left (minimum x) coordinate
- bottom (float): Bottom (minimum y) coordinate
- right (float): Right (maximum x) coordinate
- top (float): Top (maximum y) coordinate
- transform (Affine): Dataset geospatial transformation
- height (int): Dataset height for validation
- width (int): Dataset width for validation
- precision (int): Rounding precision for coordinates
Returns:
Window: Window covering the specified bounds
"""
def get_data_window(arr, nodata=None):
"""
Calculate window covering non-nodata pixels.
Parameters:
- arr (numpy.ndarray): Input raster array
- nodata (number): NoData value to exclude
Returns:
Window: Window covering valid data extent
"""Usage examples:
from rasterio.windows import from_bounds, get_data_window
import rasterio
# Create window from geographic bounds
with rasterio.open('dataset.tif') as dataset:
# Define area of interest
aoi_bounds = (-120.5, 35.2, -119.8, 35.9) # left, bottom, right, top
# Create window covering these bounds
window = from_bounds(*aoi_bounds, dataset.transform)
# Read data for area of interest
aoi_data = dataset.read(1, window=window)
# Get transform for windowed data
window_transform = dataset.window_transform(window)
# Find data extent window
with rasterio.open('sparse_dataset.tif') as dataset:
full_data = dataset.read(1)
# Get window covering only valid data
data_window = get_data_window(full_data, nodata=dataset.nodata)
# Read only the data extent
valid_data = dataset.read(1, window=data_window)Functions for combining and manipulating windows geometrically.
def union(*windows):
"""
Create window covering the union of input windows.
Parameters:
- *windows: Variable number of Window objects
Returns:
Window: Window covering all input windows
"""
def intersection(*windows):
"""
Create window covering the intersection of input windows.
Parameters:
- *windows: Variable number of Window objects
Returns:
Window or None: Intersecting window, or None if no intersection
"""
def intersect(*windows):
"""
Test if windows intersect.
Parameters:
- *windows: Variable number of Window objects
Returns:
bool: True if all windows intersect
"""Usage examples:
from rasterio.windows import union, intersection, intersect
# Create overlapping windows
window1 = Window(0, 0, 100, 100) # Top-left quadrant
window2 = Window(50, 50, 100, 100) # Overlapping area
window3 = Window(200, 200, 50, 50) # Non-overlapping area
# Union of windows
combined_window = union(window1, window2)
print(f"Union covers: {combined_window}") # Covers both windows
# Intersection of windows
overlap_window = intersection(window1, window2)
if overlap_window:
print(f"Overlap area: {overlap_window}") # Window(50, 50, 50, 50)
# Test for intersection
has_overlap = intersect(window1, window2) # True
no_overlap = intersect(window1, window3) # False
# Multiple window operations
all_windows = union(window1, window2, window3) # Covers all three
common_area = intersection(window1, window2, window3) # NoneUtilities for converting between window and geographic coordinates.
def bounds(window, transform):
"""
Calculate geographic bounds of window.
Parameters:
- window (Window): Raster window
- transform (Affine): Geospatial transformation
Returns:
BoundingBox: Geographic bounds (left, bottom, right, top)
"""
def transform(window, src_transform):
"""
Calculate transformation matrix for windowed data.
Parameters:
- window (Window): Raster window
- src_transform (Affine): Source dataset transformation
Returns:
Affine: Transformation for windowed data
"""Usage examples:
from rasterio.windows import bounds, transform
from rasterio.coords import BoundingBox
# Calculate window bounds
window = Window(100, 200, 512, 512)
with rasterio.open('dataset.tif') as dataset:
# Get geographic bounds of window
window_bounds = bounds(window, dataset.transform)
print(f"Window bounds: {window_bounds}")
# Get transformation for windowed data
window_transform = transform(window, dataset.transform)
# Read windowed data
windowed_data = dataset.read(1, window=window)
# Windowed data has its own coordinate system
height, width = windowed_data.shape
windowed_bounds = array_bounds(height, width, window_transform)
# Should match window_bounds
assert windowed_bounds == window_boundsHelper functions for window validation and manipulation.
def crop(raster, window):
"""
Crop raster array using window.
Parameters:
- raster (numpy.ndarray): Input raster array
- window (Window): Cropping window
Returns:
numpy.ndarray: Cropped array
"""
def validate_window(window, height, width):
"""
Validate window against dataset dimensions.
Parameters:
- window (Window): Window to validate
- height (int): Dataset height
- width (int): Dataset width
Returns:
bool: True if window is valid
"""Usage examples:
# Crop array using window
full_array = dataset.read(1)
window = Window(100, 100, 200, 200)
cropped_array = crop(full_array, window)
# Validate window bounds
is_valid = validate_window(window, dataset.height, dataset.width)
if not is_valid:
print("Window extends beyond dataset bounds")
# Safe windowed reading with validation
def safe_read_window(dataset, window, band=1):
if validate_window(window, dataset.height, dataset.width):
return dataset.read(band, window=window)
else:
raise ValueError("Window extends beyond dataset bounds")Window operations can raise specific exceptions for invalid windows or operations:
class WindowError(RasterioError):
"""Window operation related errors."""Common error scenarios:
from rasterio.errors import WindowError
try:
# Invalid window dimensions
invalid_window = Window(-10, -10, 100, 100) # Negative offsets
validate_window(invalid_window, 1000, 1000)
except WindowError as e:
print(f"Invalid window: {e}")
# Window extending beyond dataset
large_window = Window(900, 900, 200, 200) # Extends beyond 1000x1000 dataset
try:
with rasterio.open('small_dataset.tif') as dataset:
data = dataset.read(1, window=large_window) # May raise WindowError
except WindowError as e:
print(f"Window out of bounds: {e}")Install with Tessl CLI
npx tessl i tessl/pypi-rasterio