Generate distance raster using arbitrary sets of spatial features
Distance-rasters was designed to support the generation of rasters in which each pixel is the distance to a discrete set of user defined locations. Common uses include calculating the distances to roads, water features, or cities. Distance-rasters is flexible and can support a wide range of use cases and input data, and provides the tools necessary for rasterizing vector features.
The most notable existing tool for calculating raster distance or proximity is GDAL's gdal_proximity.py
which while powerful, is not flexible enough for many use cases and has practical limitations when integrating distance calculations into broader workflows. Distance-rasters offers a simple, flexible, and Pythonic alternative.
See the Example section below for a simple example of using distance-rasters. Distance-rasters is extremely fast for small areas at moderate resolution, and has performed well when tested at global scales with moderate-coarse resolution (1km).
The below example calculates the distance to a rough approximation of a section of the Niger river in Mali. See the examples
folder for the code and data.
import fiona
import distancerasters as dr
# load vector data (crs = epsg:4326)
shp = fiona.open("examples/linestrings.geojson", "r")
# resolution (in units matching projection) at which vector data will be rasterized
pixel_size = 0.01
# rasterize vector data and output to geotiff
rv_array, affine = dr.rasterize(shp, pixel_size=pixel_size, bounds=shp.bounds, output="examples/linestrings_rasterized_binary.tif")
"""
# you can manually export rasterized vector data if needed
dr.export_raster(rv_array, affine, "linestrings_rasterized_binary.tif")
# you can also load an existing raster directly to use for distance calculations
import rasterio
with rasterio.open("examples/linestrings_rasterized_binary.tif") as src:
affine = src.transform
rv_array = src.read(1)
"""
# function to define which cells from rasterized input to calculate distance to
# - this is the default function, and does not need to be explicity passed to class
# - this would be modified if using a non-binary rasterization
def raster_conditional(rarray):
return (rarray == 1)
# generate distance array and output to geotiff
my_dr = dr.DistanceRaster(rv_array, affine=affine,
output_path="examples/linestrings_distance_raster.tif",
conditional=raster_conditional)
# dist_array = my_dr.dist_array
# Output:
#
# Tree build time: 0.0330 seconds
# Building distance array...
# Total run time: 2.88 seconds
The resulting distance raster indicates the distance to the line segment. In the image below, areas close to the line segment (in dark blue) are yellow and get darker the further away you go.
An additional example is included in examples/adv_rasterization_example.py
to demonstrate how multiple sets of vector data can be combined to create a distance raster. This example also illustrates how the area for which distances are calculated can be adjusted based on a user's needs.
- Distance-rasters primarily uses an implementation of the Haversine formula to calculate distance in kilometers
- For the best results, convert your data to EPSG 4326 (i.e., "WGS84") before using distance-rasters. Performing this conversion prior to using distance-rasters allows the package to remain lightweight and return results fast and accurately.
- If you do not want to convert your data to EPSG 4326, or are using non-geographic data already in a raster/array format (i.e., an abritrary grid) you can pass the data to the
DistanceRaster
class without anaffine
oroutput_path
argument in order to use a simple Euclidean/index based distance calculation.
The latest version of distance-rasters is available on PyPi, and can be installed with Pip:
pip install distancerasters
If you'd like to install the latest development (alpha) release, there may be a newer version on TestPyPi:
pip install -i https://test.pypi.org/simple/ distancerasters
To install this package from source, first clone this repository, then use pip to install:
git clone git@github.com:sgoodm/python-distance-rasters.git
cd python-distance-rasters
pip install .
New issues are always welcome, and if you'd like to make a change, fork the repo and submit a pull request.
We use Pytest and Coveralls to run unit tests and track code coverage of tests. If you submit code, please make sure it passes existing tests and adds relevant testing coverage for new features.
You can run tests and coverage checks locally, or you can fork the repository and utilize GitHub actions and Coveralls. To use GitHub actions and Coveralls, you'll need to add your forked repo to your own Coverall accounts and add you Coveralls token to your repository as a GitHub Secret (see below).
To run tests and coverage checks locally, you can use the following commands:
pip install pytest coverage
coverage run -m pytest ./
coverage html
There are three GitHub Secrets required to enable all of our GitHub Actions:
- COVERALLS_REPO_TOKEN - this is the API token for Coveralls, used for publishing code coverage reports
- TEST_PYPI_API_TOKEN - this is the API token for TestPyPi, needed for publishing alpha releases
- PYPI_API_TOKEN - this is the API token for PyPi, needed for publishing releases
Note: contributors do not need PyPi tokens; if you create a new release in a forked repo it will trigger a GitHub action that will attempt to publish to PyPi and fail.