Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save daliposc/f91f825d153ac3308e77282030923be7 to your computer and use it in GitHub Desktop.
Save daliposc/f91f825d153ac3308e77282030923be7 to your computer and use it in GitHub Desktop.
Some person on reddit asked how they could use QGIS to calculate the number of police stations within 5 miles of a school. I made them a small tutorial.
from collections import defaultdict
# Initialize layer variables
streets_lyr = QgsProject.instance().mapLayersByName('streets')[0]
origin_lyr = QgsProject.instance().mapLayersByName('schools')[0]
destination_lyr = QgsProject.instance().mapLayersByName('police_stations')[0]
od_matrix = QgsProject.instance().mapLayersByName('od_pairs')[0]
# Initialize variables for analysis
origin_ids = QgsExpression('array_agg("fid")').evaluate(origin_lyr.createExpressionContext())
destination_id_closest_origins = defaultdict(list)
# Make dict of lists of origin-destination pairs grouped by destination
for origin_id in origin_ids:
closest_destinations = QgsExpression(
f'array_agg(\
"destination_id",\
filter:="origin_id" = {origin_id},\
order_by:="network_miles"\
)').evaluate(od_matrix.createExpressionContext())
destination_id_closest_origins[closest_destinations[0]].append(origin_id)
# Run "Shortest Path (Layer to Point)" processing on each o-d pair list
# See: https://docs.qgis.org/testing/en/docs/user_manual/processing_algs/qgis/networkanalysis.html#shortest-path-layer-to-point
all_paths = []
for destination_id in destination_id_closest_origins:
origin_lyr.selectByIds(destination_id_closest_origins[destination_id])
print(f'processing destination: {destination_id} from origins: {origin_lyr.selectedFeatureIds()}...')
processing.run("native:shortestpathlayertopoint", {
'DEFAULT_DIRECTION' : 2,
'DEFAULT_SPEED' : 50,
'DIRECTION_FIELD' : None,
'END_POINT' : destination_lyr.getFeature(destination_id).geometry().asPoint().toString(),
'INPUT' : streets_lyr.id(),
'OUTPUT' : f'{destination_id}',
'SPEED_FIELD' : None,
'START_POINTS' : QgsProcessingFeatureSourceDefinition(origin_lyr.id(), True),
'STRATEGY' : 0,
'TOLERANCE' : 0,
'VALUE_BACKWARD' : '',
'VALUE_BOTH' : '',
'VALUE_FORWARD' : ''})
all_paths.append(f'{destination_id}.gpkg')
# Load results as temporary layer
processing.runAndLoadResults("native:mergevectorlayers", {
'LAYERS':all_paths,
'CRS': iface.crs(),
'OUTPUT':'memory'})

Data from OSM. police_stations = "amenity=police". schools = "amenity=school" excluding private religion schools and excluding preschools. start_img

Table after origin-destination pairs analysis and processing. middle_img

Results visualized. end_img

Results of draw_shortest_path_from_origin_to_destination.py final_final_img

Full imgur album: https://imgur.com/a/6Y1LeX2

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