Skip to content

Instantly share code, notes, and snippets.

@tastatham
Created April 13, 2021 09:34
Show Gist options
  • Save tastatham/399332a8ff2edff31c3fa94d17eb3883 to your computer and use it in GitHub Desktop.
Save tastatham/399332a8ff2edff31c3fa94d17eb3883 to your computer and use it in GitHub Desktop.
Updated Geopandas (constant) multi-ring buffer function with example
import pandas as pd
import geopandas as gpd
def multi_ring_buffers(gdf, number, distance):
"""
Apply a function to a GeoDataFrame containing Point data and compute constant multi-ring buffers
Parameters
----------
gdf : A GeoDataFrame containing Point data
number : Number of ring buffers to compute
distance : Constant distance between ring buffers
Returns
-------
A GeoDataFrame containing constant multi-ring buffers for each Point in GeoDataFrame
"""
# Define default geometry column
DEFAULT_GEO_COLUMN_NAME = "geometry"
# Define max distance from point toouter ring buffer
max_distance = (number * distance)
# Calculate the distance intervals between each buffer
buffer_ls = list(range(max_distance + distance)[distance::distance] )
# Ignore the first buffer because we don't want to create a ring buffer for this
outer_buffer_ls = buffer_ls[1:]
# Ignore the last buffer because we can't create a ring buffer for the last outer value
inner_buffer_ls = buffer_ls[:-1]
# Create first buffer
first_buff = gdf.buffer(distance).to_frame(name = DEFAULT_GEO_COLUMN_NAME)
# Define inner and outer buffers
outer_buffers = [gdf.buffer(buff).to_frame(name = DEFAULT_GEO_COLUMN_NAME) for buff in outer_buffer_ls ]
inner_buffers = [gdf.buffer(buff).to_frame(name = DEFAULT_GEO_COLUMN_NAME) for buff in inner_buffer_ls ]
# Create empty list
sym = []
# Loop through each combination of inner and outer buffers and run a symmetrical difference to create ring buffers
[sym.append(gpd.overlay(inner_buffers[buff], outer_buffers[buff], how = "symmetric_difference") ) for buff in range(len(outer_buffers))]
# Concat list of ring buffers
sym = pd.concat(sym)
# Merge first buffer with ring buffers
ring_buffers = pd.concat([first_buff, sym])
# Add buffer distance as attribute
ring_buffers['buffer'] = buffer_ls
return(ring_buffers)
# Queen square bristol - Equestrian Statue of William III
lng = -2.5947
lat = 51.4505
# Create DataFrame from lat, lon coordinates
df = pd.DataFrame({'x':[lng], 'y':[lat] } )
# Create GeoDataFrame from DataFrame and reproject to british national grid
gdf = gpd.GeoDataFrame(df,
geometry = gpd.points_from_xy(df['x'], df['y']),
crs = 4326).to_crs(27700)
# Number of ring buffers
number = 10
# Distance between ring buffers
distance = 10
# Create ring buffers
ring_buffers = multi_ring_buffers(gdf, number, distance)
# Plot ring buffers
ring_buffers.plot();
@tastatham
Copy link
Author

could also be done using something like;

def donuts(point, outer_distance, step = 1000):
    return(point.buffer(outer_distance).difference(point.buffer(outer_distance-step)))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment