Raster Geoprocessing

Pyspatialml includes common geoprocessing methods that collectively operate on stacks of raster datasets, such as cropping, reprojecting, masking etc. Most of these methods are simple wrappers around underlying rasterio functions, but applied to stacks of raster datasets.

Handling of Temporary Files

All of the geoprocessing methods have a file_path parameter to specify a file path to save the results of th geoprocessing operation. However, pyspatialml is designed for quick an interactive analyses on raster datasets, and if a file path is not specified then the results are saved to a temporary file location and a new Raster object is returned with the geoprocessing results.

Cropping

All layers within a Raster can be cropped to a new extent using the Raster.crop method.

import geopandas as gpd
from pyspatialml import Raster
from pyspatialml.datasets import nc

predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7]

stack = Raster(predictors)

# crop to new extent (xmin, ymin, xmax, ymax)
crop_bounds = training_py.loc[0, "geometry"].bounds
stack_cropped = stack.crop(self.crop_bounds)

Masking

In comparison to cropping, masking can be used to set pixels that occur outside of masking geometries to NaN, and optionally can also crop a Raster.

import geopandas as gpd
import pyspatialml.datasets.nc as nc
from pyspatialml import Raster

training_py = gpd.read_file(nc.polygons)
mask_py = training_py.iloc[0:1, :]

predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7]
stack = Raster(predictors)

# mask a Raster
masked_object = stack.mask(mask_py)

Intersecting Layers

The Raster.intersect method computes the geometric intersection of the RasterLayers with the Raster object. This will cause nodata values in any of the rasters to be propagated through all of the output rasters.

import pyspatialml.datasets.nc as nc
from pyspatialml import Raster

predictors = [nc.band1, nc.band2, nc.band3, nc.band4, nc.band5, nc.band7]
stack = Raster(predictors)

result = stack.intersect()

The intersect method is memory-safe, i.e. the intersection occurs during windowed reading and writing of the Raster. The size and dimensions of the windows can be changed using the Raster.block_shapes property.

Reprojecting

Reprojecting a raster using the Raster.to_crs method.

stack_prj = stack.to_crs(crs={"init": "EPSG:4326"})

Other parameters that can be passed and their defaults are resampling=”nearest”, file_path=None, driver=”GTiff”, nodata=None, n_jobs=1, warp_mem_lim=0, progress=False, and other kwargs that are passed to the raster format drivers.

Resampling

The Raster.aggregate method is used to resample a raster to a different resolution using the decimated reading approach in the rasterio library.

stack.aggregate(out_shape, resampling="nearest", file_path=None,
                driver="GTiff", dtype=None, nodata=None, **kwargs)

Computation

Apply user-supplied function to a Raster object.

stack.apply(self, function, file_path=None, driver="GTiff", dtype=None,
            nodata=None, progress=False, n_jobs=-1, function_args={},
            **kwargs)

Where function is a user-defined python that takes an numpy array as a single argument, and can return either a 2d array that represents a single raster dataset, such as NDVI, or can operate on a number of layers and can return a raster with multiple layers in a 3d array in (layer, row, col) order.

The apply function is memory-safe, i.e. it applies the function to windows of the raster data that are read sequentially or in parallel (with n_jobs != 1). The size and dimensions of the windows can be changed using the Raster.block_shapes property.

Raster Algebra

RasterLayer objects also support basic raster math operations using python’s magic methods, which supports all of the usual math operators. Calculations on RasterLayers occur in memory using Rasterio’s in-memory files, thus they are not memory safe. For applying computations and algebra to large raster datasets in windows, using Raster.apply().

a = stack.iloc[0] + stack.iloc[1]
b = stack.iloc[0] - stack.iloc[1]

ndvi = (stack.iloc[3] - stack.iloc[2]) / (stack.iloc[3] + stack.iloc[2])