# How to split overlapping polygon isochrones in QGIS?

I have two overlapping isochrones -- 10 minutes by bike from 2 neighbouring railway station -- and I want to split them in a balanced way, so as to determine the bikeshed of each railway station. The separation should occur at equi-distance from each station.

On the image form QGIS the green polygons are the isochrones around railway stations represented by red stars. I have added a red line showing where I would like the two isochrones to be separated. How could I process this in QGIS?

• What defines that red line? Is it half way between the red stars? Does it divide the green polygons in half? What are the green polygons? What do you mean by "split in a balanced way"? – Spacedman Feb 9 '17 at 10:04
• thanks Spacedman for helping me to precise my problem; indeed as my problem is separating areas of influence of stations, the red line is half way, so a solutions lies in using Voronoi polygons for splitting the buffers – the world is not flat Feb 9 '17 at 13:55
• Given that you've gone to the trouble of generating isochrones, you're obviously interested in more realistic travel choices. You might want to consider why someone in the isochrone for the RH station but left of the red line, might still want to go to the RH station, even if they are physically closer to the left: the RH station might have more frequent/faster/useful services. – George of all trades Feb 10 '17 at 9:22
• I agree with what you say George of all trades, this is a matter of travel choice. Before refining with railway services, it would be better to trace the limit between the two stations based on actual travel travel times and not on geometry, even if the second option gives already a good approximation in my sense. – the world is not flat Feb 13 '17 at 9:44

To split overlapping isochrones to determine areas of influence, a possibility is to generate a set of Voronoi polygons based on central points of the isochrones, in this case railway stations. Voronoi lines will be geometrically at equi-distance between neighbouring railway stations, which is an approximate of the limit of the respective areas of influence. The steps in QGIS are then:

1. Dissolve all isochrones in one single poly-polygon
2. Generate Voronoi polygons based on railway stations
3. Transform Voronoi polygons into lines (not sure this is necessary)
4. Split the dissolved isochron with the Voronoi lines

The end result is the bikeshed of each station without overlap.

Here is a code that first uses Graphhoper API to calculate isochrones then splits them with with geovoronoi library(https://pypi.org/project/geovoronoi/)

``````from routingpy import Graphhopper
import geopandas as gdp
from shapely.geometry import Polygon, MultiPolygon, MultiLineString, Point
from geovoronoi import voronoi_regions_from_coords
import numpy as np
from datetime import datetime

#This algorithm calculates influence areas of store points based on the isochrone method from Graphhopper library
# which is run on a local server. The algorithm has the following steps:
#1) Calculate isochrones for input coordinates
#2) For isochrones that intersect each other merge them togteher into a single polygon
#3) Convert the input coordinates into numpy arrays
#4) Split the merged polygons into voronoi regions associated with the points that are contained within them

begin = datetime.now()
print("Welcome to Isochrone Maker!")
# input coordiniates
coords = [[13.413706, 52.490202],
[13.421838, 52.514105],
[13.453649, 52.507987]]
# set the projection of the output
crs = {'init': 'epsg:4326'}
list_of_polygons = []
# loop through the coordinates
for i in coords:
# call Graphhopper API and calculate isochrones
client = Graphhopper(base_url='http://localhost:8989')
route = client.isochrones(
locations = i,
profile='car',
buckets=3,
interval_type="distance",
intervals = [20000]
)
# convert isochrone geometry to shapely format
polygon_geom = Polygon(route[0].geometry)
list_of_polygons.append(polygon_geom)
# find the intersection of polygons
if len(list_of_polygons) > 1:
# start the loop from the one end of the polygon list
for t in reversed(list_of_polygons):
# start loop through the other side of the polygon list
for x in list_of_polygons:
if x != t:
if t.is_valid & x.is_valid:
if t.intersects(x):
union = t.union(x)
list_of_polygons.append(union)
list_of_polygons.remove(t)
list_of_polygons.remove(x)

dif_points = []
new_array = []
for i in list_of_polygons:
points_list = []
for x in coords:
y = Point(x)
if y.within(i):
new_array.append(x)
new_array = np.array(new_array)
dif_points.append(new_array)

list_of_shit = []
for i in list_of_polygons:
for x in dif_points:
poly_shapes, pts, poly_to_pt_assingments = voronoi_regions_from_coords(x, i)

list_of_shit.append(poly_shapes)

for i in list_of_shit:
if len(list_of_shit) == 1:
multi = MultiPolygon(list_of_shit[0])
multi_1 = gdp.GeoDataFrame(index=[0], crs=crs, geometry=[multi])
multi_1.to_file("shape.geojson", driver="GeoJSON")
else:
multi = MultiPolygon(list_of_shit)
multi_1 = gdp.GeoDataFrame(index=[0], crs=crs, geometry=[multi])
multi_1.to_file("shape.geojson", driver="GeoJSON")

print("The algorithm finished! The new file called Shape has been created in geojson format")
print("{} isochrones have been created for {} input points".format(len(multi), len(coords)))
print("Elapsed time: {}".format(datetime.now() - begin))
``````