| name | qgis-impl-network-analysis |
| description | Use when performing routing, shortest path, or service area analysis on road/transport networks. Prevents incorrect results from wrong edge direction assumptions and missing cost strategies. Covers QgsGraphBuilder, QgsGraphAnalyzer (Dijkstra), QgsVectorLayerDirector, cost strategies, and service areas. Keywords: network analysis, routing, shortest path, Dijkstra, service area, QgsGraphBuilder, QgsGraphAnalyzer, road network, find route, travel distance, reachability, path between points.
|
| license | MIT |
| compatibility | Designed for Claude Code. Requires QGIS 3.44+ / PyQGIS 3.x. |
| metadata | {"author":"OpenAEC-Foundation","version":"1.0"} |
qgis-impl-network-analysis
Quick Reference
Core Classes (qgis.analysis)
| Class | Purpose |
|---|
QgsVectorLayerDirector | Controls edge direction rules for a line layer |
QgsNetworkDistanceStrategy | Cost = geometric edge length |
QgsNetworkSpeedStrategy | Cost = travel time (from speed field) |
QgsGraphBuilder | Constructs a QgsGraph from a directed layer |
QgsGraphAnalyzer | Static methods: dijkstra(), shortestTree() |
QgsGraph | In-memory graph with vertices and edges |
Workflow Steps
| Step | Class/Method | Output |
|---|
| 1. Set direction rules | QgsVectorLayerDirector(layer, ...) | Director object |
| 2. Add cost strategy | director.addStrategy(strategy) | Strategy index (0, 1, ...) |
| 3. Build graph | director.makeGraph(builder, points) | Tied (snapped) points |
| 4. Get graph object | builder.graph() | QgsGraph |
| 5. Find vertex IDs | graph.findVertex(tied_point) | Integer vertex ID |
| 6. Run Dijkstra | QgsGraphAnalyzer.dijkstra(graph, start, criterion) | (tree, cost) tuple |
| 7. Reconstruct path | Walk tree[] backwards from destination | List of QgsPointXY |
Processing Algorithm IDs
| Algorithm | ID |
|---|
| Shortest path (point to point) | native:shortestpathpointtopoint |
| Shortest path (point to layer) | native:shortestpathpointtolayer |
| Shortest path (layer to point) | native:shortestpathlayertopoint |
| Service area (from point) | native:serviceareafrompoint |
| Service area (from layer) | native:serviceareafromlayer |
Critical Warnings
NEVER assume all edges are bidirectional -- road networks contain one-way streets. ALWAYS configure QgsVectorLayerDirector with the correct direction field and values.
ALWAYS check tree[destination_id] == -1 before path reconstruction -- this value means the destination is unreachable from the source vertex.
ALWAYS use graph.findVertex(tied_point) with the tied (snapped) point returned by makeGraph(), NOT the original input point -- the original point does not exist in the graph.
NEVER skip adding a strategy before building the graph -- without at least one strategy, the graph has no edge costs and dijkstra() produces meaningless results.
ALWAYS use a projected CRS (meters) for distance-based analysis -- geographic CRS (degrees) produces incorrect distance calculations.
NEVER reconstruct a path using graph.vertex(current).incomingEdges() -- use tree[current] from the Dijkstra result instead, which gives the specific edge in the shortest path tree.
Decision Tree
Need network analysis?
├── Simple point-to-point route?
│ ├── Need full control over graph → Use QgsGraphBuilder + QgsGraphAnalyzer
│ └── Need quick result → Use processing.run("native:shortestpathpointtopoint")
├── Route from one point to many destinations?
│ └── Use processing.run("native:shortestpathpointtolayer")
├── Route from many origins to one destination?
│ └── Use processing.run("native:shortestpathlayertopoint")
├── Service area (reachability)?
│ ├── Single origin → Use processing.run("native:serviceareafrompoint")
│ ├── Multiple origins → Use processing.run("native:serviceareafromlayer")
│ └── Need boundary interpolation → Use QgsGraphAnalyzer.dijkstra() manually
├── Cost criterion?
│ ├── Distance (length) → QgsNetworkDistanceStrategy()
│ ├── Travel time → QgsNetworkSpeedStrategy(field_index, default_speed, factor)
│ └── Multiple criteria → Add multiple strategies, use criterion index in dijkstra()
└── Direction handling?
├── All bidirectional → directionFieldId = -1
├── One-way from attribute → directionFieldId = field index
└── All one-way (forward) → directionFieldId = -1, defaultDirection = DirectionForward
Essential Patterns
Pattern 1: Complete Shortest Path Workflow
from qgis.analysis import (
QgsGraphBuilder, QgsVectorLayerDirector,
QgsNetworkDistanceStrategy, QgsGraphAnalyzer
)
from qgis.core import QgsProject, QgsPointXY, QgsGeometry, QgsPoint
roads = QgsProject.instance().mapLayersByName("roads")[0]
director = QgsVectorLayerDirector(
roads,
-1,
'', '', '',
QgsVectorLayerDirector.DirectionBoth
)
director.addStrategy(QgsNetworkDistanceStrategy())
start_point = QgsPointXY(5.1214, 52.0907)
end_point = QgsPointXY(4.8952, 52.3702)
builder = QgsGraphBuilder(roads.crs())
tied_points = director.makeGraph(builder, [start_point, end_point])
graph = builder.graph()
start_id = graph.findVertex(tied_points[0])
end_id = graph.findVertex(tied_points[1])
(tree, cost) = QgsGraphAnalyzer.dijkstra(graph, start_id, 0)
if tree[end_id] == -1:
raise ValueError("Destination is unreachable from origin")
route_points = [graph.vertex(end_id).point()]
current = end_id
current != start_id:
edge = graph.edge(tree[current])
current = edge.fromVertex()
route_points.insert(, graph.vertex(current).point())
route_geom = QgsGeometry.fromPolyline(
[QgsPoint(p.x(), p.y()) p route_points]
)
()
Pattern 2: One-Way Street Handling
oneway_idx = roads.fields().indexOf('oneway')
director = QgsVectorLayerDirector(
roads,
oneway_idx,
'F',
'T',
'B',
QgsVectorLayerDirector.DirectionBoth
)
Direction constants:
| Constant | Meaning |
|---|
QgsVectorLayerDirector.DirectionForward | Digitized direction only |
QgsVectorLayerDirector.DirectionBackward | Reverse of digitized direction only |
QgsVectorLayerDirector.DirectionBoth | Both directions (bidirectional) |
Pattern 3: Travel Time Cost Strategy
speed_field_index = roads.fields().indexOf('speed_kmh')
strategy = QgsNetworkSpeedStrategy(
speed_field_index,
50.0,
1000.0 / 3600.0
)
director.addStrategy(strategy)
Pattern 4: Multiple Cost Criteria
director.addStrategy(QgsNetworkDistanceStrategy())
speed_idx = roads.fields().indexOf('speed_kmh')
director.addStrategy(QgsNetworkSpeedStrategy(speed_idx, 50.0, 1000.0 / 3600.0))
builder = QgsGraphBuilder(roads.crs())
tied = director.makeGraph(builder, [start_point, end_point])
graph = builder.graph()
sid = graph.findVertex(tied[0])
eid = graph.findVertex(tied[1])
(tree_dist, cost_dist) = QgsGraphAnalyzer.dijkstra(graph, sid, 0)
(tree_time, cost_time) = QgsGraphAnalyzer.dijkstra(graph, sid, 1)
Pattern 5: Service Area Analysis
(tree, cost) = QgsGraphAnalyzer.dijkstra(graph, start_id, 0)
threshold = 5000.0
reachable = []
for vid in range(graph.vertexCount()):
if cost[vid] <= threshold and tree[vid] != -1:
reachable.append(graph.vertex(vid).point())
boundary = []
for vid in range(graph.vertexCount()):
if cost[vid] > threshold and tree[vid] != -1:
edge = graph.edge(tree[vid])
from_v = edge.fromVertex()
if cost[from_v] < threshold:
ratio = (threshold - cost[from_v]) / (cost[vid] - cost[from_v])
p1 = graph.vertex(from_v).point()
p2 = graph.vertex(vid).point()
interpolated = QgsPointXY(
p1.x() + ratio * (p2.x() - p1.x()),
p1.y() + ratio * (p2.y() - p1.y())
)
boundary.append(interpolated)
all_points = reachable + boundary
Pattern 6: Shortest Path Tree
tree_graph = QgsGraphAnalyzer.shortestTree(graph, start_id, 0)
for eid in range(tree_graph.edgeCount()):
edge = tree_graph.edge(eid)
from_pt = tree_graph.vertex(edge.fromVertex()).point()
to_pt = tree_graph.vertex(edge.toVertex()).point()
line = QgsGeometry.fromPolylineXY([from_pt, to_pt])
Common Operations
Using Processing Algorithms for Routing
import processing
result = processing.run("native:shortestpathpointtopoint", {
'INPUT': roads,
'STRATEGY': 0,
'DIRECTION_FIELD': 'oneway',
'VALUE_FORWARD': 'F',
'VALUE_BACKWARD': 'T',
'VALUE_BOTH': 'B',
'DEFAULT_DIRECTION': 2,
'SPEED_FIELD': 'speed_kmh',
'DEFAULT_SPEED': 50.0,
'TOLERANCE': 0.0,
'START_POINT': '5.1214,52.0907 [EPSG:4326]',
'END_POINT': '4.8952,52.3702 [EPSG:4326]',
'OUTPUT': 'TEMPORARY_OUTPUT'
})
route_layer = result['OUTPUT']
Service Area via Processing
result = processing.run("native:serviceareafrompoint", {
'INPUT': roads,
'STRATEGY': 0,
'DIRECTION_FIELD': '',
'VALUE_FORWARD': '',
'VALUE_BACKWARD': '',
'VALUE_BOTH': '',
'DEFAULT_DIRECTION': 2,
'SPEED_FIELD': '',
'DEFAULT_SPEED': 50.0,
'TOLERANCE': 0.0,
'START_POINT': '5.1214,52.0907 [EPSG:4326]',
'TRAVEL_COST': 5000.0,
'OUTPUT': 'TEMPORARY_OUTPUT'
})
Creating a Route Layer from Graph Results
from qgis.core import QgsVectorLayer, QgsFeature, QgsField
from qgis.PyQt.QtCore import QVariant
route_layer = QgsVectorLayer(
f"LineString?crs={roads.crs().authid()}",
"Route",
"memory"
)
provider = route_layer.dataProvider()
provider.addAttributes([
QgsField("distance", QVariant.Double),
])
route_layer.updateFields()
feat = QgsFeature()
feat.setGeometry(route_geom)
feat.setAttributes([cost[end_id]])
provider.addFeature(feat)
route_layer.updateExtents()
QgsProject.instance().addMapLayer(route_layer)
Reference Links
Official Sources